使用Freemaker的Java、python代码生成器

  • 代码生成简介
  • 代码
  • Entity模板文件
  • Mapper.XML模板文件
  • DAO模板文件
  • ServiceInterface模板文件
  • ServiceImpl模板文件


代码生成简介

freemarket的语法知识: 
通过下面的方法可以自己自定义的去生成任何代码, 包括生成python、php代码

代码

import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;

public class CodeGenerateUtils {
    private final String AUTHOR = "<作者名称>";
    private final String CURRENT_DATE = calendarToString();
    private final String tableName = "<表名称>";
    private final String packageName = "<包名称>";
    private final String tableAnnotation = "<表描述>";
    private final String URL = "<数据库连接地址>";
    private final String USER = "<数据库账号>";
    private final String PASSWORD = "<数据库密码>";
    private final String DRIVER = "<数据库驱动>"; 
    private final String diskPath = "D://"; //导出位置
    private final String changeTableName = replaceUnderLineAndUpperCase(tableName);

    public Connection getConnection() throws Exception{
        Class.forName(DRIVER);
        Connection connection= DriverManager.getConnection(URL, USER, PASSWORD);
        return connection;
    }

    public static void main(String[] args) throws Exception{
        CodeGenerateUtils codeGenerateUtils = new CodeGenerateUtils();
        codeGenerateUtils.generate();
    }

    private static String calendarToString()  {
        Calendar calendar = Calendar.getInstance();
        if (calendar == null) {
            return null;
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");// 设置你想要的格式
        String dateStr = df.format(calendar.getTime());
        return dateStr;
    }
    
    public static String replaceUnderLineAndUpperCase(String str){
        //处理第一个下划线前字符串不超过两个时候删除
        String[] splits = str.split("_");
        Integer i = 0;
        if (splits[0].length() < 3) {

            for (char c : str.toCharArray()) {
                if (c == UNDERLINE) {
                    ++i;
                    break;
                } else {
                    ++i;
                }
            }
            str = str.substring(i);
        }
        StringBuffer sb = new StringBuffer();
        sb.append(str);
        int count = sb.indexOf("_");
        while(count!=0){
            int num = sb.indexOf("_",count);
            count = num + 1;
            if(num != -1){
                char ss = sb.charAt(count);
                char ia = (char) (ss - 32);
                sb.replace(count , count + 1,ia + "");
            }
        }
        String result = sb.toString().replaceAll("_","");
        return StringUtils.capitalize(result);
    }
    private static final char UNDERLINE='_';

    //驼峰转换
    public static String underlineToCamel(String param){
        if (param==null||"".equals(param.trim())){
            return "";
        }
        int len=param.length();
        StringBuilder sb=new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = Character.toLowerCase(param.charAt(i));
            if (c == UNDERLINE){
                if (++i<len){
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            }else{
                sb.append(c);
            }
        }
        return sb.toString();
    }


    List<Map<String, Object>> mapList;

    public void generate() throws Exception{
        try {
            Connection connection = getConnection();
            DatabaseMetaData databaseMetaData = connection.getMetaData();
            ResultSet resultSet = databaseMetaData.getColumns(null,"%", tableName,"%")
            //生成Mapper文件(该方法必须启用)
            generateMapperFile(resultSet);
            //生成DTO文件
            generateDTOFile(resultSet);
            //生成Dao文件
            generateMapperInterfaceFile(resultSet);
            //生成Repository文件
            //generateRepositoryFile(resultSet);
            //生成服务层接口文件
            generateServiceInterfaceFile(resultSet);
            //生成服务实现层文件
            generateServiceImplFile(resultSet);
            //生成Controller层文件
            //generateControllerFile(resultSet);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally{

        }
    }

    private void generateModelFile(ResultSet resultSet) throws Exception{

        final String suffix = ".java";
        final String path = diskPath + changeTableName + suffix;
        final String templateName = "Model.ftl";
        File mapperFile = new File(path);
        List<ColumnClass> columnClassList = new ArrayList<>();
        ColumnClass columnClass = null;
        while(resultSet.next()){
            //id字段略过
            if(resultSet.getString("COLUMN_NAME").equals("id")) continue;
            columnClass = new ColumnClass();
            //获取字段名称
            columnClass.setColumnName(resultSet.getString("COLUMN_NAME"));
            //获取字段类型
            columnClass.setColumnType(resultSet.getString("TYPE_NAME"));
            //转换字段名称,如 sys_name 变成 SysName
            columnClass.setChangeColumnName(replaceUnderLineAndUpperCase(resultSet.getString("COLUMN_NAME")));
            //字段在数据库的注释
            columnClass.setColumnComment(resultSet.getString("REMARKS"));
            columnClassList.add(columnClass);
        }
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("model_column",columnClassList);
        generateFileByTemplate(templateName,mapperFile,resultSet);

    }

    private  String suitTypeName(String TYPE_NAME){
        String res = TYPE_NAME;
        switch (TYPE_NAME){
            case "CHAR":
                res =  "VARCHAR";
                break;
            case "DATETIME":
                res =  "TIMESTAMP";
                break;
            case "INT":
                res =  "INTEGER";
                break;
            case "JSON":
                res =  "BLOB";
                break;
        }
        return res;
    }

	//获取数据库中每个字段的信息
    private  List<Map<String,Object>> getDataMap(ResultSet resultSet) throws SQLException {
        List<Map<String, Object>> tempList = new ArrayList<Map<String, Object>>();
        while(resultSet.next()) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("COLUMN_NAME", resultSet.getString("COLUMN_NAME"));//表字段名称
            map.put("DATA_TYPE", resultSet.getString("DATA_TYPE")); //字段类型
            map.put("TYPE_NAME",suitTypeName(resultSet.getString("TYPE_NAME")));//字段类型名称
            map.put("COLUMN_SIZE", resultSet.getString("COLUMN_SIZE"));//字段大小
            map.put("NULLABLE", resultSet.getString("NULLABLE"));//是否为空
            map.put("REMARKS", resultSet.getString("REMARKS"));//表的注释
            //转换为驼峰后字段名称
            map.put("humpName", underlineToCamel(resultSet.getString("COLUMN_NAME")));
            map.put("POJO_TYPE_NAME", getPojoType(resultSet.getString("TYPE_NAME")));//字段对应的实体类的名称
            //实体类与sql类转换
            tempList.add(map);
            System.out.println(map);
        }
        return tempList;
    }

