前言
最近工作的时候研究了一下线上生成器的代码,自己仿造着写了一个
1.新建一个数据库,添加两张表
2.建立对应的列,创建合适的约束,写好注释
3.开始搭建工程,我使用的是SpringBoot快速搭建,引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<!--mybatis -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!--druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.28</version>
</dependency>
<!-- common -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 引入模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
4.编写yml文件
server:
port: 8009
spring:
thymeleaf:
mode: LEGACYHTML5
cache: false
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seckill?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: 123456
initialSize: 1
minIdle: 3
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 30000
5.新建一个工具包,里面放模板文件
6.根据自己的喜好去编写,之后生成的类、页面或Mapper配置都是按你编写的来生成的,不过是其中的一些关键值不一样,这就是模板生成器,放一个domain示例
package ${package}.domain;
import java.io.Serializable;
import java.util.Date;
#if(${hasBigDecimal})
import java.math.BigDecimal;
#end
/**
* ${comments}
*
* @author ${author}
* @email ${email}
* @date ${datetime}
*/
public class ${className}DO implements Serializable {
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
//$column.comments
private $column.attrType $column.attrname;
#end
#foreach ($column in $columns)
/**
* 设置:${column.comments}
*/
public void set${column.attrName}($column.attrType $column.attrname) {
this.$column.attrname = $column.attrname;
}
/**
* 获取:${column.comments}
*/
public $column.attrType get${column.attrName}() {
return $column.attrname;
}
#end
}
7.编写之后需要的一些配置信息,generator.properties
#代码生成器,配置信息
#包名
package=com.generator.system
#作者
author=ZNJ
#Email
email=1250622989@qq.com
#自动去除表前缀,默认是 true
autoRemovePre=true
#表前缀(类名不会包含表前缀)
tablePrefix=sys_
#类型转换,配置信息
tinyint=Integer
smallint=Integer
mediumint=Integer
int=Integer
integer=Integer
bigint=Long
float=Float
double=Double
decimal=BigDecimal
bit=Boolean
char=String
varchar=String
tinytext=String
text=String
mediumtext=String
longtext=String
date=Date
datetime=Date
timestamp=Date
8.准备工作完成,开始正式撸代码,编写Controller的代码
@Controller
public class GenerateController {
@Autowired
GeneratorService generatorService;
@RequestMapping("/index")
String welcome() {
return "index";
}
@RequestMapping("/batchCode")
public void batchCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
String[] tableNames = new String[] {"seckill","success_killed"};
byte[] data = generatorService.generatorCode(tableNames);
response.reset();
response.setHeader("Content-Disposition", "attachment; filename=\"bootdo.zip\"");
response.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(data, response.getOutputStream());
}
}
/index:开始访问这个路径,去显示一个页面,然后点击超链接来访问生成代码的方法。
/batchCode:具体的生成代码的方法,注意,我这里为了简单直接写死了需要生成的表名,实际开发中不可。
9.编写Service中的代码
@Service
public class GeneratorServiceImpl implements GeneratorService {
@Autowired
GeneratorMapper generatorMapper;
@Override
public byte[] generatorCode(String[] tableNames) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
for(String tableName : tableNames){
//查询表信息
Map<String, String> table = generatorMapper.get(tableName);
//查询列信息
List<Map<String, String>> columns = generatorMapper.listColumns(tableName);
//生成代码
try {
GenUtils.generatorCode(table, columns, zip);
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
IOUtils.closeQuietly(zip);
return outputStream.toByteArray();
}
}
10.编写Mapper中的代码
@Select("select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables \r\n"
+ " where table_schema = (select database()) and table_name = #{tableName}")
Map<String, String> get(String tableName);
@Select("select column_name columnName, data_type dataType, column_comment columnComment, column_key columnKey, extra from information_schema.columns\r\n"
+ " where table_name = #{tableName} and table_schema = (select database()) order by ordinal_position")
List<Map<String, String>> listColumns(String tableName);
11.util中的方法
具体的生成规则,还是要根据各位的需求去生成,大致的改变即可
public static List<String> getTemplates() {
List<String> templates = new ArrayList<String>();
templates.add("generator/domain.java.vm");
templates.add("generator/Dao.java.vm");
//templates.add("templates/common/generator/Mapper.java.vm");
templates.add("generator/Mapper.xml.vm");
templates.add("generator/Service.java.vm");
templates.add("generator/ServiceImpl.java.vm");
templates.add("generator/Controller.java.vm");
templates.add("generator/list.html.vm");
templates.add("generator/add.html.vm");
templates.add("generator/edit.html.vm");
templates.add("generator/list.js.vm");
templates.add("generator/add.js.vm");
templates.add("generator/edit.js.vm");
//templates.add("templates/common/generator/menu.sql.vm");
return templates;
}
public static String columnToJava(String columnName) {
//WordUtils.capitalizeFully(columnName, new char[]{'_'})
//in_stock_pp ====>In_Stock_Pp instockpp ===>Instockpp
return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
}
/**
* 获取配置信息
*/
public static Configuration getConfig() throws ConfigurationException {
return new PropertiesConfiguration("generator.properties");
}
public static void generatorCode(Map<String, String> table, List<Map<String, String>> columns, ZipOutputStream zip) throws ConfigurationException {
//配置信息
Configuration config = getConfig();
//表信息
TableDO tableDO = new TableDO();
tableDO.setTableName(table.get("tableName"));
tableDO.setComments(table.get("tableComment"));
//这里直接用表名作为java类名,有需要可以进行定制化
String className = columnToJava(tableDO.getTableName());
tableDO.setClassName(className);
//StringUtils.uncapitalize将首字母大写的转为小写
//INstock ==>iNstock
tableDO.setClassname(StringUtils.uncapitalize(className));
//列信息
List<ColumnDO> columsList = new ArrayList<>();
for (Map<String, String> column : columns) {
ColumnDO columnDO = new ColumnDO();
columnDO.setColumnName(column.get("columnName"));
columnDO.setDataType(column.get("dataType"));
columnDO.setComments(column.get("columnComment"));
columnDO.setExtra(column.get("extra"));
//列名转换成Java属性名
String attrName = columnToJava(columnDO.getColumnName());
columnDO.setAttrName(attrName);
columnDO.setAttrname(StringUtils.uncapitalize(attrName));
//列的数据类型,转换成Java类型
String attrType = config.getString(columnDO.getDataType(), "unknowType");
columnDO.setAttrType(attrType);
//是否主键
if ("PRI".equalsIgnoreCase(column.get("columnKey")) && tableDO.getPk() == null) {
tableDO.setPk(columnDO);
}
columsList.add(columnDO);
}
tableDO.setColumns(columsList);
//没主键,则第一个字段为主键
if (tableDO.getPk() == null) {
tableDO.setPk(tableDO.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<String, Object> map = new HashMap<>(16);
map.put("tableName", tableDO.getTableName());
map.put("comments", tableDO.getComments());
map.put("pk", tableDO.getPk());
map.put("className", tableDO.getClassName());
map.put("classname", tableDO.getClassname());
map.put("pathName", config.getString("package").substring(config.getString("package").lastIndexOf(".") + 1));
map.put("columns", tableDO.getColumns());
map.put("package", config.getString("package"));
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);
//获取模板列表
List<String> templates = getTemplates();
for (String template : templates) {
//渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, "UTF-8");
tpl.merge(context, sw);
//添加到zip
try {
zip.putNextEntry(new ZipEntry(getFileName(template, tableDO.getClassname(), tableDO.getClassName(), config.getString("package").substring(config.getString("package").lastIndexOf(".") + 1))));
IOUtils.write(sw.toString(), zip, "UTF-8");
IOUtils.closeQuietly(sw);
zip.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 获取文件名
*/
public static String getFileName(String template, String classname, String className, String packageName) {
String packagePath = "main" + File.separator + "java" + File.separator;
//String modulesname=config.getString("packageName");
if (StringUtils.isNotBlank(packageName)) {
packagePath += packageName.replace(".", File.separator) + File.separator;
}
if (template.contains("domain.java.vm")) {
return packagePath + "domain" + File.separator + className + "DO.java";
}
if (template.contains("Dao.java.vm")) {
return packagePath + "dao" + File.separator + className + "Dao.java";
}
// if(template.contains("Mapper.java.vm")){
// return packagePath + "dao" + File.separator + className + "Mapper.java";
// }
if (template.contains("Service.java.vm")) {
return packagePath + "service" + File.separator + className + "Service.java";
}
if (template.contains("ServiceImpl.java.vm")) {
return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
}
if (template.contains("Controller.java.vm")) {
return packagePath + "controller" + File.separator + className + "Controller.java";
}
if (template.contains("Mapper.xml.vm")) {
return "main" + File.separator + "resources" + File.separator + "mapper" + File.separator + packageName + File.separator + className + "Mapper.xml";
}
if (template.contains("list.html.vm")) {
return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
+ packageName + File.separator + classname + File.separator + classname + ".html";
// + "modules" + File.separator + "generator" + File.separator + className.toLowerCase() + ".html";
}
if (template.contains("add.html.vm")) {
return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
+ packageName + File.separator + classname + File.separator + "add.html";
}
if (template.contains("edit.html.vm")) {
return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
+ packageName + File.separator + classname + File.separator + "edit.html";
}
if (template.contains("list.js.vm")) {
return "main" + File.separator + "resources" + File.separator + "static" + File.separator + "js" + File.separator
+ "appjs" + File.separator + packageName + File.separator + classname + File.separator + classname + ".js";
// + "modules" + File.separator + "generator" + File.separator + className.toLowerCase() + ".js";
}
if (template.contains("add.js.vm")) {
return "main" + File.separator + "resources" + File.separator + "static" + File.separator + "js" + File.separator
+ "appjs" + File.separator + packageName + File.separator + classname + File.separator + "add.js";
}
if (template.contains("edit.js.vm")) {
return "main" + File.separator + "resources" + File.separator + "static" + File.separator + "js" + File.separator
+ "appjs" + File.separator + packageName + File.separator + classname + File.separator + "edit.js";
}
// if(template.contains("menu.sql.vm")){
// return className.toLowerCase() + "_menu.sql";
// }
return null;
}
12.启动类和欢迎页面
@ServletComponentScan
@MapperScan("com.jinyi.generatecode.dao")
@SpringBootApplication
public class GeneratecodeApplication {
public static void main(String[] args) {
SpringApplication.run(GeneratecodeApplication.class, args);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/batchCode">生成</a>
</body>
</html>
12.启动后,点击生成,会压缩一个文件包,里面就有我们需要的文件
生成的domain代码,以上代码仅供参考
package com.generator.system.domain;
import java.io.Serializable;
import java.util.Date;
/**
* 秒杀库存表
*
* @author ZNJ
* @email 1250622989@qq.com
* @date 2019-06-14 18:21:15
*/
public class SeckillDO implements Serializable {
private static final long serialVersionUID = 1L;
//商品库存ID
private Long seckillId;
//商品名称
private String name;
//库存数量
private Integer number;
//秒杀开始时间
private Date startTime;
//秒杀结束时间
private Date endTime;
//创建时间
private Date createTime;
/**
* 设置:商品库存ID
*/
public void setSeckillId(Long seckillId) {
this.seckillId = seckillId;
}
/**
* 获取:商品库存ID
*/
public Long getSeckillId() {
return seckillId;
}
/**
* 设置:商品名称
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取:商品名称
*/
public String getName() {
return name;
}
/**
* 设置:库存数量
*/
public void setNumber(Integer number) {
this.number = number;
}
/**
* 获取:库存数量
*/
public Integer getNumber() {
return number;
}
/**
* 设置:秒杀开始时间
*/
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
/**
* 获取:秒杀开始时间
*/
public Date getStartTime() {
return startTime;
}
/**
* 设置:秒杀结束时间
*/
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
/**
* 获取:秒杀结束时间
*/
public Date getEndTime() {
return endTime;
}
/**
* 设置:创建时间
*/
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
/**
* 获取:创建时间
*/
public Date getCreateTime() {
return createTime;
}
}