Freemarker自定义代码生成器

FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

温馨提示:不要盲目的 copy                                                                      有些路径是需要你自己改(๑′ᴗ‵๑)づ╭❤~;

(这只是我自己的路径o(๑′ᴗ‵๑)づ╭❤~)

可能会涉及到:jdk版本

注:(这是我的JDK的版本,你也可以设置你的JDK版本)

                                                                只要不涉及到冲突就好。

 

 

依赖模板引擎: FreeMarker

maven依赖freemarke

模板:生成文件的模板文件。

数据:生成文件所需要的关键数据。

合成机制:使用数据置换模板中的占位符,生成新的文件的机制。

效果图:

生成的Dao层的

     

生成  pojo层的

                                  APP的main执行完成

话不多说直接操作:

---------存放数据的对象 ColumnVo和TableVo:

                                                                                                                                                      按照上面结构图自己分析搭建

        ColumnVo.java

package cc.huangjunqi.vo;

public class ColumnVo {
    private String name;//在数据库中的列名
    private String fieldName;//java属性名
    private String javaType;//java类型
    private String dbType;//数据库中的类型
    private String comment;//注释
    private String upperCaseColumnName;//转成帕斯卡之后的名称

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    public String getJavaType() {
        return javaType;
    }

    public void setJavaType(String javaType) {
        this.javaType = javaType;
    }

    public String getDbType() {
        return dbType;
    }

    public void setDbType(String dbType) {
        this.dbType = dbType;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public String getUpperCaseColumnName() {
        return upperCaseColumnName;
    }

    public void setUpperCaseColumnName(String upperCaseColumnName) {
        this.upperCaseColumnName = upperCaseColumnName;
    }
}

        TableVo.java

package cc.huangjunqi.vo;

import java.util.ArrayList;
import java.util.List;

public class TableVo {
    private String className;//帕斯卡风格的类名 user_table UserTable
    private String camelName;//骆驼风格的类名(用育作为方法参数)userTable
    private String tableName;//下划线风格的表名
    private String comment;//注释
    private List<ColumnVo>columns =new ArrayList<>();//包含的列对象集合

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getCamelName() {
        return camelName;
    }

    public void setCamelName(String camelName) {
        this.camelName = camelName;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public List<ColumnVo> getColumns() {
        return columns;
    }

    public void setColumns(List<ColumnVo> columns) {
        this.columns = columns;
    }
}

 帮助类:

        JavaNameUtil.class

package cc.huangjunqi.util;

public class JavaNameUtil {

    public static String translate(String underscoreName,boolean isPascal){
        StringBuilder result = new StringBuilder();//返回字符结果
        if(underscoreName!=null && underscoreName.length()>0){
            boolean flag=false;
            char firstChar =underscoreName.charAt(0);//判断获取首字母
            if(isPascal){
                result.append(Character.toUpperCase(firstChar));//将首字母转换成大写
            }else{
                result.append(firstChar);
            }
            //从第二个字符开始循环
            for (int i=1;i<underscoreName.length();i++){
                char ch=underscoreName.charAt(i);
                //判断是否出现下划线
                if('_'==ch){
                    flag=true;
                }else {
                    if(flag){
                        result.append(Character.toUpperCase(ch));
                        flag=false;
                    }else {
                        result.append(ch);
                    }
                }
            }
        }
        return result.toString();//返回转换字符
    }
    /**
     * 骆驼命名法
     * @param str
     * @return
     */
    public static String toCamel(String str){
        return translate(str,false);
    }

    /**
     * 帕斯卡命名法
     * @param str
     * @return
     */
    public static String toPascal(String str){
        return translate(str,true);
    }

    /**
     * 转换数据类型
     * @param dbTypeName
     * @return
     */
    public static String dbtype2JavaType(String dbTypeName){
        String javaType=null;
        switch (dbTypeName){
            case "VARCHAR":javaType="String";break;
            case "BIGINT":javaType="Long";break;
            case "INT":javaType="Integer";break;
            case "DATETIME":javaType="Date";break;
            default: javaType="String";break;
        }
        return javaType;
    }

    public static void main(String[] arg){
        String testName =toCamel("user_liu_jh");
        System.out.println(testName);
        String testName2=toPascal("user_liu_jh");
        System.out.println(testName2);
    }
    //数据库类型名到Java类型名的转换
    public static String dbType2JavaType(String dbType){
        String javaType = null;
        if ("VARCHAR".equals(dbType)) {
            javaType = "String";
        } else if ("BIGINT".equals(dbType)) {
            javaType = "Long";
        } else if ("INT".equals(dbType)) {
            javaType = "Integer";
        } else if ("DATETIME".equals(dbType)) {
            javaType = "Date";
        } else {
            javaType = "String";
        }
        return javaType;
    }
}
MetadataUtil.class

注意这个不要盲目的copy:数据库是你自己的!请根据自己想生成的数据进行!(๑′ᴗ‵๑)づ╭❤~;

package cc.huangjunqi.util;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MetadataUtil {
    private static Connection conn;//连接对象
    private static DatabaseMetaData meta;//数据库元信息
    //静态块加载数据库驱动类
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("数据库连接失败!");
        }
    }

