zoukankan      html  css  js  c++  java
  • FreeMarker生成java类与sql文件

      在javaweb开发过程中往往需要创建很多与数据库关联的java实体类与sql(xml格式)文件,这些工作是既耗时,又没什么技术含量,但是却是必不可少的工作。使用过mybatis的都知道,mybatis有对应的插件可以快速生成相应的java类与sql文件,通过使用插件可以大大提高开发效率。但是并不是所有的公司都使用mybatis,本人所在的公司就是其中之一。本人所在公司虽然使用的不是mybatis,但是开发过程却是很像,都需要创建实体类与sql文件。由于每次开发都需要创建大量的实体类与sql文件,使本人开发时感到很痛苦,尤其数据库表字段特别多的时候真是相当的痛苦。基于以上原因,本人研究了一下使用FreeMarker 生成文件的方法,在此记录一下,也方便以后的查找。

     “FreeMarker是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。”--来源于网络

      FreeMarker是一种模板引擎,使用过springmvc的应该都知道,springmvc支持多种模板引擎,其中FreeMarker就是其中之一。当然,在springmvc中主要用来做作为前端页面使用。要使用FreeMarker,首先要有对应的模板,其模板的格式为*.ftl。行了,说了这么多,好像都是废话,下面直接上代码。

      1、ftl模板

       此处主要有两个模板:bean.ftl和sqlMap.ftl,一个用来生成实体类,一个用来生成sql文件。

      bean.ftl

    package ${packageName};
    
    import com.alibaba.fastjson.JSONObject;
    import java.util.Date;
    
    /**
    * 〈一句话功能简述〉
    * 〈功能详细描述〉
    *
    * @author 19043197
    * @see [相关类/方法](可选)
    * @since [产品/模块版本] (可选)
    */
    public class ${className} implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
    <#-- 循环类型及属性 -->
    <#list attrs as attr>
        //${attr.remarks}
        private ${attr.type} ${attr.name};
    
    </#list>
    
    <#-- 循环生成set get方法 -->
    <#list attrs as attr>
        public void set${attr.firstUpperName}(${attr.type} ${attr.name}) {
            this.${attr.name} = ${attr.name};
        }
    
        public ${attr.type} get${attr.firstUpperName}() {
            return ${attr.name};
        }
    
    </#list>
    
        @Override
        public String toString() {
            return JSONObject.toJSONString(this);
        }
    }

      sqlMap.ftl

    package ${packageName};
    
    import com.alibaba.fastjson.JSONObject;
    import java.util.Date;
    
    /**
    * 〈一句话功能简述〉
    * 〈功能详细描述〉
    *
    * @author 19043197
    * @see [相关类/方法](可选)
    * @since [产品/模块版本] (可选)
    */
    public class ${className} implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
    <#-- 循环类型及属性 -->
    <#list attrs as attr>
        //${attr.remarks}
        private ${attr.type} ${attr.name};
    
    </#list>
    
    <#-- 循环生成set get方法 -->
    <#list attrs as attr>
        public void set${attr.firstUpperName}(${attr.type} ${attr.name}) {
            this.${attr.name} = ${attr.name};
        }
    
        public ${attr.type} get${attr.firstUpperName}() {
            return ${attr.name};
        }
    
    </#list>
    
        @Override
        public String toString() {
            return JSONObject.toJSONString(this);
        }
    }

      简单介绍下FreeMarker语法:

        (1)、${className} 直接获取对象属性

     (2)、<#list attrs as attr></#list> 对集合进行循环

     (3)、<#if attr_has_next></#if> 条件判断,attr_has_next判断还有下一个,格式:对象_has_next

     (4)、${r" "}或${r''}特殊字符显示,由于本人所在公司sql(xml格式)文件使用的freemerker解析的,所以生成的文件中难免会有以下Freemarker的标签

        2、数据库连接类(此处只贴了mysql的)

    package utils;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    /**
     *  数据库连接工具类(仅mysql)
     * 〈功能详细描述〉
     *
     * @author lipan
     * @see [相关类/方法](可选)
     * @since [产品/模块版本] (可选)
     */
    public class MysqlDBUtil {
    
        private static String URL;
        private static String USER;
        private static String PASSWORD;
        private static String DRIVER;
        static{
            URL = "jdbc:mysql://localhost:3306/lpan?useSSL=false&serverTimezone=UTC";
            USER = "root";
            PASSWORD = "1234";
            DRIVER = "com.mysql.cj.jdbc.Driver";
        }
    
        public static Connection getConnection() throws Exception{
            Class.forName(DRIVER);
            Connection connection= DriverManager.getConnection(URL, USER, PASSWORD);
            return connection;
        }
    
        public static void close(Connection connection){
            if(connection!=null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

        3、ColumnBean类

      主要是定义数据字段与实体类属性

    package utils;
    
    /**
     *  实体类
     * 〈功能详细描述〉
     *
     * @author [作者](必须)
     * @see [相关类/方法](可选)
     * @since [产品/模块版本] (可选)
     */
    public class ColumnBean {
    
        //成员变量类型
        private String type;
        //成员变量名称
        private String name;
        //注释
        private String remarks;
        //首字母大写
        private String firstUpperName;
        //字段(大写)
        private String columnName;
        //指定长度的字段大写,不足右侧补空格(select sql使用,美观,个人习惯)
        private String columnNameWithLen;
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getRemarks() {
            return remarks;
        }
    
        public void setRemarks(String remarks) {
            this.remarks = remarks;
        }
    
        public String getFirstUpperName() {
            return firstUpperName;
        }
    
        public void setFirstUpperName(String firstUpperName) {
            this.firstUpperName = firstUpperName;
        }
    
        public String getColumnName() {
            return columnName;
        }
    
        public void setColumnName(String columnName) {
            this.columnName = columnName;
        }
    
        public String getColumnNameWithLen() {
            return columnNameWithLen;
        }
    
        public void setColumnNameWithLen(String columnNameWithLen) {
            this.columnNameWithLen = columnNameWithLen;
        }
    
        public ColumnBean(String type, String name, String remarks, String firstUpperName, String columnName, String columnNameWithLen) {
            this.type = type;
            this.name = name;
            this.remarks = remarks;
            this.firstUpperName = firstUpperName;
            this.columnName = columnName;
            this.columnNameWithLen = columnNameWithLen;
        }
    
        public ColumnBean() {
        }
    }

        4、从数据库查询表字段信息封装成ColumnBean(此处有mysql和postgresql两种)

    package utils;
    
    import com.alibaba.fastjson.JSONObject;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     *  数据处理
     * 〈功能详细描述〉
     *
     * @author [作者](必须)
     * @see [相关类/方法](可选)
     * @since [产品/模块版本] (可选)
     */
    public class DataUtils {
    
        public static String dealDataTypeForPG(String dataType){
            if(dataType==null || dataType.length()==0){
                throw new RuntimeException("字段类型为空");
            }
            if(dataType.contains("character varying")){
                return "String";
            }else if(dataType.contains("numeric")){
                return "BigDecimal";
            }else if(dataType.contains("timestamp")){
                return "Date";
            }else if(dataType.contains("int4")){
                return "Integer";
            }
            throw new RuntimeException("字段类型转换异常");
        }
    
        public static String dealDataTypeForMysql(String dataType){
            if(dataType==null || dataType.length()==0){
                throw new RuntimeException("字段类型为空");
            }
            if(dataType.contains("varchar")){
                return "String";
            }else if(dataType.contains("decimal")){
                return "BigDecimal";
            }else if(dataType.contains("datetime")){
                return "Date";
            }else if(dataType.contains("int")){
                return "Integer";
            }
            throw new RuntimeException("字段类型转换异常");
        }
    
        /**
         * 首字母大写
         * @param columnName
         * @return
         */
        public static String dealColumnNameFirstUpper(String columnName){
            return columnName.substring(0,1)+columnName.substring(1);
        }
    
        private static Pattern linePattern = Pattern.compile("_(\w)");
    
        /** 下划线转驼峰 */
        public static String lineToHump(String str) {
            str = str.toLowerCase();
            Matcher matcher = linePattern.matcher(str);
            StringBuffer sb = new StringBuffer();
            while (matcher.find()) {
                matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
            }
            matcher.appendTail(sb);
            return sb.toString();
        }
    
        public static ColumnBean createColumnBeanName(String dataType,String columnName,String remarks,String dbType){
            String type = "";
            if("mysql".equals(dbType)){
                type = dealDataTypeForMysql(dataType);
            }else{
                type = dealDataTypeForPG(dataType);
            }
            String name = lineToHump(columnName);
            String firstUpperName = dealColumnNameFirstUpper(name);
            String newColumnName = addEmptyChar(columnName.toUpperCase(), 25);
            ColumnBean columnBean = new ColumnBean(type,name,remarks,firstUpperName,columnName.toUpperCase(),newColumnName);
            return columnBean;
        }
    
        /**
         * 字符串不足指定长度补空格
         * @param str
         * @param length
         * @return
         */
        public static String addEmptyChar(String str,int length){
            StringBuffer buffer = new StringBuffer();
            if(str.isEmpty()){
                for(int i=0;i<length;i++){
                    buffer.append(" ");
                }
            }else if(str.length()<length){
                buffer.append(str);
                for(int i=0;i<length-str.length();i++){
                    buffer.append(" ");
                }
            }else{
                buffer.append(str);
            }
            return buffer.toString();
        }
    
        public static List<ColumnBean> processDataForPG(Connection connection, String tableName) throws SQLException {
            StringBuffer sql = new StringBuffer();
            sql.append(" SELECT  ");
            sql.append("     b.attname AS column_name, ");
            sql.append("     c.description AS remarks, ");
            sql.append("     pg_catalog.format_type(b.atttypid,b.atttypmod) AS data_type ");
            sql.append(" FROM ");
            sql.append("     pg_catalog.pg_class a, ");
            sql.append("     pg_catalog.pg_attribute b, ");
            sql.append("     pg_catalog.pg_description c ");
            sql.append(" WHERE ");
            sql.append("     a.oid=b.attrelid ");
            sql.append(" AND b.attrelid=c.objoid ");
            sql.append(" AND a.relname= ? ");
            sql.append(" AND c.objsubid=b.attnum ");
            PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
            preparedStatement.setString(1,tableName);
            System.out.println(preparedStatement.toString());
            ResultSet resultSet = preparedStatement.executeQuery();
            List<ColumnBean> list = new ArrayList<ColumnBean>();
            while (resultSet.next()){
                String dataType = resultSet.getString("data_type");
                String columnName = resultSet.getString("column_name");
                String remarks = resultSet.getString("remarks");
                ColumnBean columnBean = createColumnBeanName(dataType, columnName, remarks,"PG");
                list.add(columnBean);
            }
            return list;
        }
    
        public static List<ColumnBean> processDataForMysql(Connection connection, String tableName) throws SQLException {
            StringBuffer sql = new StringBuffer();
            sql.append(" select * from information_schema.COLUMNS where table_name= ? ");
            PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
            preparedStatement.setString(1,tableName);
            System.out.println(preparedStatement.toString());
            ResultSet resultSet = preparedStatement.executeQuery();
            List<ColumnBean> list = new ArrayList<ColumnBean>();
            while (resultSet.next()){
                String dataType = resultSet.getString("data_type");
                String columnName = resultSet.getString("column_name");
                String remarks = resultSet.getString("column_comment");
                ColumnBean columnBean = createColumnBeanName(dataType, columnName, remarks,"mysql");
                list.add(columnBean);
            }
            return list;
        }
    }

        5、使用FreeMarker生成具体文件

    package utils;
    
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    
    import java.io.*;
    import java.sql.Connection;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     *  模板生成类
     * 〈功能详细描述〉
     *
     * @author [作者](必须)
     * @see [相关类/方法](可选)
     * @since [产品/模块版本] (可选)
     */
    public class FreemarkerGenerator {
        //模板路径
        public static String PATH = "D:\IdeaProjects\freemarker-generator\src\main\resources";
        //生成文件路径
        public static String OUT_PATH = "E:\study\";
    
        public static void createBean(Connection connection,String packageName, String className, String tableName,String dbType){
            // step1 创建freeMarker配置实例
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
            Writer out = null;
            try {
                // step2 获取模版路径
                configuration.setDirectoryForTemplateLoading(new File(PATH));
                // step3 创建数据模型
                Map<String, Object> dataMap = new HashMap<String, Object>();
                List<ColumnBean> columnBeans = null;
                if("mysql".equals(dbType)){
                    columnBeans = DataUtils.processDataForMysql(connection,tableName);
                }else{
                    columnBeans = DataUtils.processDataForPG(connection,tableName);
                }
                dataMap.put("packageName", packageName);
                dataMap.put("className", className);
                dataMap.put("attrs",columnBeans);
                // step4 加载模版文件
                Template template = configuration.getTemplate("bean.ftl");
                // step5 生成数据
                File docFile = new File(OUT_PATH+className+".java");
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
                // step6 输出文件
                template.process(dataMap, out);
                System.out.println("文件创建成功 !");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != out) {
                        out.flush();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
    
        public static void createSqlMap(Connection connection,String tableName,String fileName,String namespace,String dbType){
            // step1 创建freeMarker配置实例
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
            Writer out = null;
            try {
                // step2 获取模版路径
                configuration.setDirectoryForTemplateLoading(new File(PATH));
                // step3 创建数据模型
                Map<String, Object> dataMap = new HashMap<String, Object>();
    
                List<ColumnBean> columnBeans = null;
                if("mysql".equals(dbType)){
                    columnBeans = DataUtils.processDataForMysql(connection,tableName);
                }else{
                    columnBeans = DataUtils.processDataForPG(connection,tableName);
                }
                dataMap.put("tableName", tableName);
                dataMap.put("namespace", namespace);
                dataMap.put("pageSize","${pageSize}");
                dataMap.put("startPage","${startPage}");
                dataMap.put("attrs",columnBeans);
                // step4 加载模版文件
                Template template = configuration.getTemplate("sqlMap.ftl");
                // step5 生成数据
                File docFile = new File(OUT_PATH+fileName+".xml");
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
                // step6 输出文件
                template.process(dataMap, out);
                System.out.println("文件创建成功 !");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != out) {
                        out.flush();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
    
    }
    PATH 模板的路径
    OUT_PATH生成文件的路径
    代码注释应该比较清楚,在此不多做解释。
    6、测试类
    package utils;
    
    import com.alibaba.fastjson.JSONObject;
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import org.junit.Test;
    
    import java.io.*;
    import java.sql.Connection;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     *  测试类
     * 〈功能详细描述〉
     *
     * @author [作者](必须)
     * @see [相关类/方法](可选)
     * @since [产品/模块版本] (可选)
     */
    public class FreemarkerGeneratorTest {
    
        @Test
        public void testKeyWord() {
            // step1 创建freeMarker配置实例
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
            Writer out = null;
            try {
                // step2 获取模版路径
                configuration.setDirectoryForTemplateLoading(new File(FreemarkerGenerator.PATH));
                // step3 创建数据模型
                Map<String, Object> dataMap = new HashMap<String, Object>();
                dataMap.put("aa", "${pageSize}");
                // step4 加载模版文件
                Template template = configuration.getTemplate("test.ftl");
                // step5 生成数据
                File docFile = new File(FreemarkerGenerator.OUT_PATH + "aa.txt");
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
                // step6 输出文件
                template.process(dataMap, out);
                System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^文件创建成功 !");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != out) {
                        out.flush();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
    
    
        @Test
        public void processDataForMysqlTest() throws Exception {
            Connection connection = MysqlDBUtil.getConnection();
            List<ColumnBean> list = DataUtils.processDataForMysql(connection, "d_menu");
            JSONObject.toJSONString(list);
            System.out.println(JSONObject.toJSONString(list));
            MysqlDBUtil.close(connection);
        }
    
        @Test
        public void createBeanWithMysql() throws Exception {
            String packageName = "com.test";
            String className = "Menu";
            String tableName = "d_menu";
            Connection connection = MysqlDBUtil.getConnection();
            FreemarkerGenerator.createBean(connection,packageName,className,tableName,"mysql");
            PGDBUtil.close(connection);
        }
    
        @Test
        public void createSqlMapWithMysql() throws Exception {
            String tableName = "d_menu";
            String fileName = "sqlMap_menu";
            String namespace = "menu";
            Connection connection = MysqlDBUtil.getConnection();
            FreemarkerGenerator.createSqlMap(connection,tableName,fileName,namespace,"mysql");
            PGDBUtil.close(connection);
        }
    }
    createBeanWithMysql和createSqlMapWithMysql分别是测试生成实体类和sql配置文件。
    生成后的文件

    Menu.java

    package com.test;
    
    import com.alibaba.fastjson.JSONObject;
    
    /**
    * 〈一句话功能简述〉
    * 〈功能详细描述〉
    *
    * @author xxxxx
    * @see [相关类/方法](可选)
    * @since [产品/模块版本] (可选)
    */
    public class Menu implements Serializable {
    
        private static final long serialVersionUID = -5717628049858495391L;
    
        //主键
        private Integer menuId;
    
        //创建时间
        private Date createDate;
    
        //图标
        private String iconCls;
    
        //菜单名称
        private String menuName;
    
        //父id
        private Integer pid;
    
        //状态
        private String status;
    
        //菜单地址
        private String url;
    
    
        public void setmenuId(Integer menuId) {
            this.menuId = menuId;
        }
    
        public Integer getmenuId() {
            return menuId;
        }
    
        public void setcreateDate(Date createDate) {
            this.createDate = createDate;
        }
    
        public Date getcreateDate() {
            return createDate;
        }
    
        public void seticonCls(String iconCls) {
            this.iconCls = iconCls;
        }
    
        public String geticonCls() {
            return iconCls;
        }
    
        public void setmenuName(String menuName) {
            this.menuName = menuName;
        }
    
        public String getmenuName() {
            return menuName;
        }
    
        public void setpid(Integer pid) {
            this.pid = pid;
        }
    
        public Integer getpid() {
            return pid;
        }
    
        public void setstatus(String status) {
            this.status = status;
        }
    
        public String getstatus() {
            return status;
        }
    
        public void seturl(String url) {
            this.url = url;
        }
    
        public String geturl() {
            return url;
        }
    
    
        @Override
        public String toString() {
            return JSONObject.toJSONString(this);
        }
    }

    sqlMap_menu.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <sqlMap namespace="menu">
    
        <sql id="queryCount">
            <![CDATA[
                SELECT
                    COUNT(ID)    AS    TOTALCOUNT
                FROM
                    D_MENU
                WHERE 1=1
            ]]>
        </sql>
    
        <sql id="queryList">
            <![CDATA[
                SELECT
                    MENU_ID                   AS "menuId",
                    CREATE_DATE               AS "createDate",
                    ICON_CLS                  AS "iconCls",
                    MENU_NAME                 AS "menuName",
                    PID                       AS "pid",
                    STATUS                    AS "status",
                    URL                       AS "url"
                FROM
                    D_MENU
                WHERE 1=1
                    LIMIT ${pageSize} OFFSET ${startPage}
            ]]>
        </sql>
    
        <sql id="insert">
            <![CDATA[
                INSERT INTO D_MENU(
                    MENU_ID,
                    CREATE_DATE,
                    ICON_CLS,
                    MENU_NAME,
                    PID,
                    STATUS,
                    URL
                )
                VALUES
                (
                    :menuId,
                    :createDate,
                    :iconCls,
                    :menuName,
                    :pid,
                    :status,
                    :url
                )
            ]]>
        </sql>
    
        <sql id="update">
            <![CDATA[
                UPDATE D_MENU
                SET
                    MENU_ID = :menuId,
                    CREATE_DATE = :createDate,
                    ICON_CLS = :iconCls,
                    MENU_NAME = :menuName,
                    PID = :pid,
                    STATUS = :status,
                    URL = :url
                WHERE
                <#if menuId?exists && menuId!=''>
                        MENU_ID = :menuId
                </#if>
                <#if createDate?exists && createDate!=''>
                    AND CREATE_DATE = :createDate
                </#if>
                <#if iconCls?exists && iconCls!=''>
                    AND ICON_CLS = :iconCls
                </#if>
                <#if menuName?exists && menuName!=''>
                    AND MENU_NAME = :menuName
                </#if>
                <#if pid?exists && pid!=''>
                    AND PID = :pid
                </#if>
                <#if status?exists && status!=''>
                    AND STATUS = :status
                </#if>
                <#if url?exists && url!=''>
                    AND URL = :url
                </#if>
            ]]>
        </sql>
    
    
    </sqlMap>

     github地址:https://github.com/panli1988/freemarker-generator

        以上全部内容,仅供参考

  • 相关阅读:
    可搜索的下拉框
    Vue 父组件调用子组件的方法
    vue中异步函数async和await的用法
    用配置文件的方法发送axios请求
    vue中 localStorage的使用方法(详解)
    下拉框 组件的使用
    遇到不懂的记录
    做测试平台可能会用到的东西
    下拉框 v-for循环拿值的方法
    ant 自定义遮罩
  • 原文地址:https://www.cnblogs.com/xiupan/p/12630692.html
Copyright © 2011-2022 走看看