	//生成对应的类型名称
    private String getPojoType(String type_name) {
        String res = "";
        switch (type_name){
            case "TINYINT":
                res =  "Integer";
                break;
            case "SMALLINT":
                res = "Integer";
                break;
            case "MEDIUMINT":
                res = "Integer";
                break;
            case "INT":
                res = "Integer";
                break;
            case "BIGINT":
                res = "Long";
                break;
            case "FLOAT":
                res = "Float";
                break;
            case "DOUBLE":
                res = "Double";
                break;
            case "DECIMAL":
                res = "BigDecimal";
                break;
            case "DATETIME":
                res = "Date";
                break;
            case "CHAR":
                res = "String";
                break;
            case "VARCHAR":
                res = "String";
                break;
            case "TINYBLOB":
                res = "String";
                break;
            case "TINYTEXT":
                res = "String";
                break;
            case "BLOB":
                res = "String";
                break;
            case "TEXT":
                res = "String";
                break;
            case "MEDIUMBLOB":
                res = "String";
                break;
            case "LONGTEXT":
                res = "String";
                break;
            case "MEDIUMTEXT":
                res = "String";
                break;
            case "JSON":
                res = "String";
                break;
        }
        return res;
    }

    private void generateDTOFile(ResultSet resultSet) throws Exception{
        final String suffix = ".java";
        final String path = diskPath + changeTableName + suffix;
        final String templateName = "DTO.ftl";
        File mapperFile = new File(path);
        generateFileByTemplate(templateName,mapperFile,resultSet);
    }

    /*private void generateControllerFile(ResultSet resultSet) throws Exception{
        final String suffix = "Controller.java";
        final String path = diskPath + changeTableName + suffix;
        final String templateName = "Controller.ftl";
        File mapperFile = new File(path);
        Map<String,Object> dataMap = new HashMap<>();
        generateFileByTemplate(templateName,mapperFile,resultSet);
    }*/

    private void generateServiceImplFile(ResultSet resultSet) throws Exception{
        final String suffix = "ServiceImpl.java";
        final String path = diskPath + changeTableName + suffix;
        final String templateName = "ServiceImpl.ftl";
        File mapperFile = new File(path);
        Map<String,Object> dataMap = new HashMap<>();
        generateFileByTemplate(templateName,mapperFile,resultSet);
    }

    private void generateServiceInterfaceFile(ResultSet resultSet) throws Exception{
        //final String prefix = "I";
        final String suffix = "Service.java";
        final String path = diskPath + changeTableName + suffix;
        final String templateName = "ServiceInterface.ftl";
        File mapperFile = new File(path);
        Map<String,Object> dataMap = new HashMap<>();
        generateFileByTemplate(templateName,mapperFile,resultSet);
    }
    private void generateMapperInterfaceFile(ResultSet resultSet) throws Exception{
        final String suffix = "Mapper.java";
        final String path = diskPath + changeTableName + suffix;
        final String templateName = "MapperInterface.ftl";
        File mapperFile = new File(path);
        generateFileByTemplate(templateName,mapperFile,resultSet);
    }

