ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

使用Freemarker模板自动生成代码

2019-09-17 16:02:58  阅读:155  来源: 互联网

标签:String Freemarker DATABASE 代码 param new public 模板


前言

因感概业务代码存在大量的增删改查功能,只是针对不同的表数据而已。故想有没有办法,在重复的相同代码中替换某些内容,于是按此思路搜寻,了解到有freemarker这个东西,一番学习后,特记录于此。

Freemarker简介

FreeMarker是一款模板引擎: 一种基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。即:输出=模板+数据。简单来说,其用法原理类似String的replace方法,或MessageFormat的format方法,都是在一定的代码中改变(替换)某些内容。不过FreeMarker更加强大,模板来源可以是外部文件或字符串格式,替换的数据格式多样,而且支持逻辑判断,如此替换的内容将更加灵活。

小例子

比如我们要产生实体类,我们将模板定义如下,模板文件名为entity.flt(flt是freemarker模板的后缀名)

package com.tenny.${interfaceName?lower_case}.entity;

import java.util.Date;

public class ${entityName} {

<#list params as param>
    // ${param.fieldNote}
    private ${param.fieldType} ${param.fieldName};

</#list>
<#list params as param>
    public void set${param.fieldName?cap_first}(${param.fieldType} ${param.fieldName}){
        this.${param.fieldName} = ${param.fieldName};
    }

    public ${param.fieldType} get${param.fieldName?cap_first}(){
        return this.${param.fieldName};
    }

</#list>
}

其中的${xxx}就是变量了,由外部传入。可以看到模板还有类似java for each循环的语法。

接下来我们要填充数据了。数据来源后面详细说,先假定我们有了数据。其格式为Map,内容为:

Map<String, Object> beanMap = new HashMap<String, Object>();
beanMap.put("beanName", "User");// 实体类名
beanMap.put("interfaceName", "User");// 接口名
List<Map<String, String>> paramsList = new ArrayList<Map<String, String>>();
for (int i = 0; i < 4; i++) {
      Map<String, String> tmpParamMap = new HashMap<String, String>();
      tmpParamMap.put("fieldNote", "fieldNote" + i);
      tmpParamMap.put("fieldType", "String");
      tmpParamMap.put("fieldName", "fieldName" + i);
      paramsList.add(tmpParamMap);
}
beanMap.put("params", paramsList);

最后我们使用模板替换数据(这里我的模板放在resources/model/下,目标文件放在resources/class/下):

Configuration config = new Configuration();
config.setObjectWrapper(new DefaultObjectWrapper());
Template template = config.getTemplate("src/main/resources/model/entity.ftl", "UTF-8");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("src/main/resources/class/User.java"), "UTF-8"));
template.process(rootMap, out);
out.flush();
out.close();

这样最后生成的User.java的内容大概如下:

package com.tenny.user.entity;

import java.util.Date;

public class User {

    // 主键id
    private Integer id;

    // 用户名
    private String username;

    // 密码
    private String password;

    // 用户类型#1、管理员;2、普通用户
    private Integer type;

    // 创建时间
    private Date createtime;

    public void setId(Integer id){
        this.id = id;
    }

    public Integer getId(){
        return this.id;
    }

    public void setUsername(String username){
        this.username = username;
    }

    public String getUsername(){
        return this.username;
    }

    public void setPassword(String password){
        this.password = password;
    }

    public String getPassword(){
        return this.password;
    }

    public void setType(Integer type){
        this.type = type;
    }

    public Integer getType(){
        return this.type;
    }

    public void setCreatetime(Date createtime){
        this.createtime = createtime;
    }

    public Date getCreatetime(){
        return this.createtime;
    }

}

补充

其实上面已经基本将Freemarker的用法展现了。但是我们还可以做更多改进。

使用数据库作为数据来源

模板中要替换的数据,我们可以从外部手动输入,然后由程序拼装成模板引擎需要的格式。但因为我们最开始也说了,大部分相同的是增删改查,不同的是业务数据库表,所以我们可以直接将数据库表字段作为数据来源。

假如你使用的是mysql,可以写一个mysql工具类,获取数据库字段信息

