Java通过FreeMarker实现代码生成(以SSM的Mapper和实体类为例)

代码生成的模板使用的时ftl编写的,需要先了解下基本语法
官方文档:http://freemarker.foofun.cn/ref_directive_ftl.html

一丶实现思路

1.首先创建相关字段,赋予信息(数据库连接、存放目录、作者等)
2.获取数据库连接,创建生成代码存目录
3.获取数据库元信息,当对应的信息存放到所写的Column类中
4.根据模板生成对应的代码

二、代码

所需要的依赖pom.xml

这里我是放到了SpringBoot项目中,SpringBoot的并没有删,主要是用到freemarker和MySQL的依赖包

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.23</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.36</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

实体类:

在这里是用于

public class Column {

    /** 数据库字段名称 **/
    private String columnName;
    /** 数据库字段类型 **/
    private String columnType;
    /** 数据库字段首字母小写且去掉下划线字符串 **/
    private String changeColumnName;
    /** 数据库字段注释 **/
    private String columnComment;

    public String getColumnComment() {
        return columnComment;
    }

    public void setColumnComment(String columnComment) {
        this.columnComment = columnComment;
    }

    public String getColumnName() {
        return columnName;
    }

    public void setColumnName(String columnName) {
        this.columnName = columnName;
    }

    public String getColumnType() {
        return columnType;
    }

    public void setColumnType(String columnType) {
        this.columnType = columnType;
    }

    public String getChangeColumnName() {
        return changeColumnName;
    }

    public void setChangeColumnName(String changeColumnName) {
        this.changeColumnName = changeColumnName;
    }
}

FreeMarker工具类:

package com.code.generate;

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{
        //这里比较重要,用来指定加载模板所在的路径
        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();
    }
}

代码生成的工具类:

因为是通过main方法执行,好多个东西都是自己定义的,包名等各种信息均是个人习惯,可根据个人需求进行修改

package com.code.generate;

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

import java.io.*;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.*;

public class CodeGenerateUtils {
    //类上的注释(作者 日期)
    private final String AUTHOR = "ST";
    private static String CURRENT_DATE="";
    private final String tableName = "user";
    //包名
    private final String packageName = "com.st.task";
    //数据库信息
    private final String URL = "jdbc:mysql://localhost:3306/stapp";
    private final String USER = "root";
    private final String PASSWORD = "root";
    private final String DRIVER = "com.mysql.jdbc.Driver";
    //生成的位置
    private final static String diskPath = "D:\\code";
    private final String changeTableName = replaceUnderLineAndUpperCase(tableName);
    //文件生成目录
    private final static String[] dirs={
            diskPath+"\\entity",diskPath+"\\controller",diskPath+"\\service",
            diskPath+"\\service\\impl",diskPath+"\\mapper",diskPath+"\\mappers"
    };
    public static void main(String[] args) throws Exception{
        CodeGenerateUtils codeGenerateUtils = new CodeGenerateUtils();
        setDF();
        createDirs();
        codeGenerateUtils.generate();
    }

    /**
     * 设置日期
     * @throws Exception
     */
    public static void setDF() throws Exception{
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        CURRENT_DATE=sdf.format(date);
    }
    /**
     * 获取数据库连接
     * @return
     * @throws Exception
     */
    public Connection getConnection() throws Exception{
        Class.forName(DRIVER);
        Connection connection= DriverManager.getConnection(URL, USER, PASSWORD);
        return connection;
    }

    /**
     * 用于创建存放的java类的路径
     * @throws Exception
     */
    public static void createDirs() throws Exception{
        for(int i= 0; i < dirs.length; i++) {
            File file = new File(dirs[i]);
            if (!file.exists()){
                file.mkdir();
            }
        }
    }