    private void generateMapperFile(ResultSet resultSet) throws Exception{
        final String suffix = "Mapper.xml";
        final String path = diskPath + changeTableName + suffix;
        final String templateName = "Mapper.ftl";
        File mapperFile = new File(path);
        mapList = getDataMap(resultSet);
        generateFileByTemplate(templateName,mapperFile,resultSet);
    }

    private void generateFileByTemplate(final String templateName,File file,ResultSet resultSet) throws Exception{
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("mapList", mapList);
        Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
        FileOutputStream fos = new FileOutputStream(file);
        dataMap.put("table_name_small",tableName);
        dataMap.put("table_name",changeTableName);
        dataMap.put("author",AUTHOR);
        dataMap.put("date",CURRENT_DATE);
        dataMap.put("package_name",packageName);
        dataMap.put("table_annotation",tableAnnotation);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"),10240);
        template.process(dataMap,out); //dataMap就是向模板引擎进行传值
    }

获取字段的基本信息

import lombok.Data;//需要引入lombok依赖
@Data
public class ColumnClass {
    /** 数据库字段名称 **/
    private String columnName;
    /** 数据库字段类型 **/
    private String columnType;
    /** 数据库字段首字母小写且去掉下划线字符串 **/
    private String changeColumnName;
    /** 数据库字段注释 **/
    private String columnComment;
}

调用FreeMarkerTemplate模板引擎

import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;

import java.io.IOException;

public class FreeMarkerTemplateUtils {
    private FreeMarkerTemplateUtils(){}
    private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);
    static{
        //这里比较重要,用来指定加载模板所在的路径(最好是把模板文件放在source目录下的templates中)
        CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtils.class, "/templates"));
        CONFIGURATION.setDefaultEncoding("UTF-8");
        CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
    }
    public static Template getTemplate(String templateName) throws IOException {
        try {
            return CONFIGURATION.getTemplate(templateName);
        } catch (IOException e) {
            throw e;
        }
    }
    public static void clearCache() {
        CONFIGURATION.clearTemplateCache();
    }
}

Entity模板文件

模板文件必须放在resource目录下,否则会找不到
模板的名称为DTO.ftl

package ${package_name}.entity;

import lombok.Data;
import java.io.Serializable;
import java.util.Date;

/**
* @描述 ${table_annotation}
* @author ${author}
* @date ${date}
*/
@Data
public class ${table_name} implements Serializable{

    private static final long serialVersionUID = 1L;
<#list mapList as map>

    //${map.REMARKS}
    private ${map.POJO_TYPE_NAME}  ${map.humpName};
</#list>
}

Mapper.XML模板文件