    /**
     * 打开连接之后获取数据库元数据
     */
    public static void openConnection() {
        try {
            if (conn == null || conn.isClosed()) {//isClosed:判断连接是否关闭
                conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/itripdb"+
                                "?useUnicode=true&characterEncoding=utf-8"+
                                "&useInformationSchema=true",
                        "root",
                        "root");//连接数据库 XXX表示你自己的数据库名称 、用户名、密码
                meta = conn.getMetaData();//获取元数据
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    //关闭链接
    public static void closeConnection(){
        try {
            if (conn != null && !conn.isClosed()) {
                conn.close();
            }
        }
            catch(SQLException e){
            e.printStackTrace();
        }
    }


    /**
     * 获取表的注释
     * @param
     * @return
     */
    public static String getCommentByTableName(String tableName) throws SQLException {
        openConnection();//打开连接
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SHOW CREATE TABLE " + tableName);
        String comment = null;
        if (rs != null && rs.next()) {
            comment=rs.getString(2);
            //判断字符,只获取注解部分
            int index = comment.lastIndexOf("=");
            comment = comment.substring(index+1);
        }
        rs.close();
        stmt.close();
        conn.close();
        return comment;
    }

    /**
     * 获取所有的名称
     * @return
     */

    //获取所有表名称
    public static Map<String,String> getTableNames(){
        openConnection();
        ResultSet rs = null;
        Map<String,String> tableComment = new HashMap<>();
        try {
            //用元信息对象,获取所有表信息
            rs = meta.getTables(
                    null,
                    null,
                    null,
                    new String[]{"TABLE"});
            while (rs.next()){
                String tName = rs.getString("TABLE_NAME");
                String tComment = rs.getString("REMARKS");
                tableComment.put(tName,tComment);
            }
        }catch (SQLException e){
            e.printStackTrace();
        }
        return tableComment;
    }

    /**
     * 获取某个表中所有的列信息
     * @param tableName
     * @return
     * @throws Exception
     */
    public static List<String[]> getTableColumnsInfo(String tableName)throws Exception{
        openConnection();
        ResultSet rs= meta.getColumns(null,
                "%",
                tableName,
                "%");
        List<String[]> columnInfoList =new ArrayList<>();
        while (rs.next()){
            String[] colInfo = new String[3];
            colInfo[0]=rs.getString("COLUMN_NAME");//COLUMN_NAME 列名
            colInfo[1]=rs.getString("REMARKS");//REMARKS 获取列注释
            colInfo[2]=rs.getString("TYPE_NAME");//TYPE_NAME 列类型
            columnInfoList.add(colInfo);
        }
        return columnInfoList;
    }
}

---------合成机制

CodeGenerator.java

package cc.huangjunqi.generator;

import cc.huangjunqi.util.JavaNameUtil;
import cc.huangjunqi.util.MetadataUtil;
import cc.huangjunqi.vo.ColumnVo;
import cc.huangjunqi.vo.TableVo;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CodeGenerator {

    protected Configuration cfg;//Freemarker配置对象
    protected Map valueMap;//要填充到模板的数据
    protected Template template;//ftl模板对象
    protected String savePath;//保存代码的路径
    protected List<TableVo> tableList;//表信息对象集合
    protected String fileNameSuffix;//生成的文件名后缀

    //构造方法
    public CodeGenerator(String ftl) throws Exception{
        cfg = new Configuration();//Freemarkey配置对象
        cfg.setClassForTemplateLoading(this.getClass(),"/templates");//设置加载ftl模板的路径
        template = cfg.getTemplate(ftl);
        valueMap = new HashMap();
        parseMetadate();
    }

    //调用MetadataUtil,获取所有的表信息、列信息,并且转换为对象
    public void parseMetadate()throws Exception{
        tableList = new ArrayList<>();
        //获取所有表名
        Map<String,String> tableMap = MetadataUtil.getTableNames();
        for (Map.Entry<String,String> entry: tableMap.entrySet()){
            TableVo table = new TableVo();//表对象
            //下划线转帕斯卡类名
            table.setClassName(JavaNameUtil.toPascal(entry.getKey()));
            table.setTableName(entry.getKey());
            table.setComment(entry.getValue());
            table.setCamelName(JavaNameUtil.toCamel(entry.getKey()));//调用工具类,获取列信息
            List<String[]> colInfoList = MetadataUtil.getTableColumnsInfo(entry.getKey());
            for (String[] colInfo:colInfoList){
                String cName = colInfo[0];//列名
                String cComment = colInfo[1];//列注释
                String cType = colInfo[2];//列的数据库类型
                ColumnVo column = new ColumnVo();
                column.setComment(cComment);
                column.setName(cName);//列名转java属性名
                column.setFieldName(JavaNameUtil.toCamel(cName));
                column.setDbType(cType);//数据库类型转java类型
                column.setJavaType(JavaNameUtil.dbType2JavaType(cType));//列名转帕斯卡,用于getter和setter
                column.setUpperCaseColumnName(JavaNameUtil.toPascal(cName));
                table.getColumns().add(column);//列对象加入到表的集合属性
            }
            tableList.add(table);//表加入表集合
        }
        MetadataUtil.closeConnection();
        System.out.println("构建元数据成功!\n\n");
    }

    //生成代码的方法
    public void generateCode() throws Exception{
        System.out.println("-----------开始生成"+template.getName()+"代码");
        OutputStreamWriter writer = null;
        for (TableVo table : tableList){
            valueMap.put("table",table);
            try {
                //生成的每个代码文件,拼接文件名,创建一个文件写入器
                writer = new FileWriter(savePath+"/"+table.getClassName()+fileNameSuffix);
                //Freemarker合成数据和模板,输出带代码文件
                this.template.process(valueMap,writer);
                //清空写入器缓冲
                writer.flush();
            }catch (TemplateException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                try {
                    writer.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        System.out.println("根据"+template.getName()+"模板生成代码成功!\n\n");
    }

    public void setSavePath(String savePath) {
        this.savePath = savePath;
    }

    public void setPackage(String packg) {
        this.valueMap.put("package",packg);
    }

    public void setFileNameSuffix(String fileNameSuffix) {
        this.fileNameSuffix = fileNameSuffix;
    }
}

------------APP.java

存储的文件位置自己改一下因为这是我自己生成后部署在那里的位置

注意O!(๑′ᴗ‵๑)づ╭❤~;

package cc.huangjunqi;

import cc.huangjunqi.generator.CodeGenerator;

//代码生成器启动类
public class APP {
    public static void main(String[] args) throws Exception {
        String myProjectPkg = "cn.itrip.beans";
        CodeGenerator pojoGenerator = new CodeGenerator("pojo.ftl");//设置所用的模板
        pojoGenerator.setSavePath("C:\\itrip-flex\\fffdao\\pojo");
        pojoGenerator.setFileNameSuffix(".java");//生成文件后缀
        pojoGenerator.setPackage(myProjectPkg);//项目包名
        //映射接口生成器
        CodeGenerator mapperGenerator = new CodeGenerator("mapper.ftl");
        mapperGenerator.setSavePath("C:\\itrip-flex\\fffdao\\dao");
        mapperGenerator.setFileNameSuffix("Mapper.java");
        mapperGenerator.setPackage(myProjectPkg);
        //Mapper.xml生成器
        CodeGenerator sqlGenerator = new CodeGenerator("sql.ftl");
        sqlGenerator.setSavePath("C:\\itrip-flex\\fffdao\\dao");
        sqlGenerator.setFileNameSuffix("Mapper.xml");
        sqlGenerator.setPackage(myProjectPkg);
        try{
            pojoGenerator .generateCode();
            mapperGenerator.generateCode();
            sqlGenerator.generateCode();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

----------------模板文件(pojo.ftl、mapper.ftl、sql.ftl)

mapper.ftl

package ${package}.dao;

import ${package}.pojo.${table.className};
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
/**
*${table.className}映射器接口
*@author newtonn@qq.com
*/
@Mapper
public interface ${table.className}Mapper{
    //根据id查询单个对象
    public ${table.className} get${table.className}ById(@Param(value="id")Long id)throws Exception;
    //根据多个条件(可包括分页参数)查询所有符合条件的对象
    //如分页,包含brginPos初始化下标,pageSize每页函数两个参数
    public List<${table.className}>	find${table.className}ListByMap(Map<String , Object> param)throws Exception;
    //根据多个条件查询符合条件的总数量
    public Integer get${table.className}CountByMap(Map<String , Object> param)throws Exception;
    //插入一个对象,返回受影响的行数
    public Integer insert${table.className}(${table.className} ${table.camelName})throws Exception;
    //修改一个对象,返回受影响的行数
    public Integer update${table.className}(${table.className} ${table.camelName})throws Exception;
    //删除一个对象,放回受影响的行数
    public Integer delete${table.className}ById(@Param(value="id")Long id)throws Exception;


}

sql.ftl

注意O!(๑′ᴗ‵๑)づ╭❤~;(温馨小提示:这不是xml文件这是.java)

<?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}.dao.${table.className}Mapper">

    <select id="get${table.className}ById" resultType="${package}.pojo.${table.className}" >
        select
        <trim suffixOverrides=",">
        <#list table.columns as col>
            ${col.name} as ${col.fieldName},
        </#list>
        </trim>
        from ${table.tableName}
        <trim prefix="where" prefixOverrides="and | or">
            <if test="id != null">
                and id=${r"#{"}id}
            </if>
        </trim>
    </select>

    <select id="find${table.className}ListByMap" resultType="${package}.pojo.${table.className}" parameterType="java.util.Map">
        select
        <trim suffixOverrides=",">
        <#list table.columns as col>
            ${col.name} as ${col.fieldName},
        </#list>
        </trim>
        from ${table.tableName}
        <trim prefix="where" prefixOverrides="and | or" >
        <#list table.columns as col>
            <if test="${col.fieldName} != null ">
                and ${col.name}=${r"#{"}${col.fieldName}}
            </if>
        </#list>
        </trim>
        <if test="beginPos != null and pageSize != null  ">
            limit ${r"#{"}beginPos},${r"#{"}pageSize}
        </if>
    </select>

    <select id="get${table.className}CountByMap" resultType="Integer"  parameterType="java.util.Map">
        select count(1) from ${table.tableName}
        <trim prefix="where" prefixOverrides="and | or" >
        <#list table.columns as col>
            <if test="${col.fieldName} != null ">
                and ${col.name}=${r"#{"}${col.fieldName}}
            </if>
        </#list>
        </trim>
    </select>

    <insert id="insert${table.className}" parameterType="${package}.pojo.${table.className}">
        insert into ${table.tableName}(
        <trim suffixOverrides=",">
        <#list table.columns as col>
            ${col.name},
        </#list>
        </trim>
        )
        values(
        <trim suffixOverrides=",">
        <#list table.columns as col>
            ${r"#{"}${col.fieldName}},
        </#list>
        </trim>
        )
    </insert>

