一、引言
在项目开发中,我们有碰到大量的简单、重复的增删改查需求,通过阅读若依框架https://github.com/yangzongzhuan/RuoYi 的代码生成器实现,结合我项目所用的技术栈,开发出本项目的代码生成器。
二、Velocity 简单介绍
1、Velocity是一个基于Java的模板引擎,我们可以往Context容器中填值,在vm文件中使用模板语言(Velocity Template Language)获取变量的值,生成一套通用的模板代码。
2、引入依赖:
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>2.0</version>
</dependency>
3、语法示例:
获取Context中的ClassName值:${ClassName}
判断:#if($table.crud || $table.sub)
遍历:#foreach ($column in $columns)
结束:#end
/**
* ${functionName}对象 ${tableName}
*
* @author ${author}
* @date ${datetime}
*/
#if($table.crud || $table.sub)
#set($Entity="BaseEntity")
#elseif($table.tree)
#set($Entity="TreeEntity")
#end
@Data
public class ${ClassName} extends BasicEntity
{
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField))
/** $column.columnComment */
#if($column.list)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($parentheseIndex != -1)
@Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
#elseif($column.javaType == 'Date')
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
#else
@Excel(name = "${comment}")
#end
#end
private $column.javaType $column.javaField;
#end
#end
#if($table.sub)
/** $table.subTable.functionName信息 */
private List<${subClassName}> ${subclassName}List;
#end
}
三、若依代码生成器核心源码阅读
前置:根据业务代码和模板语言编写代码模板
1、获取数据库表列表,查询 information_schema.tables 表
select table_name, table_comment, create_time, update_time
from information_schema.tables
where table_schema = (select database())
2、初始化表结构信息,填充代码生成器基本信息,插入到 gen_table表
public static void initTable(GenTable genTable, String operName)
{
genTable.setClassName(convertClassName(genTable.getTableName()));
genTable.setPackageName(GenConfig.getPackageName());
genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
genTable.setBusinessName(getBusinessName(genTable.getTableName()));
genTable.setFunctionName(replaceText(genTable.getTableComment()));
genTable.setFunctionAuthor(GenConfig.getAuthor());
genTable.setCreateBy(operName);
}
3、初始化表的列信息:查询 information_schema.`COLUMNS`表,插入到 gen_table_column表
select table_name, column_name, column_type, data_type, column_comment, column_key
from information_schema.`COLUMNS`
where table_schema = 'smart_ca' and table_name = '表名'
4、初始化vm,加载模板
public static void initVelocity()
{
Properties p = new Properties();
try {
// 加载classpath目录下的vm文件
p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
// 定义字符集
p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
// 初始化Velocity引擎,指定配置Properties
Velocity.init(p);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
5、给容器Context中设置模板变量(重要),例:
VelocityContext velocityContext = new VelocityContext();
velocityContext.put("tplCategory", genTable.getTplCategory());
velocityContext.put("tableName", genTable.getTableName());
velocityContext.put("ClassName", genTable.getClassName());
velocityContext.put("moduleName", genTable.getModuleName());
6、设置模板
List<String> templates = new ArrayList<String>();
templates.add("vm/java/domain.java.vm");
templates.add("vm/java/mapper.java.vm");
templates.add("vm/java/service.java.vm");
templates.add("vm/java/serviceImpl.java.vm");
templates.add("vm/java/controller.java.vm");
7、渲染模板,生成至指定位置
// 渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
tpl.merge(context, sw);
String path = getGenPath(table, template);
FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
四、结合项目业务开发代码生成器
1、梳理项目通用代码(重要)
和团队成员一同梳理出通用的代码,我们是要一键生成前后端代码,直接实现增删改查。模板代码必须是经过前后端同学一起验证,避免反复修改。
2、结合自己的业务,定义所有需要的变量,并且使用velocity模板语法,使用变量替换代码。
3、编写操作后台,将模板中需要用到的变量,存储到gen_table,gen_table_column表,以便整个流程使用。
4、开发者点击代码生成时,查询gen_table, gen_table_column表中的数据,设置模板变量到容器Context中,这边要注意把之前自定义的变量全部 put
5、设置代码生成路径,我们的代码默认生成在项目根路径的 generator目录。