Spring Boot 集成代码生成工具
- 基于第三方代码生成器 renren-generator
- renren-generator是人人开源项目的代码生成器,基于此项目修改代码模板,
修改代码生成程序,使生成代码直接在项目中相应位置创建,可批量生成基于数据库表的基础代码,高效。
拉取renren-generator项目源码
在项目中创建子项目 generator
复制源码
- 将renren-generator项目中源码,复制进子项目generator。
编辑代码生成模板
- 路径 main\ resources\template 新建模板文件
- 参考模板内容如下
- M-DO.java.vm
package ${package}.${moduleName}.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
#if(${hasBigDecimal})
import java.math.BigDecimal;
#end
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* ${comments}
*
* @author ${author}
* @date ${datetime}
*/
@ApiModel(value = "${comments}DO")
@Data
@TableName("${tableName}")
public class ${className}DO implements Serializable {
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
@ApiModelProperty(value = "$column.comments")
#if($column.columnName == $pk.columnName)
@TableId
#end
#if($column.attrType == 'Date')
#if($column.dataType == 'date')
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd")
@DateTimeFormat(pattern="yyyy-MM-dd")
#elseif($column.dataType == 'time')
@JsonFormat(locale="zh", timezone="GMT+8", pattern="HH:mm:ss")
@DateTimeFormat(pattern="HH:mm:ss")
#else
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
#end
#end
#if($column.attrname == 'updateBy' || $column.attrname == 'updateTime')
@TableField(fill = FieldFill.UPDATE)
#end
#if($column.attrname == 'createBy' || $column.attrname == 'createTime')
@TableField(fill = FieldFill.INSERT)
#end
private $column.attrType $column.attrname;
#end
}
- M-Dao.java.vm
package ${package}.${moduleName}.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import ${package}.${moduleName}.domain.${className}DO;
/**
* ${comments}
*
* @author ${author}
* @date ${datetime}
*/
@Mapper
public interface ${className}Dao extends BaseMapper<${className}DO> {
}
- M-Mapper.xml.vm
<?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="${package}.${moduleName}.dao.${className}Dao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="${package}.${moduleName}.domain.${className}DO" id="${classname}Map">
#foreach($column in $columns)
<result property="${column.attrname}" column="${column.columnName}"/>
#end
</resultMap>
</mapper>
- M-Service.java.vm
package ${package}.${moduleName}.service;
import com.baomidou.mybatisplus.extension.service.IService;
import ${package}.${moduleName}.domain.${className}DO;
/**
* ${comments}
*
* @author ${author}
* @date ${datetime}
*/
public interface ${className}Service extends IService<${className}DO> {
}
- M-ServiceImpl.java.vm
package ${package}.${moduleName}.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${package}.${moduleName}.dao.${className}Dao;
import ${package}.${moduleName}.domain.${className}DO;
import ${package}.${moduleName}.service.${className}Service;
import org.springframework.stereotype.Service;
/**
* ${comments}
*
* @author ${author}
* @date ${datetime}
*/
@Service("${classname}Service")
public class ${className}ServiceImpl extends ServiceImpl<${className}Dao, ${className}DO> implements ${className}Service {
}
- M-Controller.java.vm
package org.mur.system.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import ${mainPath}.common.core.BaseController;
import ${mainPath}.common.core.Convert;
import ${mainPath}.common.utils.Result;
import ${package}.${moduleName}.domain.${className}DO;
import ${package}.${moduleName}.service.${className}Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* ${comments}
*
* @author ${author}
* @date ${datetime}
*/
@Api(tags = "${comments}")
@RestController
@RequestMapping("${moduleName}/${pathName}")
public class ${className}Controller {
@Autowired
private ${className}Service ${classname}Service;
@ApiOperation("列表")
@GetMapping("/list")
//@RequiresPermissions("${moduleName}:${pathName}:list")
public Result<List<${className}DO>> getList(@ModelAttribute ${className}DO ${classname}DO ) {
QueryWrapper<${className}DO> qw = new QueryWrapper<${className}DO>().setEntity(${classname}DO);
return Result.ok(${classname}Service.list(qw));
}
@ApiOperation("信息")
@GetMapping("/info/{${pk.attrname}}")
//@RequiresPermissions("${moduleName}:${pathName}:info")
@ApiImplicitParam(name = "${pk.attrname}", value = "主键${pk.attrname}", dataTypeClass = ${pk.attrType}.class)
public Result<${className}DO> getInfo(@PathVariable("${pk.attrname}") ${pk.attrType} ${pk.attrname}) {
return Result.ok(${classname}Service.getById(${pk.attrname}));
}
/**
* 保存
*/
@ApiOperation("保存")
@PostMapping("/save")
//@RequiresPermissions("${moduleName}:${pathName}:save")
public Result save(@RequestBody ${className}DO ${classname}DO){
boolean save = ${classname}Service.save(${classname}DO);
return Result.status(save);
}
/**
* 修改
*/
@ApiOperation("修改")
@PostMapping("/update")
//@RequiresPermissions("${moduleName}:${pathName}:update")
public Result update(@RequestBody ${className}DO ${classname}DO) {
boolean update = ${classname}Service.updateById(${classname}DO);
return Result.status(update);
}
/**
* 删除
*/
@ApiOperation("删除")
@PostMapping("/delete")
//@RequiresPermissions("${moduleName}:${pathName}:delete")
@ApiImplicitParam(name = "ids", value = "主键ids(逗号隔开)", dataType = "string")
public Result delete(String ids) {
List<Long> idList = Convert.toLongList(ids);
boolean delete = ${classname}Service.removeByIds(idList);
return Result.status(delete);
}
}
修改代码生成程序
- SysGeneratorController中添加
/** 生成代码ServiceCode */
@ResponseBody
@RequestMapping("/serviceCode")
public R serviceCode(String tables, String moduleProject) throws IOException{
byte[] data = sysGeneratorService.generatorCodeToProject(tables.split(","),1);
return R.ok("代码已生成!");
}
/** 生成代码ServiceCode */
@ResponseBody
@RequestMapping("/controllerCode")
public R controllerCode(String tables,String moduleProject) throws IOException{
byte[] data = sysGeneratorService.generatorCodeToProject(tables.split(","),2);
return R.ok("代码已生成!");
}
- SysGeneratorService中添加
public byte[] generatorCodeToProject(String[] tableNames, int type) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
for (String tableName : tableNames) {
//查询表信息
Map<String, String> table = queryTable(tableName);
//查询列信息
List<Map<String, String>> columns = queryColumns(tableName);
//生成代码
GenUtils.generatorCodeToProject(table, columns, type);
}
return outputStream.toByteArray();
}
- GenUtils中添加
/**
* 获取模板列表
* @param type 1:DO, Dao, mapper,Service,ServiceImpl 2:Controller
* @return
*/
public static List<String> getTemplates(int type) {
List<String> templates = new ArrayList<String>();
if(type == 1){
// DO, Dao, mapper,Service,ServiceImpl
templates.add("template/M-DO.java.vm");
templates.add("template/M-Dao.java.vm");
templates.add("template/M-Mapper.xml.vm");
templates.add("template/M-Service.java.vm");
templates.add("template/M-ServiceImpl.java.vm");
}else if(type == 2){
// Controller
templates.add("template/M-Controller.java.vm");
}
return templates;
}
/**
* 生成代码
*/
public static void generatorCodeToProject(Map<String, String> table, List<Map<String, String>> columns, int type) {
//配置信息
Configuration config = getConfig();
// boolean hasBigDecimal = false;
// boolean hasList = false;
//表信息
TableEntity tableEntity = getTableEntity(table, columns);
//设置velocity资源加载器
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
String mainPath = config.getString("mainPath");
mainPath = StringUtils.isBlank(mainPath) ? "org.mur" : mainPath;
//封装模板数据
VelocityContext context = getVelocityContext(tableEntity);
//获取模板列表
List<String> templates = getTemplates(type) ;
for (String template : templates) {
//渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, "UTF-8");
tpl.merge(context, sw);
try {
//获取当前项目的根路径
File directory = new File("");// 参数为空
String courseFile = directory.getCanonicalPath();
String project = config.getString("moduleProject");
if (StringUtils.isNotEmpty(project)) {
int i = StringUtils.lastIndexOf(courseFile, "\\");
courseFile += "\\" + project;
}
String entityFileName = getFileNameM(template, tableEntity.getClassName(), config.getString("package"), config.getString("moduleName"));
FileUtil.writeString(sw.toString(),FileUtil.touch(courseFile+"\\src\\"+entityFileName), "UTF-8");
} catch (IOException e){
throw new RRException("渲染模板失败,表名:" + tableEntity.getTableName(), e);
}
}
}
/**
* 获取表信息
* @param table
* @param columns
* @return
*/
public static TableEntity getTableEntity(Map<String, String> table, List<Map<String, String>> columns){
//配置信息
Configuration config = getConfig();
boolean hasBigDecimal = false;
boolean hasList = false;
//表信息
TableEntity tableEntity = new TableEntity();
tableEntity.setTableName(table.get("tableName"));
tableEntity.setComments(table.get("tableComment"));
//表名转换成Java类名
String className = tableToJava(tableEntity.getTableName(), config.getStringArray("tablePrefix"));
tableEntity.setClassName(className);
tableEntity.setClassname(StringUtils.uncapitalize(className));
//列信息
List<ColumnEntity> columsList = new ArrayList<>();
for (Map<String, String> column : columns) {
ColumnEntity columnEntity = new ColumnEntity();
columnEntity.setColumnName(column.get("columnName"));
columnEntity.setDataType(column.get("dataType"));
columnEntity.setComments(column.get("columnComment"));
columnEntity.setExtra(column.get("extra"));
//列名转换成Java属性名
String attrName = columnToJava(columnEntity.getColumnName());
columnEntity.setAttrName(attrName);
columnEntity.setAttrname(StringUtils.uncapitalize(attrName));
//列的数据类型,转换成Java类型
String attrType = config.getString(columnEntity.getDataType(), columnToJava(columnEntity.getDataType()));
columnEntity.setAttrType(attrType);
if (!hasBigDecimal && attrType.equals("BigDecimal")) {
hasBigDecimal = true;
}
if (!hasList && "array".equals(columnEntity.getExtra())) {
hasList = true;
}
//是否主键
if ("PRI".equalsIgnoreCase(column.get("columnKey")) && tableEntity.getPk() == null) {
tableEntity.setPk(columnEntity);
}
columsList.add(columnEntity);
}
tableEntity.setColumns(columsList);
//没主键,则第一个字段为主键
if (tableEntity.getPk() == null) {
tableEntity.setPk(tableEntity.getColumns().get(0));
}
return tableEntity;
}
public static VelocityContext getVelocityContext(TableEntity tableEntity){
//配置信息
Configuration config = getConfig();
boolean hasBigDecimal = false;
boolean hasList = false;
String mainPath = config.getString("mainPath");
//封装模板数据
Map<String, Object> map = new HashMap<>();
map.put("tableName", tableEntity.getTableName());
map.put("comments", tableEntity.getComments());
map.put("pk", tableEntity.getPk());
map.put("className", tableEntity.getClassName());
map.put("classname", tableEntity.getClassname());
map.put("pathName", tableEntity.getClassname().toLowerCase());
map.put("columns", tableEntity.getColumns());
map.put("hasBigDecimal", hasBigDecimal);
map.put("hasList", hasList);
map.put("mainPath", mainPath);
map.put("package", config.getString("package"));
map.put("moduleName", config.getString("moduleName"));
map.put("author", config.getString("author"));
map.put("email", config.getString("email"));
map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
VelocityContext context = new VelocityContext(map);
return context;
}
/**
* 获取文件名
*/
public static String getFileNameM(String template, String className, String packageName, String moduleName) {
String packagePath = "main" + File.separator + "java" + File.separator;
if (StringUtils.isNotBlank(packageName)) {
packagePath += packageName.replace(".", File.separator) + File.separator + moduleName + File.separator;
}
if (template.contains("M-DO.java.vm")) {
return packagePath + "domain" + File.separator + className + "DO.java";
}
if (template.contains("M-Dao.java.vm")) {
return packagePath + "dao" + File.separator + className + "Dao.java";
}
if (template.contains("M-Service.java.vm")) {
return packagePath + "service" + File.separator + className + "Service.java";
}
if (template.contains("M-ServiceImpl.java.vm")) {
return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
}
if (template.contains("M-Controller.java.vm")) {
return packagePath + "controller" + File.separator + className + "Controller.java";
}
if (template.contains("M-Mapper.xml.vm")) {
return "main" + File.separator + "resources" + File.separator + "mapper" + File.separator + moduleName + File.separator + className + "Mapper.xml";
}
return null;
}
修改配置信息
- 修改generator.properties中配置信息
#\u4EE3\u7801\u751F\u6210\u5668\uFF0C\u914D\u7F6E\u4FE1\u606F
#主路径
mainPath=org.mur
#\u5305\u540D
#包名
package=org.mur
#模块名
moduleName=system
#子项目名
moduleProject = admin
#\u4F5C\u8005
author=Mur
#Email
#email=sunlightcs@gmail.com
#\u8868\u524D\u7F00(\u7C7B\u540D\u4E0D\u4F1A\u5305\u542B\u8868\u524D\u7F00)
tablePrefix=
修改连接数据库信息
- 修改application.yml文件
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: username
password: password
生成代码
-
启动项目,访问页面 http://localhost:80
-
勾选需要生成代码的数据表,点击代码生成按钮