经过前2篇博文的努力,现在已经我们已经可以通过自己定义数据库的相关设置,但是原始的MBG生成的类过于简单,即使生成了出来的文件还需要我们生成controller,service后才能进行开发,这次开发的工具主要就是解决这个问题,利用FreeMark模板语言生成基于指定表生成对应整套模板,生成文件后开箱即用。
1.FreeMark
1.1 简介
FreeMarker是一个基于Java的模板引擎,最初专注于使用MVC软件架构生成动态网页。但是,它是一个通用的模板引擎,不依赖于servlets或HTTP或HTML,因此它通常用于生成源代码,配置文件或电子邮件。
1.2 使用
在SpingBoot环境下只需要引用boot自带的starter依赖,添加配置,依赖注入Configuration就能使用。
配置如下:
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
application.yml
spring:
freemarker:
template-loader-path: classpath:/ftl
1.3 常用语法
输出
${cloumn}
if..else
<#if columntemp.primaryKey == true>1<#else >2</#if>
循环
<#list columnList as columntemp></#list>
转义
${"#"}
2.模板生成
其实只用简单的jdbc就可以获取模板需要的基础参数,但是MBG分析出的参数齐全基于不做不必要的轮子的想法,我的这个工具直接套用了MBG,在此之上生成模板。
2.1 流程
2.2 源码追踪
通过对源码的学习,我们可以定位到Context中的generateFiles方法中,因此在循环中追加了下面代码:
TableRelateDetail tableinfo = (TableRelateDetail) ThreadLocalUtil.get("tableinfo");
//封装FreeMark参数
Map<String,Object> freemarkMap=new HashMap();
//定义对象名称
freemarkMap.put("objectName",CommonUtil.upperCaseObjectName(tableinfo.getObjectName()));//对象名称
freemarkMap.put("lowerObjectName",tableinfo.getObjectName().toLowerCase());//全小写类名
freemarkMap.put("upperObjectName",tableinfo.getObjectName().toUpperCase());//全大写雷鸣
freemarkMap.put("author",tableinfo.getAuthor());//作者
freemarkMap.put("serverPackage",tableinfo.getServerPackage());//服务路径
freemarkMap.put("objectPackage",tableinfo.getObjectPackage());//对象路径
freemarkMap.put("tableName",introspectedTable.getTableConfiguration().getTableName());//表名
List<ColumnObject> columnList=new ArrayList<>();
CommonUtil.buildColumnList(columnList,introspectedTable.getPrimaryKeyColumns(),true);
CommonUtil.buildColumnList(columnList,introspectedTable.getNonPrimaryKeyColumns(),false);
freemarkMap.put("columnList",columnList);//列数组
ColumnObject对象,他涵盖了POJO对象生成时需要的参数,而nullable,isPrimaryKey这些参数则用于模板生成时的非空注解@Null的判断规则还有resultMap生成id元素的判断。
public class ColumnObject {
/**
* 列名
*/
private String columnname;
/**
* 列名
*/
private String columnCNname;
/**
* 是否可空
*/
private Boolean nullable;
/**
* 列类型
*/
private Integer columnType;
/**
* 长度
*/
private Integer length;
/**
* 是否主键
*/
private Boolean isPrimaryKey;
/**
* java类型
*/
private String javaType;
/**
* sql列
*/
private String SqlColumn;
}
最后来看一看模板,首先你肯定需要了解每个文件代码的组成,这样你才知道在模板中哪里需要输出什么代码,例如mybatis的xml文件中resultMap的id是依据什么定义的,根据不同类型的文件,利用freemark的代码进行数据输出的限制,最终得到:
<?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="${serverPackage}.mapper.${objectName}Mapper">
<resultMap id="ResultMap" type="${objectPackage}.vo.${objectName}VO">
<#list columnList as columntemp>
<#if columntemp.primaryKey == true>
<id column="${columntemp.sqlColumn}" jdbcType="${columntemp.javaType}" property="${columntemp.columnname}" />
<#else >
<result column="${columntemp.sqlColumn}" jdbcType="${columntemp.javaType}" property="${columntemp.columnname}" />
</#if>
</#list>
</resultMap>
<select id="list" resultMap="ResultMap">
select <#list columnList as columntemp><#if columntemp_has_next>${columntemp.sqlColumn},<#else >${columntemp.sqlColumn}</#if></#list>
from ${tableName}
</select>
<select id="get" resultMap="ResultMap">
select <#list columnList as columntemp><#if columntemp_has_next>${columntemp.sqlColumn},<#else >${columntemp.sqlColumn}</#if></#list>
from ${tableName}
where 1=1
<#list columnList as columntemp>
<#if columntemp.primaryKey == true>
and ${columntemp.sqlColumn}=${"#"}{${columntemp.columnname}}<#break>
<#else >
</#if>
</#list>
</select>
<delete id="delete" >
delete from
where <#list columnList as columntemp><#if columntemp.primaryKey == true>${columntemp.sqlColumn}=${"#"}{${columntemp.columnname}}<#break></#if></#list>
</delete>
<insert id="insert" >
insert into ${tableName}
<#list columnList as columntemp><#if columntemp_has_next>${columntemp.sqlColumn},<#else >${columntemp.sqlColumn}</#if></#list>
values
(<#list columnList as columntemp><#if columntemp_has_next>${"#"}{${columntemp.columnname}},<#else >${"#"}{${columntemp.columnname}}</#if></#list>)
</insert>
<insert id="insertBatch" >
insert into ${tableName}
<#list columnList as columntemp><#if columntemp_has_next>${columntemp.sqlColumn},<#else >${columntemp.sqlColumn}</#if></#list>
values
<foreach collection="list" separator="," item="item">
(<#list columnList as columntemp><#if columntemp_has_next>${"#"}{item.${columntemp.columnname}},<#else >${"#"}{item.${columntemp.columnname}}</#if></#list>)
</foreach>
</insert>
<update id="update">
update ${tableName}
<set>
<#list columnList as columntemp>
<#if columntemp.primaryKey == false>
<if test="${columntemp.columnname} != null">
columntemp.sqlColumn=${columntemp.sqlColumn},
</if>
</#if>
</#list>
</set>
where <#list columnList as columntemp><#if columntemp.primaryKey == true>${columntemp.sqlColumn}=${"#"}{${columntemp.columnname}}<#break></#if></#list>
</update>
</mapper>
提交表单生成模板
至此工具需要实现的功能已经完成,但是还有很多有待完善的地方,如前端交换和多数据库支持,后续会在github上逐步更新。