【mybatis|mybatis-plus-自定义模板】
文章目录
- 自定义模板
- GIT 地址
- 关注点
- 生成的代码调用流程
- 生成器
-
- 我写到这里我在想要不要把所有代码都贴出来...
- 自定义配置
-
- 定义接口
- 定义上下文
- 具体的模板我就不贴了
- 代码生成具体的类
- Pack配置
- 表的相关信息
- 将上面的两个config主要到Map中
- 源码查看
-
- 生成代码
- 继续看
自定义模板
- 由于公司需求,好吧由于本人比较懒,不愿意写代码,估采用代码生成器的方式来解决我的痛点
- 官方的代码生成器已经够好了但是还是不太符合我的要求,那咋能自己改吧改吧呗
- 拥有 一键生成
增、删、改、查、分页
功能还有导入导出等… - 具体的模板参考GitHub
- 如需特殊生成,联系我,免费给你加~~
- 自己下去吧
https://github.com/myliwenbo/Springboot/tree/master/springboot/springboot-mybatis-plus-generator关注点
- VelocityTemplateEngineEnhance 这个是具体的生成代码的,
- MD
mermaid
图太难了…我直接贴图了
- 具体代码的流程
文章图片
- 由于官方的代码都放在了一个类中,个人强迫症都进行了规整处理
- 我将官方的进行了拆分,看起来好学习一点,这个代码生成器,主要使用的是自定义模板比较多
/**
* 生成器
*/
public class FinancingGenerator {/**
* JDBC
*/
private static final String URL = "";
private static final String USER_NAME = "";
private static final String PASSWORD = "";
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
//这里去添加要生成的表
FinancingGenerator.createStrategyConfig(mpg, "file_manage");
//策略
FinancingGenerator.createDateSource(mpg);
//数据源
FinancingGenerator.createGlobalConfig(mpg);
//全局配置
FinancingGenerator.createTemplateConfig(mpg);
//配置模板
FinancingGenerator.createInjectionConfig(mpg);
//自定义配置
new TemplateConfigEnhance(mpg);
//配置包信息
mpg.execute();
}/**
* 数据源配置
*
* @return
*/
public static void createDateSource(AutoGenerator mpg) {
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl(URL);
dsc.setUsername(USER_NAME);
dsc.setPassword(PASSWORD);
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setDbType(DbType.MYSQL);
dsc.setTypeConvert(new MySqlTypeConvert());
mpg.setDataSource(dsc);
}/**
* 全局配置
*
* @return
*/
public static void createGlobalConfig(AutoGenerator mpg) {
GlobalConfig gc = new GlobalConfig();
gc.setOutputDir(Templates.PATH);
// 设置文件生成的目录
gc.setFileOverride(true);
// 是否覆盖原来的文件---- 这里需要注意
gc.setAuthor(Templates.AUTHOR);
// 设置作者~
gc.setOpen(false);
// 打开输出目录
gc.setEnableCache(false);
// XML 二级缓存
gc.setActiveRecord(true);
// 开启 activeRecord 模式
gc.setBaseResultMap(true);
// XML ResultMap
gc.setBaseColumnList(true);
// XML columList
gc.setServiceName("I%sDao");
// 实体命名方式,就会形成 UserService ,如果使用自定义路径则该规则不会生效
gc.setServiceImplName("%sDaoImpl");
// 实体命名方式,就会形成 UserServiceImpl ,如果使用自定义路径则该规则不会生效
mpg.setGlobalConfig(gc);
}/**
* 策略配置,可指定需要生成哪些表或者排除哪些表,
* 参考:https://mp.baomidou.com/config/generator-config.html#%E6%95%B0%E6%8D%AE%E5%BA%93%E8%A1%A8%E9%85%8D%E7%BD%AE
*
* @return
*/
public static void createStrategyConfig(AutoGenerator mpg, String... include) { // 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
// 数据库映射到实体的命名策略
// 公共父类
// strategy.setSuperControllerClass("com.alijiajituan.controller.BaseController");
strategy.setSuperEntityClass("cn....entity.BaseDo");
strategy.setInclude(include);
// 需要生成的表,和排除只能2选一
//strategy.setExclude("bak_category_property", "user");
// 需要排除的表,除了排除的表其他的都生成
// 自定义实体,公共字段
strategy.setSuperEntityColumns("id", "is_valid", "op_time", "last_ver", "status", "type", "create_time", "app_id");
strategy.setVersionFieldName("last_ver");
//乐观锁属性名称
strategy.setLogicDeleteFieldName("is_valid");
//逻辑删除属性名称
strategy.setRestControllerStyle(true);
// 生成 @RestController 控制器
strategy.setEntityLombokModel(true);
// 添加lombok模型
strategy.setEntityColumnConstant(true);
//是否生成字段常量
strategy.setEntityBooleanColumnRemoveIsPrefix(true);
// Boolean类型字段是否移除is前缀处理
mpg.setStrategy(strategy);
}/**
* 模板配置,如果使用自定义模板和配置,需要将默认模板为NULL!!!!*
*
* @return
*/
public static void createTemplateConfig(AutoGenerator mpg) {
TemplateConfig templateConfig = new TemplateConfig();
// templateConfig.setService("/templates/service.java.vm");
//默认模板
templateConfig.setEntity(null);
// 模块如果设置 Null 将不生成该模块
templateConfig.setService(null);
// 模块如果设置 Null 将不生成该模块
templateConfig.setServiceImpl(null);
// 模块如果设置 Null 将不生成该模块
templateConfig.setController(null);
// 模块如果设置 Null 将不生成该模块
templateConfig.setMapper(null);
// 模块如果设置 Null 将不生成该模块
templateConfig.setXml(null);
// 模块如果设置 Null 将不生成该模块
// 自定义模板文件,注意不要带上(.ftl)或者(.vm), 会根据使用的模板引擎自动识别
// 自定义模板放在 src/main/resources/templates 目录下, 默认名称可以不配置,也可以自定义模板名称
// 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改
mpg.setTemplate(templateConfig);
}/**
* 自定义配置
*/
public static void createInjectionConfig(AutoGenerator mpg) {
StrategyContext templatesList = StrategyContext.getTemplatesList();
templatesList.contextMethod(new EntityTemplates());
templatesList.contextMethod(new QueryReuqestEntityTemplates());
templatesList.contextMethod(new SaveReuqestEntityTemplates());
templatesList.contextMethod(new VOEntityTemplates());
templatesList.contextMethod(new TDOEntityTemplates());
templatesList.contextMethod(new XMLTemplates());
templatesList.contextMethod(new MapperTemplates());
templatesList.contextMethod(new DAOTemplates());
templatesList.contextMethod(new DAOImplTemplates());
templatesList.contextMethod(new ServiceTemplates());
templatesList.contextMethod(new ManagerTemplates());
templatesList.contextMethod(new ControllerTemplates());
templatesList.getInjectionConfig(mpg);
}
}
我写到这里我在想要不要把所有代码都贴出来…
- 纠结了一下还是贴吧
- 利用策略模式把代码进行拆分掉
public interface Templates {/**
* package
*/
String PACKAGE = "vip.xjdai";
/**
* 当前项目路径
*/
String PATH = System.getProperty("user.dir") + "/src/main/java";
//这里是定义的作者
String AUTHOR = "你最棒";
/**
* 生成的目录
*/
String PACKAGE_FILE = "/vip/xjdai/";
/**
* 模板地址
*/
String TEMPLATES = "/templates/";
String ENTITY = PATH + PACKAGE_FILE + "/repository/entity/";
String ENTITY_TEMPLATES = "/templates/entity.java.vm";
String ENTITY_TDO = PATH + PACKAGE_FILE + "/repository/entity/";
String ENTITY_TDO_TEMPLATES = "/templates/dto_entity.java.vm";
String QUERY_ENTITY = PATH + PACKAGE_FILE + "/repository/vo/";
String QUERY_ENTITY_TEMPLATES = "/templates/query_entity.java.vm";
String SAVE_ENTITY = PATH + PACKAGE_FILE + "/repository/vo/";
String SAVE_ENTITY_TEMPLATES = "/templates/save_entity.java.vm";
String VO_ENTITY = PATH + PACKAGE_FILE + "/repository/vo/";
String VO_TEMPLATES = "/templates/vo_entity.java.vm";
String XML = System.getProperty("user.dir") + "/src/main/resources/mapper/";
String XML_TEMPLATES = "/templates/xml.xml.vm";
String MAPPER = PATH + PACKAGE_FILE + "/repository/mapper/";
String MAPPER_TEMPLATES = "/templates/mapper.java.vm";
String DAO = PATH + PACKAGE_FILE + "/repository/dao/";
String DAO_TEMPLATES = "/templates/dao.java.vm";
String DAO_IMPL = PATH + PACKAGE_FILE + "/repository/dao/impl/";
String DAO_IMPL_TEMPLATES = "/templates/dao_impl.java.vm";
String SERVICE = PATH + PACKAGE_FILE + "/service/";
String SERVICE_TEMPLATES = "/templates/service.java.vm";
String MANAGER = PATH + PACKAGE_FILE + "/manager/";
String MANAGER_TEMPLATES = "/templates/manager.java.vm";
String CONTROLLER = PATH + PACKAGE_FILE + "/controller/";
String CONTROLLER_TEMPLATES = "/templates/controller.java.vm";
FileOutConfig contextMethod();
String SAVE_REQUEST_SUFFIX = "SaveRequest";
String QUERY_REQUEST_SUFFIX = "QueryRequest";
String VO_REQUEST_SUFFIX = "Vo";
String DTO_REQUEST_SUFFIX = "Tdo";
String MAPPER_SUFFIX = "Mapper";
String DAO_SUFFIX = "Dao";
String DAO_IMPL_SUFFIX = "DaoImpl";
String SERVICE_SUFFIX = "Service";
String MANAGER_SUFFIX = "Manager";
String CONTROLLER_SUFFIX = "Controller";
}
定义上下文
- 用于操作具体的生成类
public class StrategyContext {private List focList;
public void contextMethod(Templates templates) {
FileOutConfig fileOutConfig = templates.contextMethod();
focList.add(fileOutConfig);
}public void getInjectionConfig(AutoGenerator mpg) {
// 注入自定义配置,可以在 VM 中使用 cfg.abc
InjectionConfig injectionConfig = new InjectionConfig() {
@Override
public void initMap() {
this.setMap(new HashMap<>());
}
};
injectionConfig.setFileOutConfigList(this.focList);
mpg.setCfg(injectionConfig);
}public static class StrategyContextOne {
static StrategyContext instance = new StrategyContext();
}public static StrategyContext getTemplatesList() {
StrategyContext strategyContext = StrategyContextOne.instance;
strategyContext.focList = Lists.newArrayList();
return strategyContext;
}public List getFocList() {
return focList;
}
}
具体的模板我就不贴了
- 都是差不多的
public class ControllerTemplates implements Templates {
@Override
public FileOutConfig contextMethod() {
// CONTROLLER_TEMPLATES 是模板的路径
return new FileOutConfig(CONTROLLER_TEMPLATES) {
@Override
public String outputFile(TableInfo tableInfo) {
// 是代码生成到那个文件夹下
return CONTROLLER + tableInfo.getEntityName() + Templates.CONTROLLER_SUFFIX + StringPool.DOT_JAVA;
}
};
}
}
代码生成具体的类 *主要就是将Map开放出去好定义自己的模板,看源码得知,这个Map是具体存放模板内的一些值
public abstract class VelocityTemplateEngineEnhance extends VelocityTemplateEngine {private Map, Object> objectMap;
@Override
public VelocityTemplateEngine init(ConfigBuilder configBuilder) {
super.init(configBuilder);
return this;
}public void writer(Map, Object> objectMap, String templatePath, String outputFile) throws Exception {
//将objectMap开放出去
this.objectMap = objectMap;
//这里调用增强方法
enhanceMap(this.objectMap);
//增强该方法
super.writer(objectMap, templatePath, outputFile);
}
public Map, Object> getObjectMap() {
return objectMap;
}/**
* 添加
*/
public abstract void enhanceMap(Map, Object> objectMap);
}
Pack配置
- 主要定义了一些在模板里面使用的一些属性,
- 本来想把就是导包也加进去了,不想写了就那么用吧
/**
* package配置
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class PackageConfigEnhance extends PackageConfig {private Map, String> packageInfo = Maps.newHashMap();
private String saveEntity = "";
private String queryEntity = "";
private String voEntity = "";
private String tdoEntity = "";
private String customizeService = "";
private String manager = "";
public PackageConfigEnhance(Map, String> packageInfo) {
this.packageInfo = packageInfo;
init();
}public Map, String> getPackageInfo() {
packageInfo.put("Entity", joinPackage(this.getParent(), this.getEntity()));
packageInfo.put("SaveEntity", joinPackage(this.getParent(), this.getSaveEntity()));
packageInfo.put("QueryEntity", joinPackage(this.getParent(), this.getQueryEntity()));
packageInfo.put("VoEntity", joinPackage(this.getParent(), this.getVoEntity()));
packageInfo.put("DtoEntity", joinPackage(this.getParent(), this.getVoEntity()));
packageInfo.put(ConstVal.MAPPER, joinPackage(this.getParent(), this.getMapper()));
packageInfo.put(ConstVal.XML, joinPackage(this.getParent(), this.getXml()));
packageInfo.put("Dao", joinPackage(this.getParent(), this.getService()));
packageInfo.put("DaoImpl", joinPackage(this.getParent(), this.getServiceImpl()));
packageInfo.put("Service", joinPackage(this.getParent(), this.getCustomizeService()));
packageInfo.put("Manager", joinPackage(this.getParent(), this.getManager()));
packageInfo.put("Controller", joinPackage(this.getParent(), this.getController()));
return packageInfo;
}//public void setClass() {
//packageInfo.put("EntityClass", packageInfo.get());
//packageInfo.put("SaveEntityClass",packageInfo.get());
//packageInfo.put("QueryEntityClass",packageInfo.get());
//packageInfo.put("VoEntityClass",packageInfo.get());
//packageInfo.put("TdoEntityClass",packageInfo.get());
//packageInfo.put(ConstVal.MAPPER, packageInfo.get());
//packageInfo.put(ConstVal.XML,packageInfo.get());
//packageInfo.put("DaoClass",packageInfo.get());
//packageInfo.put("DaoImplClass",packageInfo.get());
//packageInfo.put("ServiceClass",packageInfo.get());
//packageInfo.put("ManagerClass",packageInfo.get());
//packageInfo.put("ControllerClass",packageInfo.get());
//}/**
* 包配置
*
* @return
*/
public void init() {
this.setParent(Templates.PACKAGE);
//父节点
this.setEntity("repository.entity");
this.setQueryEntity("repository.vo");
this.setSaveEntity("repository.vo");
this.setTdoEntity("repository.vo");
this.setVoEntity("repository.vo");
this.setMapper("repository.mapper");
this.setService("repository.dao");
this.setServiceImpl("repository.dao.impl");
this.setCustomizeService("service");
this.setManager("manager");
this.setController("controller");
}/**
* 连接父子包名
*
* @param parent父包名
* @param subPackage 子包名
* @return 连接后的包名
*/
private String joinPackage(String parent, String subPackage) {
if (StringUtils.isEmpty(parent)) {
return subPackage;
}
return parent + StringPool.DOT + subPackage;
}
}
表的相关信息
- 主要是一些表的相关信息以及实体类呀变量呀之类的东西
/**
* 增强表
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class TableInfoConfigEnhance extends TableInfo {private String entity = "";
private String entityHump = "";
private String saveEntity = "";
private String saveEntityHump = "";
private String queryEntity = "";
private String queryEntityHump = "";
private String voEntity = "";
private String voEntityHump = "";
private String dtoEntity = "";
private String dtoEntityHump = "";
private String mapper= "";
private String dao= "";
private String daoHump= "";
private String daoImpl = "";
private String daoImplHump = "";
private String service = "";
private String serviceHump = "";
private String manager = "";
private String managerHump = "";
public TableInfoConfigEnhance(TableInfo tableInfo) {
BeanUtils.copyProperties(tableInfo, this);
this.setEntity(tableInfo.getEntityName());
this.setEntityHump(tableInfo.getEntityPath());
this.setSaveEntity(tableInfo.getEntityName() + Templates.SAVE_REQUEST_SUFFIX);
this.setSaveEntityHump(tableInfo.getEntityPath() + Templates.SAVE_REQUEST_SUFFIX);
this.setQueryEntity(tableInfo.getEntityName() + Templates.QUERY_REQUEST_SUFFIX);
this.setQueryEntityHump(tableInfo.getEntityPath() + Templates.QUERY_REQUEST_SUFFIX);
this.setVoEntity(tableInfo.getEntityName() + Templates.VO_REQUEST_SUFFIX);
this.setVoEntityHump(tableInfo.getEntityPath() + Templates.VO_REQUEST_SUFFIX);
this.setDtoEntity(tableInfo.getEntityName() + Templates.DTO_REQUEST_SUFFIX);
this.setDtoEntityHump(tableInfo.getEntityPath() + Templates.DTO_REQUEST_SUFFIX);
this.setMapper(tableInfo.getEntityName() + Templates.MAPPER_SUFFIX);
this.setDao(tableInfo.getEntityName() + Templates.DAO_SUFFIX);
this.setDaoHump(tableInfo.getEntityPath() + Templates.DAO_SUFFIX);
this.setDaoImpl(tableInfo.getEntityName() + Templates.DAO_IMPL_SUFFIX);
this.setDaoImplHump(tableInfo.getEntityPath() + Templates.DAO_IMPL_SUFFIX);
this.setService(tableInfo.getEntityName() + Templates.SERVICE_SUFFIX);
this.setServiceHump(tableInfo.getEntityPath() + Templates.SERVICE_SUFFIX);
this.setManager(tableInfo.getEntityName() + Templates.MANAGER_SUFFIX);
this.setManagerHump(tableInfo.getEntityPath() + Templates.MANAGER_SUFFIX);
}}
将上面的两个config主要到Map中
- 这里就是具体的将一些内容注入进去了
public class TemplateConfigEnhance {private AutoGenerator mpg;
public TemplateConfigEnhance(AutoGenerator mpg) {
this.mpg = mpg;
createVelocityTemplateEngine();
}private void createVelocityTemplateEngine() {
TemplateConfigEnhance thiz = this;
VelocityTemplateEngineEnhance velocityTemplateEngineEnhance = new VelocityTemplateEngineEnhance() {
@Override
public void enhanceMap(Map, Object> objectMap) {
thiz.add(objectMap);
}
};
mpg.setTemplateEngine(velocityTemplateEngineEnhance);
//定义模板的自定义属性
}/**
*这里就是
*
* @param objectMap
*/
@SuppressWarnings("unchecked")
public void add(Map, Object> objectMap) {
TableInfoConfigEnhance table = new TableInfoConfigEnhance((TableInfo) objectMap.get("table"));
objectMap.put("package", new PackageConfigEnhance((Map, String>) objectMap.get("package")).getPackageInfo());
//替换package信息
objectMap.put("table", table);
//替换package信息}
}
源码查看
- 先从源头开始看
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
//从这里开始看
mpg.execute();
}
生成代码
- 可以看到的是
templateEngine
==null的时候才去采用模板那摸我们给他一个值就好了,也就是我们自定义的VelocityTemplateEngineEnhance
对象
/**
* 生成代码
*/
public void execute() {
// 初始化配置
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.init(this.pretreatmentConfigBuilder(config)).mkdirs().batchOutput().open();
}
继续看
- pretreatmentConfigBuilder()方法
//这段代码就是去装载模板的可以在${}里面所使用的一些属性
templateEngine.init(this.pretreatmentConfigBuilder(config));
- batchOutput 这个方法就是具体的去输出
- 主要关注
writer()
这个抽象方法,是有子类去实现的
public AbstractTemplateEngine batchOutput() {
try {
List tableInfoList = getConfigBuilder().getTableInfoList();
for (TableInfo tableInfo : tableInfoList) {
Map, Object> objectMap = getObjectMap(tableInfo);
Map, String> pathInfo = getConfigBuilder().getPathInfo();
TemplateConfig template = getConfigBuilder().getTemplate();
// 自定义内容
InjectionConfig injectionConfig = getConfigBuilder().getInjectionConfig();
if (null != injectionConfig) {
injectionConfig.initMap();
objectMap.put("cfg", injectionConfig.getMap());
List focList = injectionConfig.getFileOutConfigList();
if (CollectionUtils.isNotEmpty(focList)) {
for (FileOutConfig foc : focList) {
if (isCreate(FileType.OTHER, foc.outputFile(tableInfo))) {
//主要就是这段代码,这段代码是抽象方法,由子类去实现,将ObjectMap和一些其他参数交给具体的实现类去处理
writer(objectMap, foc.getTemplatePath(), foc.outputFile(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);
}
}
//... 还有很多自己看源码吧
}
} catch (Exception e) {
logger.error("无法创建文件,请检查配置信息!", e);
}
return this;
}public abstract void writer(Map, Object> objectMap, String templatePath, String outputFile) throws Exception;
- 那就简单了那就找子类就可以了,发现有三个子类,其实就是对应的三个模板…
文章图片
- 既然知道
writer()
由子类实现,那就好办了直接实现 这个抽象类,然后替换掉就好了.
推荐阅读
- 笔记|Mybatis---ResultMap自定义映射规则
- 1024程序员节|SpringBoot整合Mybatis-plus及自定义多表查询
- MyBatis使用resultMap自定义映射规则与关联映射
- spring|不懂SpringApplication生命周期事件(那就等于不会Spring Boot嘛)
- java项目精品实战案例|基于Java+SpringBoot+vue+element实现前后端分离蛋糕商城系统详细设计
- APIService|Spring2.5.2 经典在线教程—https://docs.spring.io/spring/docs/
- Mybatis|Mybatis-Plus入门(Mapper CRUD接口)
- mybatis|Mybatis-plus的Mapper CRUD 接口查询数据错误
- java|Mybatis-Plus通用Mapper CRUD之select