1.代码生成器页面
代码生成菜单—— 显示所有数据库表的信息 可点击操作栏——生成按钮——弹出生成配置对话框框——填写配置——生成按钮——生成代码压缩包到本地下载后即可放入对应项目
2.代码生成菜单—— 显示所有数据库表的信息
调用后台接口/generator/page?current=1&size=20,实则为执行sql返回该数据库里数据表名称不为空且取出空白字符后不为‘’的所有数据库表的表名、存储引擎、表注释、数据表的创建时间并根据时间排序,返回给前端后显示在页面
IPage>> queryList(Page page, @Param("tableName") String tableName)
select table_name tableName, engine, table_comment tableComment, create_time createTime
from information_schema.tables
where table_schema = (select database())
and table_name like concat('%', #{tableName}, '%')
order by create_time desc
information_schema.tables 存储了数据表的元数据信息,下面对常用的字段进行介绍:
table_schema: 记录数据库名 ;
table_name: 记录数据表名 ;
engine : 存储引擎 ;
table_rows: 关于表的粗略行估计;
data_length : 记录表的大小 (单位字节);
index_length : 记录表的索引的大小
row_format: 可以查看数据表是否压缩 过;
table_comment :数据表的注释
create_time:数据表的创建时间
3.生成代码
调用后台接口/generator/code
填写生成配置接收类:
package com.amiba.crm.common.codegen.entity;
import lombok.Data;
/**
* @author HZI.HUI
* @since 2019/2/1
* 生成配置
*/
@Data
public class GenConfig {
/**
* 包名
*/
private String packageName;
/**
* 作者
*/
private String author;
/**
* 模块名称
*/
private String moduleName;
/**
* 表前缀
*/
private String tablePrefix;
/**
* 表名称
*/
private String tableName;
/**
* 表备注
*/
private String comments;
}
package com.amiba.crm.admin.controller;
import cn.hutool.core.io.IoUtil;
import com.amiba.crm.common.codegen.entity.GenConfig;
import com.amiba.crm.common.util.R;
import com.amiba.crm.service.SysGeneratorService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 代码生成操作层
*/
@RestController
@AllArgsConstructor
@RequestMapping("/generator")
public class SysGeneratorController {
private final SysGeneratorService sysGeneratorService;
/**
* 列表
*
* @param tableName 参数集
* @return 数据库表
*/
@GetMapping("/page")
public R list(Page page, String tableName) {
return new R<>(sysGeneratorService.queryPage(page,tableName));
}
/**
* 生成代码
*/
@PostMapping("/code")
public void code(@RequestBody GenConfig genConfig, HttpServletResponse response) throws IOException {
byte[] data = sysGeneratorService.generatorCode(genConfig);
response.reset();
response.setHeader("Content-Disposition", String.format("attachment; filename=%s.zip", genConfig.getTableName()));
response.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream; charset=UTF-8");
IoUtil.write(response.getOutputStream(), Boolean.TRUE, data);
}
}
实则调用
/**
* 生成代码
*
* @param genConfig 生成配置
* @return
*/
@Override
public byte[] generatorCode(GenConfig genConfig) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
//查询表信息 得到该表的 tableName, engine, tableComment, create_time
Map table = queryTable(genConfig.getTableName());
//查询列信息columnName, dataType, columnComment, columnKey, extra
List> columns = queryColumns(genConfig.getTableName());
//生成代码
GenUtils.generatorCode(genConfig, table, columns, zip);
IoUtil.close(zip);
return outputStream.toByteArray();
}
生成代码方法:
/**
* 生成代码
* 参数genConfig为用户在生成配置中填写的配置信息
* 参数table 该数据表的信息
* 参数columns 该数据表的列信息
* 参数zip 压缩文件输出流
*/
public static void generatorCode(GenConfig genConfig, Map table,
List> columns, ZipOutputStream zip) {
//获取本地配置文件信息
Configuration config = getConfig();
boolean hasBigDecimal = false;
//表的名称
TableEntity tableEntity = new TableEntity();
tableEntity.setTableName(table.get("tableName"));
//表注释
if (StrUtil.isNotBlank(genConfig.getComments())) {
tableEntity.setComments(genConfig.getComments());
} else {
tableEntity.setComments(table.get("tableComment"));
}
//得到需要删除的表前缀
String tablePrefix;
if (StrUtil.isNotBlank(genConfig.getTablePrefix())) {
tablePrefix = genConfig.getTablePrefix();
} else {
tablePrefix = config.getString("tablePrefix");
}
//表名转换成Java类名
String className = tableToJava(tableEntity.getTableName(), tablePrefix);
tableEntity.setCaseClassName(className);
tableEntity.setLowerClassName(StringUtils.uncapitalize(className));
//列信息
List columnList = new ArrayList<>();
for (Map 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.setCaseAttrName(attrName);
columnEntity.setLowerAttrName(StringUtils.uncapitalize(attrName));
//列的数据类型,转换成Java类型
String attrType = config.getString(columnEntity.getDataType(), "unknowType");
columnEntity.setAttrType(attrType);
if (!hasBigDecimal && "BigDecimal".equals(attrType)) {
hasBigDecimal = true;
}
//是否主键
if ("PRI".equalsIgnoreCase(column.get("columnKey")) && tableEntity.getPk() == null) {
tableEntity.setPk(columnEntity);
}
columnList.add(columnEntity);
}
tableEntity.setColumns(columnList);
//没主键,则第一个字段为主键
if (tableEntity.getPk() == null) {
tableEntity.setPk(tableEntity.getColumns().get(0));
}
//设置velocity资源加载器
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
//封装模板数据
Map map = new HashMap<>(16);
map.put("tableName", tableEntity.getTableName());
map.put("pk", tableEntity.getPk());
map.put("className", tableEntity.getCaseClassName());
map.put("classname", tableEntity.getLowerClassName());
map.put("pathName", tableEntity.getLowerClassName().toLowerCase());
map.put("columns", tableEntity.getColumns());
map.put("hasBigDecimal", hasBigDecimal);
map.put("date", DateUtil.format(new Date(),"yyyy/MM/dd"));
if (StrUtil.isNotBlank(genConfig.getComments())) {
map.put("comments", genConfig.getComments());
} else {
map.put("comments", tableEntity.getComments());
}
if (StrUtil.isNotBlank(genConfig.getAuthor())) {
map.put("author", genConfig.getAuthor());
} else {
map.put("author", config.getString("author"));
}
if (StrUtil.isNotBlank(genConfig.getModuleName())) {
map.put("moduleName", genConfig.getModuleName());
} else {
map.put("moduleName", config.getString("moduleName"));
}
if (StrUtil.isNotBlank(genConfig.getPackageName())) {
map.put("package", genConfig.getPackageName());
map.put("mainPath", genConfig.getPackageName());
} else {
map.put("package", config.getString("package"));
map.put("mainPath", config.getString("mainPath"));
}
VelocityContext context = new VelocityContext(map);
//获取模板列表
List templates = getTemplates();
for (String template : templates) {
//渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, CharsetUtil.UTF_8);
tpl.merge(context, sw);
try {
//添加到zip
zip.putNextEntry(new ZipEntry(Objects
.requireNonNull(getFileName(template, tableEntity.getCaseClassName() ,tableEntity.getLowerClassName()
, map.get("package").toString(), map.get("moduleName").toString()))));
IoUtil.write(zip, CharsetUtil.UTF_8, false, sw.toString());
IoUtil.close(sw);
zip.closeEntry();
} catch (IOException e) {
throw new CheckedException("渲染模板失败,表名:" + tableEntity.getTableName(), e);
}
}
}