(三)(便捷開發)基於freemarker的代碼生成工具

freemarker依賴:

        <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

實體類Table.java:

package per.san.generate.domain;

import per.san.common.CommonConstant;
import per.san.common.utils.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * description: 表數據
 *
 * @author sanchar
 * @date 12/12/2018 13:26
 * lastUpdateBy: sanchar
 * lastUpdateDate: 12/12/2018
 */
public class Table {

    /**
     * 表的名稱
     */
    private String tableName;

    /**
     * 數據庫引擎
     */
    private String engine;

    /**
     * 表的備註
     */
    private String comments;

    /**
     * 創建時間
     */
    private Date createTime;

    /**
     * 類名(第一個字母大寫),如:sys_user => SysUser
     */
    private String className;

    /**
     * 是否存在日期類型列
     * 0:不存在  1:存在
     */
    private Integer existDate;

    /**
     * 表的主鍵
     */
    private Column pk;

    /**
     * 表的列名
     */
    private List<Column> columns;

    public String getTableName() {
        return tableName;
    }

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

    public String getEngine() {
        return engine;
    }

    public void setEngine(String engine) {
        this.engine = engine;
    }

    public String getComments() {
        return comments;
    }

    public void setComments(String comments) {
        this.comments = comments;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getClassName() {
        return StringUtils.replaceUnderLineAndUpperCase(this.tableName);
    }

    public Integer getExistDate() {
        if(this.columns != null){
            for (Column column : this.columns) {
                if(CommonConstant.DATE.equalsIgnoreCase(column.getAttrType())) {
                    return 1;
                }
            }
        }
        return 0;
    }

    public Column getPk() {
        return pk;
    }

    public void setPk(Column pk) {
        this.pk = pk;
    }

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

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

實體類Column.java:

package per.san.generate.domain;

import per.san.common.SqlToJavaTypeEnum;
import per.san.common.utils.StringUtils;

/**
 * description: 列的屬性
 *
 * @author sanchar
 * @date 12/12/2018 13:24
 * lastUpdateBy: sanchar
 * lastUpdateDate: 12/12/2018
 */
public class Column {

    /**
     * 列名
     */
    private String columnName;

    /**
     * 列名類型
     */
    private String dataType;

    /**
     * 列名備註
     */
    private String comments;

    /**
     * 主鍵
     */
    private String columnKey;

    /**
     * 屬性名稱(第一個字母小寫),如:user_name => userName
     */
    private String attrName;

    /**
     * 屬性類型
     */
    private String attrType;

    /**
     * auto_increment
     */
    private String extra;

    public String getColumnName() {
        return columnName;
    }

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

    public String getDataType() {
        return dataType;
    }

    public void setDataType(String dataType) {
        this.dataType = dataType;
    }

    public String getComments() {
        return comments;
    }

    public void setComments(String comments) {
        this.comments = comments;
    }

    public String getColumnKey() {
        return columnKey;
    }

    public void setColumnKey(String columnKey) {
        this.columnKey = columnKey;
    }

    public String getAttrName() {
        return StringUtils.replaceUnderLineAndUpperCase(this.columnName);
    }

    public String getAttrType() {
        if(this.dataType != null)
            return SqlToJavaTypeEnum.valueOf(this.dataType.toUpperCase()).getJavaType();
        return null;
    }

    public void setAttrType(String attrType) {
        this.attrType = attrType;
    }

    public String getExtra() {
        return extra;
    }

    public void setExtra(String extra) {
        this.extra = extra;
    }
}

查詢數據表相關數據屬性mapper.xml:

<?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="per.san.generate.mapper.MySQLGenerateMapper">
    <resultMap id="tableResultMap" type="per.san.generate.domain.Table">
        <result property="tableName" column="table_name"/>
        <result property="engine" column="engine"/>
        <result property="comments" column="table_comment"/>
        <result property="createTime" column="create_time"/>
        <association property="pk" javaType="per.san.generate.domain.Column">
            <result property="columnName" column="pk_column_name"/>
            <result property="dataType" column="pk_data_type"/>
            <result property="comments" column="pk_column_comment"/>
            <result property="columnKey" column="pk_column_key"/>
            <result property="extra" column="pk_extra"/>
        </association>
        <collection property="columns" ofType="per.san.generate.domain.Column">
            <result property="columnName" column="column_name"/>
            <result property="dataType" column="data_type"/>
            <result property="comments" column="column_comment"/>
            <result property="columnKey" column="column_key"/>
            <result property="extra" column="extra"/>
        </collection>
    </resultMap>

    <sql id="tableBaseSql">
        ts.table_name, ts.engine, ts.table_comment, ts.create_time
    </sql>

    <sql id="columnBaseSql">
        pk.column_name as pk_column_name, pk.data_type as pk_data_type,
        pk.column_comment as pk_column_comment, pk.column_key as pk_column_key, pk.extra as pk_extra,
        cs.column_name, cs.data_type, cs.column_comment, cs.column_key, cs.extra
    </sql>

    <select id="queryList" resultMap="tableResultMap">
        select
        <include refid="tableBaseSql"/>,
        <include refid="columnBaseSql"/>
        from (select ist.* from information_schema.tables ist
              <where>
                  <if test="tableName != null and tableName.trim() != ''">
                      and ist.table_name like concat('%', #{tableName}, '%')
                  </if>
                  <if test="engine != null and engine.trim() != ''">
                      and ist.engine = #{engine}
                  </if>
                  <if test="comments != null and comments.trim() != ''">
                      and ist.table_comment like concat('%', #{comments}, '%')
                  </if>
                  ist.table_schema = (select database())
              </where>
        ) as ts left join information_schema.columns cs on cs.table_name = ts.table_name
        <where>
            cs.table_schema = (select database())
        </where>
        order by ts.create_time desc
    </select>

    <select id="queryTable" resultMap="tableResultMap">
        select
        <include refid="tableBaseSql"/>,
        <include refid="columnBaseSql"/>
        from (select ist.* from information_schema.tables ist
              where ist.table_name = #{tableName}
              and ist.table_schema = (select database()) limit 1
        ) as ts, information_schema.columns pk
        left join information_schema.columns cs on cs.table_name = #{tableName}
        <where>
            and cs.table_schema = (select database())
            and pk.table_schema = (select database())
            and pk.table_name = #{tableName}
            and pk.column_key = 'PRI'
            and cs.column_key &lt;&gt; 'PRI'
        </where>
    </select>

    <select id="queryColumns" resultType="java.util.Map">
		select column_name, data_type, column_comment,
		       column_key, extra
		from information_schema.columns
 		where table_name = #{tableName}
 		and table_schema = (select database())
 		order by ordinal_position
    </select>
</mapper>

service實現層查詢數據調工具類生成代碼:

    @Override
    public Table queryTable(String tableName) {
        Table table = mySQLGenerateMapper.queryTable(tableName);
        try {
            CodeGenerateUtils.generate(table);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return table;
    }

FreeMarkerTemplateUtils工具類:

package per.san.common.utils;

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

import java.io.IOException;

/**
 * description: 模板加載
 *
 * @author sanchar
 * @date 12/10/2018 17:10
 * lastUpdateBy: sanchar
 * lastUpdateDate: 12/10/2018
 */
public class FreeMarkerTemplateUtils {
    private FreeMarkerTemplateUtils(){}
    private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);

    static{
        //這裏比較重要,用來指定加載模板所在的路徑
        CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtils.class, "/generate/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();
    }
}

CodeGenerateUtils工具類:

package per.san.common.utils;

import freemarker.template.Template;
import per.san.common.CommonConstant;
import per.san.generate.domain.Table;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * description: 代碼生成器
 *
 * @author sanchar
 * @date 12/10/2018 17:10
 * lastUpdateBy: sanchar
 * lastUpdateDate: 12/10/2018
 */
public class CodeGenerateUtils {

    private static final String AUTHOR = "sanchar";

    private static Date CURRENT_DATE;

    private static String TARGET_PATH;

    private static String PACKAGE_PATH;

    private static String MAPPER_XML_PATH;

    static {
        CURRENT_DATE = new Date();
        TARGET_PATH = System.getProperty("user.dir") + "\\src\\main\\";
        PACKAGE_PATH = "per\\san\\demo\\";
        MAPPER_XML_PATH = "mapper\\demo\\";
    }

    public static void generate(Table table){
        generateModelFile(table);
        generateMapperXmlFile(table);
        generateMapperFile(table);
        generateServiceImplFile(table);
        generateServiceFile(table);
        generateControllerFile(table);
    }

    private static void generateModelFile(Table table){
        String suffix = ".java";
        String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "domain\\" + table.getClassName() + suffix;
        String templateName = "Model.ftl";
        generateFile(table, path, PACKAGE_PATH, templateName);
    }

    private static void generateMapperXmlFile(Table table){
        String suffix = "Mapper.xml";
        String path = TARGET_PATH + "resources\\" + MAPPER_XML_PATH + table.getClassName() + suffix;
        String templateName = "MapperXml.ftl";
        generateFile(table, path, PACKAGE_PATH, templateName);
    }

    private static void generateMapperFile(Table table){
        String suffix = "Mapper.java";
        String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "mapper\\" + table.getClassName() + suffix;
        String templateName = "Mapper.ftl";
        generateFile(table, path, PACKAGE_PATH, templateName);
    }

    private static void generateServiceImplFile(Table table){
        String suffix = "ServiceImpl.java";
        String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "service\\impl\\" + table.getClassName() + suffix;
        String templateName = "ServiceImpl.ftl";
        generateFile(table, path, PACKAGE_PATH, templateName);
    }

    private static void generateServiceFile(Table table){
        String suffix = "Service.java";
        String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "service\\I" + table.getClassName() + suffix;
        String templateName = "Service.ftl";
        generateFile(table, path, PACKAGE_PATH, templateName);
    }

    private static void generateControllerFile(Table table){
        String suffix = "Controller.java";
        String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "controller\\" + table.getClassName() + suffix;
        String templateName = "Controller.ftl";
        generateFile(table, path, PACKAGE_PATH, templateName);
    }

    private static void generateFile(Table table, String path, String packagePath, String templateName){
        File file = new File(path);
        Map<String,Object> dataMap = new HashMap<>(2);
        dataMap.put("table",table);
        String packageName = packagePath.substring(0, packagePath.length()-1);
        if(packageName.contains(CommonConstant.SLASH)){
            packageName = packageName.replace(CommonConstant.SLASH, ".");
        }
        if(packageName.contains(CommonConstant.BACK_SLASH)){
            packageName = packageName.replace(CommonConstant.BACK_SLASH, ".");
        }
        dataMap.put("packageName",packageName);
        try {
            generateFileByTemplate(templateName,file,dataMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static 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("author", AUTHOR);
        dataMap.put("date", CURRENT_DATE);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
        template.process(dataMap, out);
    }
}

模板文件Model.ftl:

package ${packageName}.domain;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
<#if table.existDate == 1>
import java.util.Date;

</#if>
/**
 * description: ${table.comments}
 *
 * @author ${author}
 * @date ${date?string('yyyy-MM-dd hh:mm')}
 * lastUpdateBy: ${author}
 * lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
 */
@Table(name="${table.tableName}")
public class ${table.className} {

    /**
    *${table.pk.comments!}
    */
    @Id
    private ${table.pk.attrType} ${table.pk.attrName?uncap_first};

<#if table.columns?exists>
    <#list table.columns as column>
    /**
    *${column.comments!}
    */
    @Column(name = "${column.columnName}",columnDefinition = "${column.dataType?upper_case}")
    private ${column.attrType} ${column.attrName?uncap_first};

    </#list>
</#if>
    public ${table.pk.attrType} get${table.pk.attrName}() {
        return this.${table.pk.attrName?uncap_first};
    }

    public void set${table.pk.attrName}(${table.pk.attrType} ${table.pk.attrName?uncap_first}) {
        this.${table.pk.attrName?uncap_first} = ${table.pk.attrName?uncap_first};
    }

<#if table.columns?exists>
    <#list table.columns as column>
    public ${column.attrType} get${column.attrName}() {
        return this.${column.attrName?uncap_first};
    }

    public void set${column.attrName}(${column.attrType} ${column.attrName?uncap_first}) {
        this.${column.attrName?uncap_first} = ${column.attrName?uncap_first};
    }

    </#list>
</#if>
}

MapperXml.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="${packageName}.mapper.${table.className}Mapper" >

    <delete id="deleteBatch">
        delete from ${table.tableName}
        <where>
            ${table.pk.columnName} in
            <foreach collection="ids" item="id" open="(" close=")" separator=",">
                ${r'#{id}'}
            </foreach>
        </where>
    </delete>
</mapper>

Mapper.ftl:

package ${packageName}.mapper;

import org.apache.ibatis.annotations.Param;
import ${packageName}.domain.${table.className};
import tk.mybatis.mapper.common.BaseMapper;

import java.util.List;

/**
 * description: ${table.comments}
 *
 * @author ${author}
 * @date ${date?string('yyyy-MM-dd hh:mm')}
 * lastUpdateBy: ${author}
 * lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
 */
public interface ${table.className}Mapper extends BaseMapper<${table.className}> {

    /**
     * description: 批量刪除
     * @param ids 刪除數據的id數組
     * @return 刪除成功的條數
     */
    Integer deleteBatch(@Param("ids") List<Long> ids);

}

ServiceImpl.ftl:

package ${packageName}.service.impl;

import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import per.san.common.utils.page.PageHelper;
import per.san.common.utils.page.PageRequest;
import ${packageName}.domain.${table.className};
import ${packageName}.mapper.${table.className}Mapper;
import ${packageName}.service.I${table.className}Service;

import java.util.List;

/**
 * description: ${table.comments}
 *
 * @author ${author}
 * @date ${date?string('yyyy-MM-dd hh:mm')}
 * lastUpdateBy: ${author}
 * lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
 */
@Service
public class ${table.className}ServiceImpl implements I${table.className}Service {

    @Autowired
    ${table.className}Mapper ${table.className?uncap_first}Mapper;

    @Override
    public Integer add(${table.className} ${table.className?uncap_first}) {
        return ${table.className?uncap_first}Mapper.insertSelective(${table.className?uncap_first});
    }

    @Override
    public Integer deleteByPrimaryKey(Long id) {
        return ${table.className?uncap_first}Mapper.deleteByPrimaryKey(id);
    }

    @Override
    public Integer deleteBatch(List<Long> ids) {
        return ${table.className?uncap_first}Mapper.deleteBatch(ids);
    }

    @Override
    public Integer update(${table.className} ${table.className?uncap_first}) {
        return ${table.className?uncap_first}Mapper.updateByPrimaryKeySelective(${table.className?uncap_first});
    }

    @Override
    public PageInfo<${table.className}> pageQuery(PageRequest pageRequest, ${table.className} ${table.className?uncap_first}) {
        return PageHelper.doPage(pageRequest, () -> ${table.className?uncap_first}Mapper.select(${table.className?uncap_first}));
    }

    @Override
    public List<${table.className}> queryList(${table.className} ${table.className?uncap_first}) {
        return ${table.className?uncap_first}Mapper.select(${table.className?uncap_first});
    }
}

Service.ftl:

package ${packageName}.service;

import com.github.pagehelper.PageInfo;
import per.san.common.utils.page.PageRequest;
import ${packageName}.domain.${table.className};

import java.util.List;

/**
 * description: ${table.comments}
 *
 * @author ${author}
 * @date ${date?string('yyyy-MM-dd hh:mm')}
 * lastUpdateBy: ${author}
 * lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
 */
public interface I${table.className}Service {

    /**
     * description: 新增
     * @param ${table.className?uncap_first} 新增的信息
     * @return 新增成功的條數
     */
    Integer add(${table.className} ${table.className?uncap_first});

    /**
     * description: 根據主鍵id刪除
     * @param id 刪除數據的id
     * @return 刪除成功的條數
     */
    Integer deleteByPrimaryKey(Long id);

    /**
     * description: 批量刪除
     * @param ids 刪除數據的id數組
     * @return 刪除成功的條數
     */
    Integer deleteBatch(List<Long> ids);

    /**
    * description: 更新
    * @param ${table.className?uncap_first} 更新的信息
    * @return 更新成功的條數
    */
    Integer update(${table.className} ${table.className?uncap_first});

    /**
    * description: 分頁查詢
    * @param pageRequest 分頁查詢參數
    * @param ${table.className?uncap_first} 分頁查詢條件
    * @return 分頁數據
    */
    PageInfo<${table.className}> pageQuery(PageRequest pageRequest, ${table.className} ${table.className?uncap_first});

    /**
    * description: 查詢List
    * @param ${table.className?uncap_first} 查詢條件
    * @return 數據List
    */
    List<${table.className}> queryList(${table.className} ${table.className?uncap_first});

}

Controller.ftl:

package ${packageName}.controller;

import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import per.san.common.utils.page.PageRequest;
import ${packageName}.domain.${table.className};
import ${packageName}.service.I${table.className}Service;
<#if table.existDate == 1>

import java.util.Date;
</#if>
import java.util.List;

/**
 * description: ${table.comments}
 *
 * @author ${author}
 * @date ${date?string('yyyy-MM-dd hh:mm')}
 * lastUpdateBy: ${author}
 * lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
 */
@RestController
@RequestMapping("/v1/${table.tableName?replace("_","/")}")
public class ${table.className}Controller {

    @Autowired
    I${table.className}Service i${table.className}Service;

    @PostMapping
    public ResponseEntity<Integer> add(@RequestBody ${table.className} ${table.className?uncap_first}) {
    return new ResponseEntity<>(i${table.className}Service.add(${table.className?uncap_first}), HttpStatus.OK);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Integer> delete(@PathVariable("id") Long id) {
        return new ResponseEntity<>(i${table.className}Service.deleteByPrimaryKey(id), HttpStatus.OK);
    }

    @DeleteMapping("/batch")
    public ResponseEntity<Integer> deleteBatch(@RequestBody List<Long> ids) {
        return new ResponseEntity<>(i${table.className}Service.deleteBatch(ids), HttpStatus.OK);
    }

    @PutMapping
    public ResponseEntity<Integer> update(@RequestBody ${table.className} ${table.className?uncap_first}) {
        return new ResponseEntity<>(i${table.className}Service.update(${table.className?uncap_first}), HttpStatus.OK);
    }

    @GetMapping("/page")
    public ResponseEntity<PageInfo<${table.className}>> pageQuery(
            PageRequest pageRequest,
            <#if table.columns?exists>
                <#list table.columns as column>
            @RequestParam(required = false) ${column.attrType} ${column.attrName?uncap_first}<#if column_has_next>,</#if>
                </#list>
            </#if>) {
        ${table.className} ${table.className?uncap_first} = new ${table.className}();
        <#if table.columns?exists>
            <#list table.columns as column>
        ${table.className?uncap_first}.set${column.attrName}(${column.attrName?uncap_first});
            </#list>
        </#if>
        return new ResponseEntity<>(i${table.className}Service.pageQuery(pageRequest, ${table.className?uncap_first}), HttpStatus.OK);
    }

    @GetMapping
    public ResponseEntity<List<${table.className}>> queryList(
            <#if table.columns?exists>
                <#list table.columns as column>
            @RequestParam(required = false) ${column.attrType} ${column.attrName?uncap_first}<#if column_has_next>,</#if>
                </#list>
            </#if>) {
        ${table.className} ${table.className?uncap_first} = new ${table.className}();
        <#if table.columns?exists>
            <#list table.columns as column>
        ${table.className?uncap_first}.set${column.attrName}(${column.attrName?uncap_first});
            </#list>
        </#if>
        return new ResponseEntity<>(i${table.className}Service.queryList(${table.className?uncap_first}), HttpStatus.OK);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章