1.逆向工程获取数据库元对象
目前的代码生成器是通过逆向工程获取指定Schema的表信息,包括表的注释,表中字段信息,字段注释。(为了后面适配Oracle数据库,DM数据库等,应该封装接口,因为时间关系只实现了Mysql数据库。)
package com.cll.jtool.template.mapper;
import com.cll.jtool.template.bean.domain.Column;
import com.cll.jtool.template.bean.domain.Schema;
import com.cll.jtool.template.bean.domain.Table;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface MysqlObjectMapper {
/**
* 查询表名,表注释
* @param schema
* @param table
* @return
*/
List<Table> selectTables(@Param("schema") String schema, @Param("table") String table);
/**
* 获取指定表的列 元信息
* @param schema
* @param table
* @return
*/
List<Column> selectColumns(@Param("schema") String schema, @Param("table") String table);
/**
* 获取指定表
* @param schema
* @param table
* @return
*/
Table selectTable(@Param("schema") String schema, @Param("table") String table);
}
2.数据类型处理
需要将Mysql数据库的数据类型映射成Java数据库的数据类型,这里通过Regex简单实现了常用的数据类型。
package com.cll.jtool.template.mapping;
import com.cll.jtool.template.bean.domain.Column;
import com.cll.jtool.template.bean.domain.Table;
import java.util.Locale;
public class MysqlColumnMapping {
public static final String integerRegex = "TINYINT|SMALLINT|MEDIUMINT|INT";
public static final String stringRegex = "CHAR|VARCHAR|TEXT|MEDIUMTEXT|LONGTEXT";
public static final String timeRegex = "DATE|TIME|DATETIME|TIMESTAMP";
public static final String longRegex = "BIGINT";
public static void mapping(Table table) {
for (Column field : table.getFields()) {
String dataType = field.getDataType().toUpperCase(Locale.ROOT);
if (dataType.matches(stringRegex)) {
field.setJavaDataType("String");
} else if (dataType.matches(longRegex)) {
field.setJavaDataType("Long");
} else if (dataType.matches(integerRegex)) {
field.setJavaDataType("Integer");
} else if (dataType.matches(timeRegex)) {
field.setJavaDataType("Date");
}
}
}
}
3.准备给Bean填充数据
以Contoller文件为例,每个Controller需要继承父类,父类包含这些需要生成的文件的共有属性。
package com.cll.jtool.template.bean.domain.base;
import lombok.Data;
@Data
public class FileMeta {
/**
* 名称
*/
private String name;
/**
* 绝对路径
*/
private String absolutePath;
/**
* 大驼峰命名风格
*/
private String upperCamelStyleName;
/**
* 小驼峰命名风格
*/
private String lowerCamelStyleName;
}
4.准备Velocity模板文件
模板文件借鉴了MybatisPlus的VM文件,改成了自己的代码风格。
package ${package.Controller};
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import com.cll.jtool.common.bean.Result;
import com.cll.jtool.service.${service.name};
/**
* $!{table.comment} 接口
*
* @author ${author}
* @since ${date}
*/
@RestController
@RequestMapping("/${name.lowerCamelStyleName}")
@Api(value="${table.comment}")
public class ${controller.name} {
@Autowired
private ${service.name} ${service.lowerCamelStyleName};
@ApiOperation(value = "${description.ADD}")
@PostMapping("/add")
public Result ${method.ADD}(){
return Result.success();
}
@ApiOperation(value = "${description.DELETE}")
@PostMapping("/delete")
public Result ${method.DELETE}(Long id){
return Result.success();
}
@ApiOperation(value = "${description.GET}")
@PostMapping("/get")
public Result ${method.GET}(Long id){
return Result.success();
}
@ApiOperation(value = "${description.EDIT}")
@PostMapping("/edit")
public Result ${method.EDIT}(){
return Result.success();
}
@ApiOperation(value = "${description.QUERY}")
@PostMapping("/query")
public Result ${method.QUERY}(){
return Result.success();
}
@ApiOperation(value = "${description.EXPORT}")
@PostMapping("/export")
public Result ${method.EXPORT}(){
return Result.success();
}
@ApiOperation(value = "${description.IMPORT}")
@PostMapping("/import")
public Result ${method.IMPORT}(){
return Result.success();
}
}
5.生成代码
最后通过生成器就可以将代码生成到指定的目录了,下面是生成的代码。(为了鼠标垫,不管这么多了)
package com.cll.jtool.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import com.cll.jtool.common.bean.Result;
import com.cll.jtool.service.SUserService;
/**
* 接口
*
* @author ${author}
* @since ${date}
*/
@RestController
@RequestMapping("/sUser")
@Api(value="${table.comment}")
public class SUserController {
@Autowired
private SUserService sUserService;
@ApiOperation(value = "新增")
@PostMapping("/add")
public Result addItem(){
return Result.success();
}
@ApiOperation(value = "根据ID删除")
@PostMapping("/delete")
public Result deleteItem(Long id){
return Result.success();
}
@ApiOperation(value = "根据ID获取详情")
@PostMapping("/get")
public Result getItem(Long id){
return Result.success();
}
@ApiOperation(value = "根据ID编辑")
@PostMapping("/edit")
public Result editItem(){
return Result.success();
}
@ApiOperation(value = "条件分页查询")
@PostMapping("/query")
public Result queryItems(){
return Result.success();
}
@ApiOperation(value = "条件Excel导出")
@PostMapping("/export")
public Result exportItem(){
return Result.success();
}
@ApiOperation(value = "Excel数据导入")
@PostMapping("/import")
public Result importItem(){
return Result.success();
}
}
生成代码
package com.cll.jtool.template.generator;
import com.cll.jtool.common.util.NamingUtil;
import com.cll.jtool.template.bean.domain.*;
import com.cll.jtool.template.bean.domain.Package;
import com.cll.jtool.template.mapper.MysqlObjectMapper;
import com.cll.jtool.template.mapping.MysqlColumnMapping;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.FieldMethodizer;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.List;
import java.util.Properties;
@Component
public class Generator {
@Autowired
private MysqlObjectMapper mysqlObjectMapper;
public void generate() throws IOException {
//从数据库读取对象元信息
Table table = mysqlObjectMapper.selectTable("jtool", "s_user");
List<Column> columns = mysqlObjectMapper.selectColumns("jtool", "s_user");
table.setFields(columns);
MysqlColumnMapping.mapping(table);
//设置基本数据
Package pa = new Package();
pa.setEntity("com.cll.jtool.bean.domain");
pa.setMapper("com.cll.jtool.mapper");
pa.setService("com.cll.jtool.service");
pa.setServiceImpl("com.cll.jtool.service.impl");
pa.setController("com.cll.jtool.controller");
Name name = new Name();
name.setUpperCamelStyleName(NamingUtil.getUpperCamelCase(table.getTableName()));
name.setLowerCamelStyleName(NamingUtil.getLowerCamelCase(table.getTableName()));
Entity entity = new Entity();
entity.setName(name.getUpperCamelStyleName());
entity.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\bean\\" + entity.getName() + ".java");
Controller controller = new Controller();
controller.setName(name.getUpperCamelStyleName()+"Controller");
controller.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\controller\\" + controller.getName() + ".java");
Mapper mapper = new Mapper();
mapper.setName(name.getUpperCamelStyleName()+"Mapper");
mapper.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\mapper\\" + mapper.getName() + ".java");
Service service = new Service();
service.setName(name.getUpperCamelStyleName()+"Service");
service.setLowerCamelStyleName(name.getLowerCamelStyleName()+"Service");
service.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\service\\" + service.getName() + ".java");
ServiceImpl serviceImpl = new ServiceImpl();
serviceImpl.setName(name.getUpperCamelStyleName()+"ServiceImpl");
serviceImpl.setLowerCamelStyleName(name.getLowerCamelStyleName()+"ServiceImpl");
serviceImpl.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\service\\impl\\" + serviceImpl.getName() + ".java");
//填充上下文数据
Properties properties = new Properties();
properties.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(properties);
VelocityContext context = new VelocityContext();
//公共属性
context.put("package", pa);
//表相关属性
context.put("table", table);
context.put("entity", entity);
context.put("mapper", mapper);
context.put("service", service);
context.put("serviceImpl", serviceImpl);
context.put("controller", controller);
context.put("name", name);
context.put("description",new FieldMethodizer( "com.cll.jtool.template.bean.domain.Description"));
context.put("method",new FieldMethodizer( "com.cll.jtool.template.bean.domain.Method"));
//加载模板
Template template = Velocity.getTemplate("/template/entity.java.vm", "utf-8");
Template template2 = Velocity.getTemplate("/template/controller.java.vm", "utf-8");
Template template3 = Velocity.getTemplate("/template/service.java.vm", "utf-8");
Template template4 = Velocity.getTemplate("/template/serviceImpl.java.vm", "utf-8");
Template template5 = Velocity.getTemplate("/template/mapper.java.vm", "utf-8");
FileWriter fileWriter = new FileWriter(entity.getAbsolutePath());
FileWriter fileWriter2 = new FileWriter(controller.getAbsolutePath());
FileWriter fileWriter3 = new FileWriter(service.getAbsolutePath());
FileWriter fileWriter4 = new FileWriter(serviceImpl.getAbsolutePath());
FileWriter fileWriter5 = new FileWriter(mapper.getAbsolutePath());
//渲染模板
template.merge(context, fileWriter);
template2.merge(context, fileWriter2);
template3.merge(context, fileWriter3);
template4.merge(context, fileWriter4);
template5.merge(context, fileWriter5);
fileWriter.close();
fileWriter2.close();
fileWriter3.close();
fileWriter4.close();
fileWriter5.close();
}
}
6.总结
后面希望能在此基础上完成各种文件的生成,最好能做成可视化的形式,避免在代码里反复配置。最好能实现一键删除功能,删除生成的代码文件。总之有些吃力不讨好,哈哈,感觉需要做的太多了。