文件的名称必须为: Mapper.ftl
详细解释一下Mapper文件:
${package_name}: 包名称
${table_name}: 表名称
<#list mapList as map> : mapList为字段的List集合, 内部可以循环遍历所有字段
${map.COLUMN_NAME}: 字段名称
${map_index} : List的索引位置
${map.humpName}: 字段的驼峰名称

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="${package_name}.mapper.${table_name}Mapper">

    <resultMap id="${table_name}ResMap" type="${package_name}.entity.${table_name}">
        <#list mapList as map>
            <result column="${map.COLUMN_NAME}" jdbcType="${map.TYPE_NAME}" property="${map.humpName}"/>
        </#list>
    </resultMap>

    <sql id="Base_Column_List">
        <#list mapList as map>${map.COLUMN_NAME}<#if mapList?size!=(map_index+1)>,</#if></#list>
    </sql>

    <!-- where clause -->
    <sql id="whereClause">
        <where>
            <#list mapList as map>
            <if test="${map.humpName} != null <#if (map.TYPE_NAME)?index_of("VARCHAR")!=-1> and ${map.humpName} != ''</#if>">
                <#if 0!=(map_index)>and</#if> ${map.COLUMN_NAME} = ${r'#{'}${map.humpName}${r'}'}
            </if>
            </#list>
        </where>
    </sql>

    <sql id="selectClause">
        select <include refid="Base_Column_List"/>  from ${table_name_small} <include refid="whereClause"/> order by update_time desc
    </sql>

    <!-- select one -->
    <select id="selectByPrimaryKey" parameterType="java.lang.${mapList[0].POJO_TYPE_NAME}" resultMap="${table_name}ResMap">
        select <include refid="Base_Column_List"/> from ${table_name_small} where ${mapList[0].COLUMN_NAME} = ${r'#{'}${mapList[0].humpName}${r'}'}
    </select>

    <!-- select many -->
    <select id="selectByPrimaryKeys" parameterType="java.util.List" resultMap="${table_name}ResMap">
        select <include refid="Base_Column_List"/> from ${table_name_small}
        <where>
            ${mapList[0].COLUMN_NAME} in
            <foreach collection="list" item="${mapList[0].humpName}" index="index" open="(" close=")" separator=",">
                ${r'#{'}${mapList[0].humpName}${r'}'}
            </foreach>
        </where>
    </select>

    <!-- select by hashMap -->
    <select id="selectByHashMap" parameterType="hashMap" resultMap="${table_name}ResMap">
        select <include refid="Base_Column_List"/> from ${table_name_small}
        <include refid="whereClause"/>
    </select>

    <!-- select list -->
    <select id="selectList" parameterType="hashMap" resultMap="${table_name}ResMap">
        <include refid="selectClause"/>
    </select>

    <insert id="insertOne" parameterType="${package_name}.entity.${table_name}">
        <selectKey keyProperty="${mapList[0].humpName}" order="AFTER" resultType="java.lang.Long">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into ${table_name_small} (
        <trim suffixOverrides=",">
            <#list mapList as map>
            <if test="${map.humpName} != null <#if (map.TYPE_NAME)?index_of("VARCHAR")!=-1> and ${map.humpName} != ''</#if>">
                ${map.COLUMN_NAME}<#if mapList?size!=(map_index+1)>,</#if>
            </if>
            </#list>
        </trim>
        ) values (
        <trim suffixOverrides=",">
            <#list mapList as map>
            <if test="${map.humpName} != null <#if (map.TYPE_NAME)?index_of("VARCHAR")!=-1> and ${map.humpName} != ''</#if>">
                ${r'#{'}${map.humpName},jdbcType=${map.TYPE_NAME}${r'}'}<#if mapList?size!=(map_index+1)>,</#if>
            </if>
            </#list>
        </trim>
        )
    </insert>

    <update id="updateById" parameterType="${package_name}.entity.${table_name}">
        update ${table_name_small}
        <set>
            <#list mapList as map>
            <if test="${map.humpName} != null <#if (map.TYPE_NAME)?index_of("VARCHAR")!=-1> and ${map.humpName} != ''</#if>">
                ${map.COLUMN_NAME} = ${r'#{'}${map.humpName},jdbcType=${map.TYPE_NAME}${r'}'}<#if mapList?size!=(map_index+1)>,</#if>
            </if>
            </#list>
        </set>
        <where>
            ${mapList[0].COLUMN_NAME} = ${r'#{'}${mapList[0].humpName}${r'}'}
        </where>
    </update>

    <delete id="deleteByPrimaryKey" parameterType="java.lang.${mapList[0].POJO_TYPE_NAME}">
        delete from ${table_name_small}
        <where>
            ${mapList[0].COLUMN_NAME} = ${r'#{'}${mapList[0].humpName}${r'}'}
        </where>
    </delete>
</mapper>

DAO模板文件

文件名称为 MapperInterface.ftl

import ${package_name}.entity.${table_name};

import java.util.HashMap;
import java.util.List;

/**
* 描述:${table_annotation} 服务实现层接口
* @author ${author}
* @date ${date}
*/
public interface ${table_name}Mapper  {

    ${table_name} selectByPrimaryKey(${mapList[0].POJO_TYPE_NAME} ${mapList[0].humpName});

    List<${table_name}> selectByPrimaryKeys(List<${mapList[0].POJO_TYPE_NAME}> ${mapList[0].humpName}s);

    ${table_name} selectByHashMap(HashMap<String,Object> hashMap);

    List<${table_name}> selectList(HashMap<String,Object> hashMap);

    int insertOne(${table_name} ${table_name?uncap_first}) ;

    int deleteByPrimaryKey(${mapList[0].POJO_TYPE_NAME} ${mapList[0].humpName});

    int updateById(${table_name} ${table_name?uncap_first});

}

ServiceInterface模板文件

文件名称为: ServiceInterface.ftl

import ${package_name}.entity.${table_name};
import com.github.pagehelper.PageInfo;

import java.util.HashMap;
import java.util.List;

/**
* 描述:${table_annotation} 服务实现层接口
* @author ${author}
* @date ${date}
*/
public interface ${table_name}Service  {

    /**
    * @描述 根据主键查询
    * @param ${mapList[0].humpName} 主键
    * @data ${date}
    */
    ${table_name} findById(${mapList[0].POJO_TYPE_NAME} ${mapList[0].humpName});