package utils;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MysqlUtil {
    private static String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    private static String DATABASE_URL = "jdbc:mysql://localhost:3306/news";
    private static String DATABASE_URL_PREFIX = "jdbc:mysql://";
    private static String DATABASE_USER = "root";
    private static String DATABASE_PASSWORD = "tenny123";
    private static Connection con = null;
    private static DatabaseMetaData dbmd = null;

    /**
     * 初始化数据库链接
     * @param db_url 数据库地址(ex: localhost:3306/news)
     * @param db_user 用户名
     * @param db_pw 密码
     */
    public static void init(String db_url, String db_user, String db_pw){
        try {
            DATABASE_URL = DATABASE_URL_PREFIX + db_url;
            DATABASE_USER = db_user;
            DATABASE_PASSWORD = db_pw;
            Class.forName(DRIVER_CLASS);
            con = DriverManager.getConnection(DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD);
            dbmd = con.getMetaData();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取当前用户所有表
     * @return
     */
    public static List<String> getTables(){
        List<String> tables = new ArrayList<String>();

        try {
            ResultSet rs = dbmd.getTables(null, DATABASE_USER, null, new String[] { "TABLE" });
            while (rs.next()) {
                tables.add(rs.getString("TABLE_NAME"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return tables;
    }

    /**
     * 获取表字段信息
     * @param tableName
     * @return
     */
    public static List<Map<String,String>> getTableCloumns(String tableName){
        List<Map<String,String>> columns = new ArrayList<Map<String,String>>();
        try{
            Statement stmt = con.createStatement();

            String sql = "select column_name, data_type, column_key, is_nullable, column_comment from information_schema.columns where table_name='" + tableName + "'and table_schema='" + DATABASE_URL.substring(DATABASE_URL.lastIndexOf("/") + 1, DATABASE_URL.length()) + "'";
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()){
                HashMap<String,String> map = new HashMap<String,String>();
                map.put("columnName", rs.getString("column_name"));
                map.put("dataType", rs.getString("data_type"));
                map.put("isKey", ParamUtil.isEmpty(rs.getString("column_key"))?"false":"true");
                map.put("notNull", rs.getString("is_nullable").equals("YES")?"false":"true");
                map.put("comment", rs.getString("column_comment"));
                columns.add(map);
            }
        }
        catch (SQLException e){
            e.printStackTrace();
        }finally{
            if(null != con){
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return columns;
    }

}

获取了数据表字段信息,再加上自己需要的一些属性,就可以给模板引擎生成最终代码文件了。

将freemarker转为字符串模板

还可以在一开始就将模板数据读取出来,存放在内存中。

/**
     * 将模板内容转成字符串
     * @param modle 模板名【eg:entity.ftl】
     * @return
     */
    public static String file2Str(String modle){
        StringBuffer buffer = new StringBuffer();
        try {
            BufferedReader br = new BufferedReader(new FileReader("/WEB-INF/templates/" + model));
            String line = "";
            while((line = br.readLine()) != null){
                buffer.append(line).append(System.getProperty("line.separator"));// 保持原有换行格式
            }
            br.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer.toString();
    }

当然,利用字符串模板填充数据的写法有些不同

Configuration config  = new Configuration();
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("entity", "this is a template of ${entityName}");
config.setTemplateLoader(stringTemplateLoader);

StringWriter stringWriter = new StringWriter();
Template template = config.getTemplate("entity", "UTF-8");
Writer out = new BufferedWriter(stringWriter);
template.process(rootMap, out);
out.flush();
out.close();
return stringWriter.toString();

这样可以将其输入到html页面观看。如果需要的话,还可以随时修改模板,后台接收前端的字符串模板。如此,模板和数据都可以随意定制,岂不是更加灵活方便。

其他

有了以上的认知,我们可以做一个页面,输入数据库参数后,选中某个表,就可以生成关于改表的增删改查代码。或者在页面上添加字段,用这些字段来生成代码。这个就可以自由发挥了~

帖几张我自己的页面截图(没啥样式,吃藕勿喷)
首页
我已经将模板转换成字符串输出了,这样方便查看(其实直接看模板文件也一样= =!)
模板字符串
点击获取表,后台就根据数据库属性查询列表,然后我们选择某一个表,前端自动填充"实体名"和"接口名"属性,一般情况无需修改,点击提交,当当~我们的代码就出来了
代码

当然还可以自定义字段,比如我们不选表,也就是说不用数据库作为来源,在页面上添加几个字段
添加字段1

添加字段2

如果你也使用spring mvc,可以和我一样,设定好多个模板后,一次性将controller-service-serviceImpl-dao-entity-mapping-test全部产生。后面甚至可以继续设定目录或包,产生的代码就可以直接使用啦。

总结

嗯,一句话,模板+数据=最终代码。

模板根据目标代码制定,数据来源我们根据实际情况获取,如此便可diy自己的autocode。

我的autocode地址:https://github.com/tenny-peng/autocode

参考链接:http://www.cnblogs.com/yejg1212/p/4322452.html
     http://blog.csdn.net/xiekuntarena/article/details/53032907
     http://blog.csdn.net/5iasp/article/details/27181365

标签:String,Freemarker,DATABASE,代码,param,new,public,模板
来源: https://www.cnblogs.com/tenny-peng/p/11534476.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有