mybatis-plus代码生成器扩展
mybatis-plus代码生成器扩展
根据服务名将生成实体类和其他类(mapper,service,controller....)分散到不同微服务项目包下
1. 概述
- ORM方面我们选用mybatisplus框架进行开发,因为我们使用的是微服务架构,所以初期建库建表完成之后需要创建大量的实体类,mapper(没有使用xml文件),service等java文件。
- 不管是mappe层还是service层,mybatisplus都为我们提供了很好的数据库操作函数,不用重复创建文件和方法了,所以可以通过代码生成器快速的生成实体类等文件。
- Mybatisplus官方提供的代码生成器只能生成在同一个项目内,不满足我们想把生成的mapper,service等文件分散到不同的项目内的需求,所以对代码生成器进行了小小的改动
项目使用springcloud,根据业务模块划分不同为子模块。
2. 正文
2.1 导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.1.1</version>
</dependency>
<!-- 模板引擎需要借助velocity依赖 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
2.2 数据配置
2.2.1 CodeGenerator.java (主类-运行main即可)
package cn.com.agree.ait.generator;
import cn.com.agree.ait.generator.config.AitAutoGenerator;
import cn.com.agree.ait.generator.config.AitTemplateEngine;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.io.File;
/**
* 代码生成工具,运行本类main方法即可
* @author lzx
* @date 2021年8月26日15:36:44
*/
public class CodeGenerator {
// 文件是否需要生成在不同的项目服务模块
private static final boolean isMicroService = true;
// 需要生成的表名,多表在数组内append
private static final String[] tableNames = {
"xxx",
"xxxxx"
};
// 实体类生成在ait-commons服务 commons->实体类服务名
private static final String CommonsServiceName = "commons";
// mapper,service...生成在其他服务 xxx->需要生成mapper等文件的服务名
private static final String OtherServiceName = "xxx";
// 开发人员名称
private static final String Author = "lzx";
// jdbc配置 xxx代表填入自己的数据库环境配置 数据库环境为mysql,oracle环境未实验
private static final String JDBC_URL = "xxx";
private static final String JDBC_DRVERCLASS = "xxx";
private static final String JDBC_USERNAME = "xxx";
private static final String JDBC_PASSWORD = "xxx";
// 指定commons服务(实体类服务) packagename为包名,xxx为服务名
private static final String rootCommonsServicePackage = "/src/main/java/packagename.../xxx/pojo";根包路径
// 指定省其他服务根包路径(mapper,service,serviceimpl,controller文件) packagename为包名,xxx为服务名
private static final String rootOtherServicePackage = "/src/main/java/packagename/xxx/";
public static void main(String[] args) {
aitAutoGeneratorExecute();
}
private static void aitAutoGeneratorExecute() {
// 代码生成器
AitAutoGenerator mpg = new AitAutoGenerator();
GlobalConfig gc = popularGlobalConfig();
mpg.setGlobalConfig(gc);
DataSourceConfig dsc = popularDataSourceConfig();
mpg.setDataSource(dsc);
PackageConfig pc = popularPackageConfig();
mpg.setPackageInfo(pc);
InjectionConfig cfg = popularInjectionConfig();
mpg.setCfg(cfg);
TemplateConfig templateConfig = popularTemplateConfig();
mpg.setTemplate(templateConfig);
StrategyConfig strategy = popularStrategyConfig(pc);
mpg.setStrategy(strategy);
AitAutoGenerator.MicroServiceConfig microServiceConfig = popularMicroServiceConfig();
mpg.setTemplateEngine(new AitTemplateEngine(microServiceConfig));
mpg.execute();
}
private static AitAutoGenerator.MicroServiceConfig popularMicroServiceConfig() {
AitAutoGenerator.MicroServiceConfig microServiceConfig = new AitAutoGenerator.MicroServiceConfig();
//默认微服务模式,多服务分散生成
microServiceConfig.setMicroService(isMicroService);
microServiceConfig.setOtherServicePath(new File(System.getProperty("user.dir") + "/" + OtherServiceName + rootOtherServicePackage).getAbsolutePath());
microServiceConfig.setCommonsServicePath(new File(System.getProperty("user.dir") + "/" + CommonsServiceName + rootCommonsServicePackage).getAbsolutePath());
return microServiceConfig;
}
private static StrategyConfig popularStrategyConfig(PackageConfig pc) {
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.no_change);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
// strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
// 写于父类中的公共字段
// strategy.setSuperEntityColumns("id");
strategy.setInclude(tableNames);
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
return strategy;
}
private static TemplateConfig popularTemplateConfig() {
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
return templateConfig;
}
private static InjectionConfig popularInjectionConfig() {
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
return cfg;
}
private static PackageConfig popularPackageConfig() {
// 包配置
PackageConfig pc = new PackageConfig();
// 不额外指定模块,如果指定为 test,则生成的xml会在 mapper/test/ 目录下
pc.setModuleName("ait");
pc.setParent("xxx");
pc.setEntity("pojo");
return pc;
}
private static DataSourceConfig popularDataSourceConfig() {
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl(JDBC_URL);
dsc.setDriverName(JDBC_DRVERCLASS);
dsc.setUsername(JDBC_USERNAME);
dsc.setPassword(JDBC_PASSWORD);
return dsc;
}
private static GlobalConfig popularGlobalConfig() {
GlobalConfig gc = new GlobalConfig();
// 全局配置
String projectPath = System.getProperty("user.dir") + "/";
gc.setOutputDir(projectPath);
gc.setAuthor(Author);
gc.setOpen(false);
// 覆盖写
gc.setFileOverride(true);
gc.setControllerName(null);
return gc;
}
}
2.2.2 AitConstVal.java
package cn.com.agree.ait.generator.config;
import com.baomidou.mybatisplus.generator.config.ConstVal;
/**
* @author lzx
* @version 1.0
* @date 2021/08/26 下午 01:51
* @description:
*/
public class AitConstVal implements ConstVal {
static String ENTITY_PATH = "entity_path";
static String SERVICE_PATH = "service_path";
static String SERVICE_IMPL_PATH = "service_impl_path";
static String MAPPER_PATH = "mapper_path";
static String XML_PATH = "xml_path";
static String CONTROLLER_PATH = "controller_path";
public static final String MAPPER_PACKAGE_PATH ="/mapper";
public static final String SERVICE_PACKAGE_PATH ="/service";
public static final String SERVICE_IMPL_PACKAGE_PATH ="/service/impl";
public static final String CONTROLLER_PACKAGE_PATH ="/controller";
}
2.2.3 AitAutoGenerator.java
package cn.com.agree.ait.generator.config;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.Version;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import lombok.*;
import lombok.experimental.Accessors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.List;
/**
* @author lzx
* @version 1.0
* @date 2021/08/26 下午 01:09
* @description:
*/
@Data
@Accessors(chain = true)
public class AitAutoGenerator extends AutoGenerator {
private static final Logger logger = LoggerFactory.getLogger(AitAutoGenerator.class);
/**
* 配置信息
*/
protected ConfigBuilder config;
/**
* 注入配置
*/
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
protected InjectionConfig injectionConfig;
/**
* 数据源配置
*/
private DataSourceConfig dataSource;
/**
* 数据库表配置
*/
private StrategyConfig strategy;
/**
* 包 相关配置
*/
private PackageConfig packageInfo;
/**
* 模板 相关配置
*/
private TemplateConfig template;
/**
* 全局 相关配置
*/
private GlobalConfig globalConfig;
/**
* 模板引擎
*/
private AbstractTemplateEngine templateEngine;
//微服务 相关配置
private MicroServiceConfig microServiceConfig;
/**
* 生成代码
*/
@Override
public void execute() {
logger.debug("==========================准备生成文件...==========================");
// 初始化配置
if (null == config) {
config = new ConfigBuilder(packageInfo, dataSource, strategy, template, globalConfig);
if (null != injectionConfig) {
injectionConfig.setConfig(config);
}
}
if (null == templateEngine) {
// 为了兼容之前逻辑,采用 Velocity 引擎 【 默认 】
templateEngine = new VelocityTemplateEngine();
}
// 模板引擎初始化执行文件输出
templateEngine.setConfigBuilder(config);
templateEngine.init(this.pretreatmentConfigBuilder(config)).mkdirs().batchOutput().open();
logger.debug("==========================文件生成完成!!!==========================");
}
/**
* 开放表信息、预留子类重写
*
* @param config 配置信息
* @return ignore
*/
@Override
protected List<TableInfo> getAllTableInfoList(ConfigBuilder config) {
return config.getTableInfoList();
}
/**
* 预处理配置
*
* @param config 总配置信息
* @return 解析数据结果集
*/
@Override
protected ConfigBuilder pretreatmentConfigBuilder(ConfigBuilder config) {
/*
* 注入自定义配置
*/
if (null != injectionConfig) {
injectionConfig.initMap();
config.setInjectionConfig(injectionConfig);
}
/*
* 表信息列表
*/
List<TableInfo> tableList = this.getAllTableInfoList(config);
for (TableInfo tableInfo : tableList) {
/* ---------- 添加导入包 ---------- */
if (config.getGlobalConfig().isActiveRecord()) {
// 开启 ActiveRecord 模式
tableInfo.setImportPackages(Model.class.getCanonicalName());
}
if (tableInfo.isConvert()) {
// 表注解
tableInfo.setImportPackages(TableName.class.getCanonicalName());
}
if (config.getStrategyConfig().getLogicDeleteFieldName() != null && tableInfo.isLogicDelete(config.getStrategyConfig().getLogicDeleteFieldName())) {
// 逻辑删除注解
tableInfo.setImportPackages(TableLogic.class.getCanonicalName());
}
if (StringUtils.isNotEmpty(config.getStrategyConfig().getVersionFieldName())) {
// 乐观锁注解
tableInfo.setImportPackages(Version.class.getCanonicalName());
}
boolean importSerializable = true;
if (StringUtils.isNotEmpty(config.getSuperEntityClass())) {
// 父实体
tableInfo.setImportPackages(config.getSuperEntityClass());
importSerializable = false;
}
if (config.getGlobalConfig().isActiveRecord()) {
importSerializable = true;
}
if (importSerializable) {
tableInfo.setImportPackages(Serializable.class.getCanonicalName());
}
// Boolean类型is前缀处理
if (config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix()) {
tableInfo.getFields().stream().filter(field -> "boolean".equalsIgnoreCase(field.getPropertyType()))
.filter(field -> field.getPropertyName().startsWith("is"))
.forEach(field -> {
field.setConvert(true);
field.setPropertyName(StringUtils.removePrefixAfterPrefixToLower(field.getPropertyName(), 2));
});
}
}
return config.setTableInfoList(tableList);
}
@Override
public InjectionConfig getCfg() {
return injectionConfig;
}
@Override
public AitAutoGenerator setCfg(InjectionConfig injectionConfig) {
this.injectionConfig = injectionConfig;
return this;
}
@Data
public static class MicroServiceConfig{
//是否是微服务模块划分
private boolean isMicroService;
//ait-commons服务根路径(主要生成实体类)
private String commonsServicePath;
//其他服务路径(先支持单服务根路径)(主要生成mapper/service/seriveimpl/controller)
private String otherServicePath;
}
}
2.2.4 AitTemplateEngine.java
package cn.com.agree.ait.generator.config;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.FileType;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* @author lzx
* @version 1.0
* @date 2021/08/26 下午 03:27
* @description:
*/
public class AitTemplateEngine extends AbstractTemplateEngine {
private static final String DOT_VM = ".vm";
private VelocityEngine velocityEngine;
private AitAutoGenerator.MicroServiceConfig microServiceConfig;
private ConfigBuilder configBuilder;
public AitTemplateEngine(AitAutoGenerator.MicroServiceConfig microServiceConfig) {
this.microServiceConfig = microServiceConfig;
}
@Override
public AitTemplateEngine init(ConfigBuilder configBuilder) {
if (null == velocityEngine) {
Properties p = new Properties();
p.setProperty(ConstVal.VM_LOAD_PATH_KEY, ConstVal.VM_LOAD_PATH_VALUE);
p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, StringPool.EMPTY);
p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
p.setProperty("file.resource.loader.unicode", StringPool.TRUE);
velocityEngine = new VelocityEngine(p);
}
this.configBuilder = configBuilder;
super.setConfigBuilder(configBuilder);
return this;
}
@Override
public ConfigBuilder getConfigBuilder() {
return super.getConfigBuilder();
}
/**
* 处理输出目录
*/
@Override
public AitTemplateEngine mkdirs() {
getConfigBuilder().getPathInfo().forEach((key, value) -> {
if(microServiceConfig.isMicroService()){
String servicePath;
String info;
if (AitConstVal.ENTITY.equals(key)){
servicePath = microServiceConfig.getCommonsServicePath();
info = "创建Ait-Commons-Service实体类目录: [";
}else {
servicePath = microServiceConfig.getOtherServicePath();
info = "创建Ait-" + servicePath + "-Service实体类目录: [";
}
File dir = new File(servicePath);
if (!dir.exists()) {
boolean result = dir.mkdirs();
if (result) {
logger.debug(info + servicePath + "]");
}
}
}else {
File dir = new File(value);
if (!dir.exists()) {
boolean result = dir.mkdirs();
if (result) {
logger.debug("创建目录: [" + value + "]");
}
}
}
});
return this;
}
@Override
public void writer(Map<String, Object> objectMap, String templatePath, String outputFile) throws Exception {
if (StringUtils.isEmpty(templatePath)) {
return;
}
Template template = velocityEngine.getTemplate(templatePath, ConstVal.UTF8);
try (FileOutputStream fos = new FileOutputStream(outputFile);
OutputStreamWriter ow = new OutputStreamWriter(fos, ConstVal.UTF8);
BufferedWriter writer = new BufferedWriter(ow)) {
template.merge(new VelocityContext(objectMap), writer);
}
logger.debug("模板:" + templatePath + "; 文件:" + outputFile);
}
@Override
public String templateFilePath(String filePath) {
if (null == filePath || filePath.contains(DOT_VM)) {
return filePath;
}
return filePath + DOT_VM;
}
@Override
public AbstractTemplateEngine batchOutput() {
try {
List<TableInfo> tableInfoList = getConfigBuilder().getTableInfoList();
for (TableInfo tableInfo : tableInfoList) {
Map<String, Object> objectMap = getObjectMap(tableInfo);
Map<String, String> pathInfo = getConfigBuilder().getPathInfo();
TemplateConfig template = getConfigBuilder().getTemplate();
// 自定义内容
InjectionConfig injectionConfig = getConfigBuilder().getInjectionConfig();
if (null != injectionConfig) {
injectionConfig.initMap();
objectMap.put("cfg", injectionConfig.getMap());
List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
if (CollectionUtils.isNotEmpty(focList)) {
for (FileOutConfig foc : focList) {
if (isCreate(FileType.OTHER, foc.outputFile(tableInfo))) {
writer(objectMap, foc.getTemplatePath(), foc.outputFile(tableInfo));
}
}
}
}
//覆盖原有目录并且优化文件名称
coverOriDirectory(pathInfo,tableInfo);
// Mp.java
String entityName = tableInfo.getEntityName();
if (null != entityName && null != pathInfo.get(ConstVal.ENTITY_PATH)) {
String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + suffixJavaOrKt()), entityName);
if (isCreate(FileType.ENTITY, entityFile)) {
writer(objectMap, templateFilePath(template.getEntity(getConfigBuilder().getGlobalConfig().isKotlin())), entityFile);
}
}
// MpMapper.java
if (null != tableInfo.getMapperName() && null != pathInfo.get(ConstVal.MAPPER_PATH)) {
String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + suffixJavaOrKt()), entityName);
if (isCreate(FileType.MAPPER, mapperFile)) {
writer(objectMap, templateFilePath(template.getMapper()), mapperFile);
}
}
// MpMapper.xml
if (null != tableInfo.getXmlName() && null != pathInfo.get(ConstVal.XML_PATH)) {
String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
if (isCreate(FileType.XML, xmlFile)) {
writer(objectMap, templateFilePath(template.getXml()), xmlFile);
}
}
// IMpService.java
if (null != tableInfo.getServiceName() && null != pathInfo.get(ConstVal.SERVICE_PATH)) {
String serviceFile = String.format((pathInfo.get(ConstVal.SERVICE_PATH) + File.separator + tableInfo.getServiceName() + suffixJavaOrKt()), entityName);
if (isCreate(FileType.SERVICE, serviceFile)) {
writer(objectMap, templateFilePath(template.getService()), serviceFile);
}
}
// MpServiceImpl.java
if (null != tableInfo.getServiceImplName() && null != pathInfo.get(ConstVal.SERVICE_IMPL_PATH)) {
String implFile = String.format((pathInfo.get(ConstVal.SERVICE_IMPL_PATH) + File.separator + tableInfo.getServiceImplName() + suffixJavaOrKt()), entityName);
if (isCreate(FileType.SERVICE_IMPL, implFile)) {
writer(objectMap, templateFilePath(template.getServiceImpl()), implFile);
}
}
// MpController.java
if (null != tableInfo.getControllerName() && null != pathInfo.get(ConstVal.CONTROLLER_PATH)) {
String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + suffixJavaOrKt()), entityName);
if (isCreate(FileType.CONTROLLER, controllerFile)) {
writer(objectMap, templateFilePath(template.getController()), controllerFile);
}
}
}
} catch (Exception e) {
logger.error("无法创建文件,请检查配置信息!", e);
}
return this;
}
private void coverOriDirectory(Map<String, String> pathInfo, TableInfo tableInfo) {
//1.重新写入文件目录
pathInfo.put(ConstVal.ENTITY_PATH,microServiceConfig.getCommonsServicePath());
pathInfo.put(ConstVal.MAPPER_PATH,new File(microServiceConfig.getOtherServicePath() + AitConstVal.MAPPER_PACKAGE_PATH).getAbsolutePath());
pathInfo.put(ConstVal.SERVICE_PATH,new File(microServiceConfig.getOtherServicePath() + AitConstVal.SERVICE_PACKAGE_PATH).getAbsolutePath());
pathInfo.put(ConstVal.SERVICE_IMPL_PATH,new File(microServiceConfig.getOtherServicePath() + AitConstVal.SERVICE_IMPL_PACKAGE_PATH).getAbsolutePath());
pathInfo.put(ConstVal.CONTROLLER_PATH,new File(microServiceConfig.getOtherServicePath() + AitConstVal.CONTROLLER_PACKAGE_PATH).getAbsolutePath());
//2.优化文件名称
tableInfo.setMapperName(optimizeFileName(tableInfo.getMapperName()));
tableInfo.setServiceName(optimizeFileName(tableInfo.getServiceName()));
tableInfo.setServiceImplName(optimizeFileName(tableInfo.getServiceImplName()));
tableInfo.setControllerName(optimizeFileName(tableInfo.getControllerName()));
}
private static String optimizeFileName(String mapperName) {
mapperName = mapperName.substring(mapperName.indexOf("_") + 1);
mapperName = mapperName.replaceFirst(String.valueOf(mapperName.charAt(0)),String.valueOf(mapperName.charAt(0)).toUpperCase());
StringBuilder tempStr = new StringBuilder(mapperName);
if (mapperName.contains("_")){
tempStr.setLength(0);
Arrays.stream(mapperName.split("_")).forEach(c -> {
tempStr.append(c.replace(String.valueOf(c.charAt(0)),String.valueOf(c.charAt(0)).toUpperCase()));
});
}
return tempStr.toString();
}
}
3. 小结
- 本文对于mybatisplus代码生成器的改造做了简单的介绍,粘贴代码即用。如果想深入了解这部分的知识,可以去了解一下官网 链接: link.
- 本次改动只是为了加快开发速度,提高效率,如果有什么疑问,欢迎留言