    /**
    * @描述 根据多个主键查询
    * @param ${mapList[0].humpName}s 主键集合
    * @data ${date}
    */
    List<${table_name}> findByIds(List<${mapList[0].POJO_TYPE_NAME}> ${mapList[0].humpName}s);

    /**
    * @描述 根据hashMap进行条件查询
    * @param hashMap 传入的键值对
    * @data ${date}
    */
    ${table_name} findByHashMap(HashMap<String , Object> hashMap);

    /**
    * @描述 查询列表
    * @param hashMap 传入的键值对
    * @data ${date}
    */
    PageInfo findList(HashMap<String , Object> hashMap,PageInfo pageInfo);

    /**
    * @描述 插入数据
    * @param ${table_name?uncap_first} 传入的Model
    * @data ${date}
    */
    ${mapList[0].POJO_TYPE_NAME} create(${table_name} ${table_name?uncap_first}) ;

    /**
    * @描述 根据主键删除
    * @param ${mapList[0].humpName} 主键
    * @data ${date}
    */
    int deleteById(${mapList[0].POJO_TYPE_NAME} ${mapList[0].humpName});

    /**
    * @描述 根据主键更新
    * @param ${table_name?uncap_first} 传入Model
    * @data ${date}
    */
    int updateById(${table_name} ${table_name?uncap_first}) ;
}

ServiceImpl模板文件

文件名称为: ServiceImpl.ftl

import com.github.pagehelper.PageHelper;
import ${package_name}.entity.${table_name};
import ${package_name}.service.${table_name}Service;
import ${package_name}.mapper.${table_name}Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ${package_name}.entity.${table_name};
import org.springframework.beans.BeanUtils;
import com.github.pagehelper.PageInfo;

import java.util.HashMap;
import java.util.List;

/**
* 描述:${table_annotation} 服务实现层
* @author ${author}
* @date ${date}
*/
@Service
public class ${table_name}ServiceImpl implements ${table_name}Service {

    @Autowired
    private ${table_name}Mapper ${table_name?uncap_first}Mapper;

    @Override
    public ${table_name} findById(${mapList[0].POJO_TYPE_NAME} ${mapList[0].humpName}) {
        return ${table_name?uncap_first}Mapper.selectByPrimaryKey(${mapList[0].humpName});
    }

    @Override
    public List<${table_name}> findByIds(List<${mapList[0].POJO_TYPE_NAME}> ${mapList[0].humpName}s) {
        List<${table_name}> ${table_name?uncap_first}List = ${table_name?uncap_first}Mapper.selectByPrimaryKeys(${mapList[0].humpName}s);
        return ${table_name?uncap_first}List;
    }

    @Override
    public ${table_name} findByHashMap(HashMap<String,Object> hashMap) {
        ${table_name} ${table_name?uncap_first} = ${table_name?uncap_first}Mapper.selectByHashMap(hashMap);
        return ${table_name?uncap_first};
    }

    @Override
    public PageInfo findList(HashMap<String , Object> hashMap,PageInfo pageInfo) {
        PageHelper.startPage(pageInfo.getPageNum(), pageInfo.getPageSize());
        List<${table_name}> ${table_name?uncap_first}List = ${table_name?uncap_first}Mapper.selectList(hashMap);
        pageInfo = new PageInfo<${table_name}>(${table_name?uncap_first}List);
        return pageInfo;
    }

    @Override
    public ${mapList[0].POJO_TYPE_NAME} create(${table_name} model){
        ${table_name} ${table_name?uncap_first} = new ${table_name}();
        BeanUtils.copyProperties(model,${table_name?uncap_first});
        int result = ${table_name?uncap_first}Mapper.insertOne(${table_name?uncap_first});
        if(result == 0)
            throw new RuntimeException("更新失败,更新结果数为0");
        return ${table_name?uncap_first}.get${mapList[0].humpName?cap_first}();
    }

    @Override
    public int updateById(${table_name} model) {
        ${table_name} ${table_name?uncap_first} = new ${table_name}();
        BeanUtils.copyProperties(model,${table_name?uncap_first});
        int result = ${table_name?uncap_first}Mapper.updateById(${table_name?uncap_first});
        if(result == 0)
            throw new RuntimeException("更新失败,更新结果数为0");
        return result;
    }

    @Override
    public int deleteById(${mapList[0].POJO_TYPE_NAME} ${mapList[0].humpName}){
        int result =${table_name?uncap_first}Mapper.deleteByPrimaryKey(${mapList[0].humpName});
        if(result == 0)
            throw new RuntimeException("更新失败,更新结果数为0");
        return result;
    }
}