mybatis|mybatis-plus-自定义模板

【mybatis|mybatis-plus-自定义模板】
文章目录

  • 自定义模板
  • GIT 地址
  • 关注点
  • 生成的代码调用流程
  • 生成器
    • 我写到这里我在想要不要把所有代码都贴出来...
    • 自定义配置
      • 定义接口
      • 定义上下文
      • 具体的模板我就不贴了
    • 代码生成具体的类
    • Pack配置
    • 表的相关信息
    • 将上面的两个config主要到Map中
  • 源码查看
    • 生成代码
    • 继续看

自定义模板
  • 由于公司需求,好吧由于本人比较懒,不愿意写代码,估采用代码生成器的方式来解决我的痛点
  • 官方的代码生成器已经够好了但是还是不太符合我的要求,那咋能自己改吧改吧呗
  • 拥有 一键生成增、删、改、查、分页功能还有导入导出等…
  • 具体的模板参考GitHub
  • 如需特殊生成,联系我,免费给你加~~
GIT 地址
  • 自己下去吧
https://github.com/myliwenbo/Springboot/tree/master/springboot/springboot-mybatis-plus-generator
关注点
  • VelocityTemplateEngineEnhance 这个是具体的生成代码的,
生成的代码调用流程
  • MD mermaid图太难了…我直接贴图了
链接 调用 调用 调用 调用 Controller Manager Service Dao Mapper XML
  • 具体代码的流程
    mybatis|mybatis-plus-自定义模板
    文章图片
生成器
  • 由于官方的代码都放在了一个类中,个人强迫症都进行了规整处理
  • 我将官方的进行了拆分,看起来好学习一点,这个代码生成器,主要使用的是自定义模板比较多
/** * 生成器 */ 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;

  • 那就简单了那就找子类就可以了,发现有三个子类,其实就是对应的三个模板…
    mybatis|mybatis-plus-自定义模板
    文章图片
  • 既然知道writer() 由子类实现,那就好办了直接实现 这个抽象类,然后替换掉就好了.

    推荐阅读