    <update id="update${table.className}" parameterType="${package}.pojo.${table.className}">
        update ${table.tableName}
        <trim prefix="set" suffixOverrides="," suffix="where id=${r"#{"}id}">
        <#list table.columns as col>
            <#if col.fieldName != 'id'>
                <if test="${col.fieldName} != null ">
                    ${col.name}=${r"#{"}${col.fieldName}},
                </if>
            </#if>
        </#list>
        </trim>
    </update>

    <delete id="delete${table.className}ById" parameterType="Long">
        delete from ${table.tableName} where id = ${r"#{"}id}
    </delete>
</mapper>

pojo.ftl

package ${package}.pojo;

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


/**
 * ${table.comment} table根对象,从作用域取出table对象
 * @author newtonn@qq.com
 */
public class ${table.className} implements Serializable{

    //生成私有属性
    <#list table.columns as col>
        //${col.comment}
        private ${col.javaType} ${col.fieldName};
    </#list>


    //生成getter、setter方法 id
    <#list table.columns as col>
        public void set${col.upperCaseColumnName} (${col.javaType} ${col.fieldName}){
            this.${col.fieldName} = ${col.fieldName};
        }
        public ${col.javaType} get${col.upperCaseColumnName}(){
            return this.${col.fieldName};
        }
    </#list>
}

关于pom.xml的配置:

<!--    注意这是你的项目名称--> 
<artifactId>code-generator</artifactId>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.30</version>
        </dependency>
      <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>
    </dependencies>

   <build>
       <resources>
           <resource>
               <directory>src/main/java</directory>
               <includes>
                   <include>**/*.xml</include>
               </includes>
           </resource>
           <resource>
               <directory>
                   src/main.resources
               </directory>
               <filtering>true</filtering>
           </resource>
       </resources>
       <!-- <plugins>
&lt;!&ndash;            把Spring Boot模板打包为能从main方法启动的可执行的包&ndash;&gt;
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>-->
    </build>

❤如果文章对您有所帮助,就请在文章末尾的左下角把大拇指点亮吧!(#^.^#);

❤如果喜欢HuangJunqi~先生分享的文章,就请给点个关注吧!(๑′ᴗ‵๑)づ╭❤~;

❤对文章有任何问题欢迎小伙伴们下方留言

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HuangJunqi~先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值