    /**
     * 生成代码
     * @throws Exception
     */
    public void generate() throws Exception{
        try {
            List<String> tables = new ArrayList();//存储表名
            //获取数据库元信息
            Connection connection = getConnection();
            DatabaseMetaData databaseMetaData = connection.getMetaData();
            //存储表名
            String[] types = {"TABLE"};
            ResultSet tabs    = databaseMetaData.getTables(null, null, null, types);
            while(tabs.next()){
                //只要表名这一列
                tables.add(tabs.getString("TABLE_NAME"));
            }
            for(int i=0;i<tables.size();i++){//生成每个表的文件
                String table = tables.get(i);
                ResultSet resultSet = databaseMetaData.getColumns(null,"%",table,"%");
                //生成Model文件
                generateModelFile(resultSet,table);
                //生成Mapper文件
                generateMapperFile(resultSet,table);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally{

        }
    }

    /**
     * 生成实体类
     * @param resultSet
     * @throws Exception
     */
     private void generateModelFile(ResultSet resultSet,String tableName) throws Exception{
        final String suffix = ".java";//后缀名
        final String package_name = "entity";//包名
        String name = replaceUnderLineAndUpperCase(tableName);
        final String path = diskPath  +"\\"+package_name+"\\"+ name+ suffix;
        final String templateName = "Model.ftl";
        File mapperFile = new File(path);
        List<Column> columnClassList = new ArrayList<>();
        Column columnClass = null;
        while(resultSet.next()){
            //id字段略过
            //if(resultSet.getString("COLUMN_NAME").equals("id")) continue;
            columnClass = new Column();
            //获取字段名称
            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);
        dataMap.put("table_name",name);
        generateFileByTemplate(templateName,mapperFile,dataMap);

    }

    /**
     * 生成mapper文件
     * @param resultSet
     * @param tableName
     * @throws Exception
     */
    private void generateMapperFile(ResultSet resultSet,String tableName) throws Exception{
        final String suffix = "Mapper.xml";
        final String package_name = "mappers";//包名
        String name = replaceUnderLineAndUpperCase(tableName);
        final String path = diskPath  +"\\"+package_name+"\\"+ name+ suffix;
        final String templateName = "Mapper.ftl";
        File mapperFile = new File(path);

        List<Column> columnClassList = new ArrayList<>();
        Column columnClass = null;
        while(resultSet.next()){
            //id字段略过
            //if(resultSet.getString("COLUMN_NAME").equals("id")) continue;
            columnClass = new Column();
            //获取字段名称
            columnClass.setColumnName(resultSet.getString("COLUMN_NAME"));
            //获取字段类型
            columnClass.setColumnType(resultSet.getString("TYPE_NAME"));
            columnClassList.add(columnClass);
        }
        Map<String,Object> dataMap = new HashMap<>();
        System.out.println(name);
        dataMap.put("model_column",columnClassList);
        dataMap.put("table_name",name);
        dataMap.put("jing","#");
        dataMap.put("left","{");
        dataMap.put("right","}");
        generateFileByTemplate(templateName,mapperFile,dataMap);
    }

    private void generateFileByTemplate(final String templateName,File file,Map<String,Object> dataMap) throws Exception{
        Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
        FileOutputStream fos = new FileOutputStream(file);
        dataMap.put("table_name_small",tableName);
        dataMap.put("author",AUTHOR);
        dataMap.put("date",CURRENT_DATE);
        dataMap.put("package_name",packageName);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"),10240);
        template.process(dataMap,out);
    }

    /**
     * 带下划线的名字转换
     * @param str
     * @return
     */
    public static String replaceUnderLineAndUpperCase(String str){
        StringBuffer sb = new StringBuffer();
        sb.append(str);
        if(str.contains("_")){
            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);
        }else {
            String first = str.substring(0, 1);
            String after = str.substring(1, str.length());
            String result = first.toUpperCase() + after;
            return result;
        }
    }

在这里提供一下Mapper和实体类的ftl模板,可根据需求进行修改,这里通过${} 获取的值都是在java中往Map中存储的值,可根据需求自行添加
Mapper.ftl

<?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">
    <!--表名 -->
    <sql id="tableName">
        ${table_name}
    </sql>
    <#if model_column ? exists>
    <!-- 字段 -->
    <sql id="Field">
    <#list model_column as model>
        ${model.columnName},
    </#list>
    </sql>
    <!-- 字段值 -->
    <sql id="FieldValue">
    <#list model_column as model>
        ${jing}${left}${model.columnName}${right},
    </#list>
    </sql>
    </#if>

    <!-- 新增-->
    <insert id="save" parameterType="${table_name}" keyProperty="id" useGeneratedKeys="true">
        insert into
        <include refid="tableName"></include>
        (
        <include refid="Field"></include>
        ) values (
        <include refid="FieldValue"></include>
        )
    </insert>

    <!-- 删除-->
    <delete id="deleteById" parameterType="${table_name}">
        delete from
        <include refid="tableName"></include>
        where
        id in ( ${jing}${left}id${right} )
    </delete>

    <!-- 修改 -->
    <update id="updateById" parameterType="${table_name}">
        update
        <include refid="tableName"></include>
        set
        id = ${jing}${left}id${right}
        <#if model_column ? exists>
        <#list model_column as model>
            <if test=" ${model.columnName} != null and ${model.columnName} != ''">,name =  ${jing}${left}${model.columnName}${right}</if>
        </#list>
        </#if>
        where
        id = ${jing}${left}id${right}
    </update>

    <!-- 列表(全部) -->
    <!--resultType:表示把查询的结果集中的每一条记录封装成什么类型的对象 -->
    <select id="listAll" parameterType="${table_name}" resultType="${table_name}">
        select
        t.*
        from
        <include refid="tableName"></include>
        t
        where 1 =1
        <#if model_column ? exists>
        <#list model_column as model>
            <#if model.columnType = 'VARCHAR' >
                <if test=" ${model.columnName} != null and ${model.columnName} != ''">and t.${model.columnName} like "%"${jing}${left}${model.columnName}${right}"%"</if>
            <#else>
                <if test=" ${model.columnName} != null and ${model.columnName} != ''">and t.${model.columnName} = ${jing}${left}${model.columnName}${right}</if>
            </#if>

        </#list>
        </#if>
    </select>

</mapper>

实体类ftl
这里要注意的是,需要根据数据库的字段类型判断实体类的成员变量的类型,需要判断所有的可能(也许有更简单的方法)

package ${package_name}.entity;

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

/**
* @author ${author}
* @date ${date}
*/
public class ${table_name} implements Serializable {

<#if model_column ? exists>
    <#list model_column as model>
        //${model.columnComment!}
        <#if model.columnType = 'VARCHAR' >
        private String ${model.changeColumnName? uncap_first};
        </#if>
        <#if model.columnType = 'BIGINT' >
        private Long ${model.changeColumnName?uncap_first};
        </#if>
        <#if model.columnType = 'INT' >
        private Integer ${model.changeColumnName?uncap_first};
        </#if>
        <#if model.columnType = 'DATETIME' >
        private Date ${model.changeColumnName?uncap_first};
        </#if>
    </#list>
</#if>


<#if model_column?exists>
    <#list model_column as model>
        <#if model.columnType = 'VARCHAR' >
        public String get${model.changeColumnName}() {
            return this.${model.changeColumnName?uncap_first};
        }
        public void set${model.changeColumnName}(String ${model.changeColumnName? uncap_first}) {
            this.${model.changeColumnName?uncap_first} = ${model.changeColumnName?uncap_first};
        }
        </#if>
        <#if model.columnType = 'BIGINT' >
        public Long get${model.changeColumnName}() {
            return this.${model.changeColumnName?uncap_first};
        }
        public void set${model.changeColumnName}(Long ${model.changeColumnName? uncap_first}) {
            this.${model.changeColumnName?uncap_first} = ${model.changeColumnName?uncap_first};
        }
        </#if>
        <#if model.columnType = 'INT' >
        public int get${model.changeColumnName}() {
            return this.${model.changeColumnName?uncap_first};
        }
        public void set${model.changeColumnName}(int ${model.changeColumnName? uncap_first}) {
            this.${model.changeColumnName?uncap_first} = ${model.changeColumnName?uncap_first};
        }
        </#if>
        <#if model.columnType = 'DATETIME' >
        public Date get${model.changeColumnName}() {
            return this.${model.changeColumnName?uncap_first};
        }
        public void set${model.changeColumnName}(Date ${model.changeColumnName?uncap_first}) {
            this.${model.changeColumnName?uncap_first} = ${model.changeColumnName?uncap_first};
        }
        </#if>
    </#list>
</#if>

}

到此即可实现代码生成,生成效果如下

freemarker 模板bian写java代码 freemarker java代码段_spring

freemarker 模板bian写java代码 freemarker java代码段_数据库_02