mybatis-plus使用Velocity格式模板生成代码
第一步 引入所需pom文件
<!--数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 代码生成器依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.1.0</version>
</dependency>
<!--druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--模版 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
第二步 配置application.yml
server:
port: 8089
#默认使用配置
spring:
profiles:
active: dev
#公共配置与profiles选择无关 mapperLocations指的路径是src/main/resources
#公共配置与profiles选择无关
mybatis-plus:
typeAliasesPackage: com.example.demo
mapperLocations: classpath:mapper/*.xml
---
#开发配置
spring:
profiles: dev
datasource:
url: jdbc:mysql://ip:port/beadwalletloan?autoReconnect=true&useUnicode=true&zeroDateTimeBehavior=convertToNull&useServerPrepStmts=false&rewriteBatchedStatements=true&serverTimezone=GMT%2B8
username: username
password: password
driverClassName: com.mysql.jdbc.Driver
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
# 配置获取连接等待超时的时间
# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
initialSize: 1
minIdle: 3
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 30000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,slf4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
useGlobalDataSourceStat: true
第三步 配置数据源
DatasourceConfig.java
package com.example.demo.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import lombok.extern.log4j.Log4j2;
@Log4j2
@Configuration
public class DatasourceConfig {
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driverClassName}")
private String driverClassName;
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.minIdle}")
private int minIdle;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.maxWait}")
private int maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters}")
private String filters;
@Value("${spring.datasource.connectionProperties}")
private String connectionProperties;
@Value("${spring.datasource.useGlobalDataSourceStat}")
private boolean useGlobalDataSourceStat;
@Bean
@Primary
public DataSource dataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
datasource.setPassword(password); //这里可以做加密处理
datasource.setDriverClassName(driverClassName);
//configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
@Bean
public ServletRegistrationBean druidServlet() {
log.info("init Druid Servlet Configuration ");
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// IP白名单
// servletRegistrationBean.addInitParameter("allow", "192.168.2.25,127.0.0.1");
// IP黑名单(共同存在时,deny优先于allow)
//servletRegistrationBean.addInitParameter("deny", "192.168.1.100");
//控制台管理用户
servletRegistrationBean.addInitParameter("loginUsername", "admin");
servletRegistrationBean.addInitParameter("loginPassword", "9527");
//是否能够重置数据 禁用HTML页面上的“Reset All”功能
servletRegistrationBean.addInitParameter("resetEnable", "false");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
第四步 配置模板
实体类模板
Entity.java.vm
package ${package}.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
#foreach ($column in $columns)
#if($column.attrType == 'LocalDate')
import java.time.LocalDate;
#break
#end
#end
#foreach ($column in $columns)
#if($column.attrType == 'LocalDateTime')
import java.time.LocalDateTime;
import com.alibaba.fastjson.annotation.JSONField;
#break
#end
#end
import lombok.Data;
/**
* Module: ${className}.java
*
* @author ${author}
* @since JDK ${jdk}
* @version ${version}
* @date ${date}
* @Descriptions:
*/
@Data
@TableName(value = "${tableName}")
public class ${className} {
#foreach ($column in $columns)
/** $column.comments */
#if ("id" == $column.attrname)
@TableId(value = "id", type = IdType.AUTO)
#end
#if ("createTime" == $column.attrname)
@TableField(fill = FieldFill.INSERT)
#end
#if ("updateTime" == $column.attrname)
@TableField(fill = FieldFill.INSERT_UPDATE)
#end
#if ("date" == $column.dataType)
@JSONField(format = "yyyy-MM-dd")
#end
#if ("datetime" == $column.dataType)
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
#end
private $column.attrType $column.attrname;
#end
}
配置service
Service.java.vm
package ${package}.service;
import ${package}.entity.${className};
import com.baomidou.mybatisplus.extension.service.IService;
/**
* Module: ${className}.java
*
* @author ${author}
* @since JDK ${jdk}
* @version ${version}
* @date ${date}
* @Descriptions:
*/
public interface ${className}Service extends IService<${className}> {
}
配置serviceImpl
ServiceImpl.java.vm
package ${package}.service.impl;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${package}.entity.${className};
import ${package}.service.${className}Service;
import ${package}.mapper.${className}Mapper;
/**
* Module: ${className}.java
*
* @author ${author}
* @since JDK ${jdk}
* @version ${version}
* @date ${date}
* @Descriptions:
*/
@Service
public class ${className}ServiceImpl extends ServiceImpl<${className}Mapper, ${className}> implements ${className}Service {
}
第五步 配置类型转换
CommonMap.java
package com.example.demo.generator;
import java.util.HashMap;
import java.util.Map;
public class CommonMap {
/** 状态编码转换 */
public static Map<String, String> javaTypeMap = new HashMap<String, String>();
static {
initJavaTypeMap();
}
/**
* 返回状态映射
*/
public static void initJavaTypeMap() {
javaTypeMap.put("tinyint", "Integer");
javaTypeMap.put("smallint", "Integer");
javaTypeMap.put("mediumint", "Integer");
javaTypeMap.put("int", "Integer");
javaTypeMap.put("integer", "integer");
javaTypeMap.put("bigint", "Long");
javaTypeMap.put("float", "Float");
javaTypeMap.put("double", "Double");
javaTypeMap.put("decimal", "Double");
// javaTypeMap.put("decimal", "BigDecimal");
javaTypeMap.put("bit", "Boolean");
javaTypeMap.put("char", "String");
javaTypeMap.put("varchar", "String");
javaTypeMap.put("tinytext", "String");
javaTypeMap.put("text", "String");
javaTypeMap.put("mediumtext", "String");
javaTypeMap.put("longtext", "String");
javaTypeMap.put("time", "LocalDateTime");
javaTypeMap.put("date", "LocalDate");
javaTypeMap.put("datetime", "LocalDateTime");
javaTypeMap.put("timestamp", "LocalDateTime");
javaTypeMap.put("tablePrefix", "");// 前缀
javaTypeMap.put("package", "com.waterelephant.common");//包名
javaTypeMap.put("author", "yueyiming");//作者
javaTypeMap.put("jdk", "1.8");
javaTypeMap.put("version", "1.0");
}
}
第六步 配置table实体类
TableEntity .java
package com.example.demo.generator;
import java.util.List;
public class TableEntity {
// 表的名称
private String tableName;
// 表的备注
private String comments;
// 表的主键
private ColumnEntity pk;
// 表的列名(不包含主键)
private List<ColumnEntity> columns;
// 类名(第一个字母大写),如:sys_user => SysUser
private String className;
// 类名(第一个字母小写),如:sys_user => sysUser
private String classname;
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public ColumnEntity getPk() {
return pk;
}
public void setPk(ColumnEntity pk) {
this.pk = pk;
}
public List<ColumnEntity> getColumns() {
return columns;
}
public void setColumns(List<ColumnEntity> columns) {
this.columns = columns;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
}
第七步 配置Column实体类
ColumnEntity 实体类
package com.example.demo.generator;
public class ColumnEntity {
// 列名
private String columnName;
// 列名类型
private String dataType;
// 列名备注
private String comments;
// 属性名称(第一个字母大写),如:user_name => UserName
private String attrName;
// 属性名称(第一个字母小写),如:user_name => userName
private String attrname;
// 属性类型
private String attrType;
// auto_increment
private String extra;
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getAttrname() {
return attrname;
}
public void setAttrname(String attrname) {
this.attrname = attrname;
}
public String getAttrName() {
return attrName;
}
public void setAttrName(String attrName) {
this.attrName = attrName;
}
public String getAttrType() {
return attrType;
}
public void setAttrType(String attrType) {
this.attrType = attrType;
}
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
}
第八步 配置所需查询mapper
GenMapper
package com.example.demo.mapper;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Select;
public interface GenMapper {
@Select("select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables where table_schema = (SELECT DATABASE()) and table_name = #{tableName}")
Map<String, Object> queryTable(String tableName);
@Select("select column_name columnName, data_type dataType, column_comment columnComment, column_key columnKey, extra from information_schema.columns where table_name =#{tableName} and table_schema = (SELECT DATABASE()) order by ordinal_position")
List<Map<String, Object>> queryColumns(String tableName);
@Select("select table_name tableName from information_schema.tables where table_schema = (SELECT DATABASE())")
List<String> queryAllTable();
}
第九步 生成代码工具类
GenUtils.java
package com.example.demo.generator;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
public class GenUtils {
/** 时间格式(yyyy-MM-dd) */
public final static String DATE_PATTERN = "yyyy-MM-dd";
/** 时间格式(yyyy-MM-dd HH:mm:ss) */
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static String format(Date date) {
return format(date, DATE_PATTERN);
}
public static String format(Date date, String pattern) {
if (date != null) {
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
public static List<String> getTemplates() {
List<String> templates = new ArrayList<>();
templates.add("vm/Entity.java.vm");
templates.add("vm/Service.java.vm");
templates.add("vm/ServiceImpl.java.vm");
templates.add("vm/Mapper.java.vm");
return templates;
}
/**
* 生成代码
*/
public static void generatorCode(Map<String, Object> table, List<Map<String, Object>> columns, ZipOutputStream zip) {
// 表信息
TableEntity tableEntity = new TableEntity();
tableEntity.setTableName(table.get("tableName") + "");
tableEntity.setComments(table.get("tableComment") + "");
// 表名转换成Java类名
String className = tableToJava(tableEntity.getTableName(), CommonMap.javaTypeMap.get("tablePrefix"));
tableEntity.setClassName(className);
tableEntity.setClassname(StringUtils.uncapitalize(className));
// 列信息
List<ColumnEntity> columsList = new ArrayList<>();
for (Map<String, Object> 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 = CommonMap.javaTypeMap.get(columnEntity.getDataType());
attrType = StringUtils.isBlank(attrType) ? "unknowType" : attrType;
columnEntity.setAttrType(attrType);
// 是否主键
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));
}
// 设置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<>();
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("package", CommonMap.javaTypeMap.get("package"));
map.put("author", CommonMap.javaTypeMap.get("author"));
map.put("date", format(new Date(), DATE_PATTERN));
// map.put("db", db);
map.put("jdk", CommonMap.javaTypeMap.get("jdk"));
map.put("version", CommonMap.javaTypeMap.get("version"));
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);
try {
// 添加到zip
zip.putNextEntry(new ZipEntry(getFileName(template, tableEntity.getClassName(), CommonMap.javaTypeMap.get("package"))));
IOUtils.write(sw.toString(), zip, "UTF-8");
IOUtils.closeQuietly(sw);
zip.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 列名转换成Java属性名
*/
public static String columnToJava(String columnName) {
return WordUtils.capitalizeFully(columnName, new char[] { '_' }).replace("_", "");
}
/**
* 表名转换成Java类名
*/
public static String tableToJava(String tableName, String tablePrefix) {
if (StringUtils.isNotBlank(tablePrefix)) {
tableName = tableName.replace(tablePrefix, "");
}
return columnToJava(tableName);
}
/**
* 获取文件名
*/
public static String getFileName(String template, String className, String packageName) {
String packagePath = "main" + File.separator + "java" + File.separator;
if (StringUtils.isNotBlank(packageName)) {
packagePath += packageName.replace(".", File.separator) + File.separator;
}
if (template.contains("Entity.java.vm")) {
return packagePath + "entity" + File.separator + className + ".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("Mapper.java.vm")) {
return packagePath + "mapper" + File.separator + className + "Mapper.java";
}
return null;
}
}
第十步:查询所有表,调用生成工具类
GenComp.java
package com.example.demo.generator;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.example.demo.mapper.GenMapper;
@Component
public class GenComp {
@Autowired
GenMapper genMapper;
/**
* 生成所有表
* @return
*/
public byte[] generatorCode() {
List<String> tableNames=genMapper.queryAllTable();
return generatorCode(tableNames);
}
/**
* 生成指定表
* @param tableNames
* @return
*/
public byte[] generatorCode( List<String> tableNames) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
for (String tableName : tableNames) {
Map<String, Object> table = genMapper.queryTable(tableName);
List<Map<String, Object>> columns = genMapper.queryColumns(tableName);
GenUtils.generatorCode( table, columns, zip);
}
IOUtils.closeQuietly(zip);
return outputStream.toByteArray();
}
}
测试
package com.example.demo;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.example.demo.generator.GenComp;
@SpringBootTest
@RunWith(SpringRunner.class)
public class MybatisDemoApplicationTests {
@Autowired
private GenComp genComp;
@Test
public void test() {
byte[] zipByte = genComp.generatorCode();
try {
//生成路径
FileUtils.writeByteArrayToFile(new File("C:\\1.zip"), zipByte);
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试生成成功
下面是生成代码截图