Mybatis-plus-Generator 3.5.5 自定义模板支持 (DTO/VO 等) 配置
随着项目节奏越来越快,为了减少把时间浪费在新建DTO 、VO 等地方,直接直接基于Mybatis-plus 这颗大树稍微扩展一下,在原来生成PO、 DAO、Service、ServiceImpl、Controller 基础新增。为了解决这个问题,网上找了一堆资料,发现都是老版本的,都是基于老的AutoGenerator ,里面配置非常臃肿,基于FastAutoGenerator 链式实现没有,通过Mybatis-Plus官方文档发现两个核心配置注入配置 (InjectionConfig),下面是官方文档解释

上面是官方文档的案例,存在两个问题,一个并没有other这个属性,第二个框生成的DTO实体会在系统parent目录下。本着要弄就要完美的执着,通过一下午翻阅mybatis-plus-generator 的源码,终于找到定位输出目录类配置CustomFile。下面直接上代码
POM依赖:
<!--gen code start--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.5</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.33</version></dependency><!--gen code ebd-->
构建代码:
FastAutoGenerator.create("jdbc:mysql://xxxx:63306/diboot","diboot", "xxx")//全局配置.globalConfig(builder -> {builder.outputDir(Paths.get(System.getProperty("user.dir")) + "/src/main/java").author("xxx").build();})//包配置.packageConfig(builder -> {builder.parent("com.example.demo").entity("model.po").service("biz").serviceImpl("biz").mapper("dao")// .xml("dao.xml").controller("api.back").build();})//表策略配置.strategyConfig(builder -> {builder.enableSkipView().disableSqlFilter().addTablePrefix("biz_", "sys_").addInclude("biz_article").build();})//entity策略.strategyConfig(builder -> {builder.entityBuilder().idType(IdType.ASSIGN_ID).superClass(BaseModel.class).disableSerialVersionUID().enableRemoveIsPrefix().enableLombok().addIgnoreColumns("is_deleted", "create_time", "update_time").build();})//controller 策略.strategyConfig(builder -> {builder.controllerBuilder().enableHyphenStyle().enableRestStyle().formatFileName("%sController").build();})//Service 策略.strategyConfig(builder -> {builder.serviceBuilder().superServiceClass(IService.class).superServiceImplClass(ServiceImpl.class).formatServiceFileName("%sService").formatServiceImplFileName("%sServiceImpl").build();})//mapper 策略.strategyConfig(builder -> {builder.mapperBuilder().superClass(BaseMapper.class).mapperAnnotation(Repository.class).enableBaseResultMap().enableBaseColumnList().formatMapperFileName("%sMapper").build();})//注入自定义配置.injectionConfig(builder -> {/**自定义生成模板参数,在ftl模版里取值使用**/Map<String,Object> data = new HashMap<>();data.put("entityBuilderModel", true);data.put("chainModel", true);data.put("swagger",true);data.put("entitySerialVersionUID",true);data.put("entityLombokModel", true);builder.customMap(data);List<CustomFile> customFiles = new ArrayList();/**DTO实体**/CustomFile updateInputFile = new CustomFile.Builder().fileName("UpdateInput.java")//生成java文件名称,要和ftl模版里的文件名保持一致.templatePath("/templates/UpdateInput.java.ftl")//实体模板位置.packageName("model.dto")//生成文件包名.build();customFiles.add(updateInputFile);CustomFile addInputFile = new CustomFile.Builder().fileName("AddInput.java").templatePath("/templates/AddInput.java.ftl").packageName("model.dto").build();/**Vo实体**/CustomFile customFileVO = new CustomFile.Builder().fileName("VO.java").templatePath("/templates/VO.java.ftl").packageName("model.vo").build();customFiles.add(customFileVO);customFiles.add(addInputFile);builder.customFile(customFiles);}).templateEngine(new FreemarkerTemplateEngine()).execute();
DTO ftl模版,为了测地解决不需要修改生成实体,根据数据库字段注释生成实体字段注释,根据数据库字段是否允许为空 加上NotBlank 或者 NotNull 以及 @ApiModelProperty 的required 的条件
新增DTO模版代码,已经调试过输出美化内容,有需要的可以直接复制
package ${package.Parent}.model.dto;
<#if swagger>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
</#if>
<#if entityLombokModel>
import lombok.Getter;
import lombok.Setter;<#if chainModel>
import lombok.experimental.Accessors;</#if>
</#if>
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.io.Serializable;
import java.io.Serial;
import java.time.*;
/**
* <p>* ${table.comment!}* </p>
*
* @author ${author}
* @since ${date}
*/
<#if entityLombokModel>
@Getter
@Setter<#if chainModel>
@Accessors(chain = true)</#if>
</#if>
<#if swagger>@ApiModel(description = "${table.comment!}")
</#if>
public class ${entity}AddInput implements Serializable {
<#if entitySerialVersionUID>@Serialprivate static final long serialVersionUID = 1L;
</#if>
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field><#if !field.keyFlag && field.propertyName!="tenantId"&&field.propertyName!="museumId"><#--不是主键、不是租户ID 输出--><#if field.comment!?length gt 0><#if field.metaInfo.nullable>@ApiModelProperty(value="${field.comment}")<#else>@ApiModelProperty(value="${field.comment}",required = true)<#if field.propertyType=="string">@NotBlank(message = "${field.comment}不能为空")<#else>@NotNull(message = "${field.comment}不能为空")</#if></#if></#if>private ${field.propertyType} ${field.propertyName};</#if>
</#list>
<#------------ END 字段循环遍历 ---------->
}
生成效果图:自动加上参数校验

修改DTO模版代码
package ${package.Parent}.model.dto;
<#if swagger>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
</#if>
<#if entityLombokModel>
import lombok.Getter;
import lombok.Setter;<#if chainModel>
import lombok.experimental.Accessors;</#if>
</#if>
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.io.Serializable;
import java.io.Serial;
import java.time.*;
/**
* <p>* ${table.comment!}* </p>
*
* @author ${author}
* @since ${date}
*/
<#if entityLombokModel>
@Getter
@Setter<#if chainModel>
@Accessors(chain = true)</#if>
</#if>
<#if swagger>@ApiModel(description = "${table.comment!}")
</#if>
public class ${entity}UpdateInput implements Serializable {
<#if entitySerialVersionUID>@Serialprivate static final long serialVersionUID = 1L;
</#if>
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field><#if field.propertyName!="tenantId"&&field.propertyName!="museumId"><#--不是租户ID 输出--><#if field.comment!?length gt 0><#if field.metaInfo.nullable>@ApiModelProperty(value="${field.comment}")<#else>@ApiModelProperty(value="${field.comment}",required = true)<#if field.propertyType=="string">@NotBlank(message = "${field.comment}不能为空")<#else>@NotNull(message = "${field.comment}不能为空")</#if></#if></#if>private ${field.propertyType} ${field.propertyName};</#if>
</#list>
<#------------ END 字段循环遍历 ---------->
}
生成效果图:

VO模版:
package ${package.Parent}.model.vo;
<#if swagger>import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;
</#if>
<#if entityLombokModel>import lombok.Getter;import lombok.Setter;<#if chainModel>import lombok.experimental.Accessors;</#if>
</#if>
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.io.Serializable;
import java.io.Serial;
import java.time.*;
/**
* <p>* ${table.comment!}* </p>
*
* @author ${author}
* @since ${date}
*/
<#if entityLombokModel>
@Getter
@Setter<#if chainModel>
@Accessors(chain = true)</#if>
</#if>
<#if swagger>@ApiModel(description = "${table.comment!}")
</#if>
public class ${entity}VO implements Serializable {
<#if entitySerialVersionUID>@Serialprivate static final long serialVersionUID = 1L;
</#if>
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field><#if field.propertyName!="tenantId"&&field.propertyName!="museumId"><#--不是租户ID 输出--><#if field.comment!?length gt 0>@ApiModelProperty(value="${field.comment}")</#if>private ${field.propertyType} ${field.propertyName};</#if>
</#list>
<#------------ END 字段循环遍历 ---------->
}
效果图:

项目结构截图:

能看到这里应该有个大概的了解了,既然能生成自定义DTO 和 VO,那我们完全也可以覆盖之前的默认Service,将生成好的 DTO 和VO 放入 Service 模版里,然后将Service模版里 放入Controller模版里,那我们一次性就可以把 PO VO DTO 以及 Service 里增删改查 全部实现,并放到 Controller接口 ,那常用的业务基本上就可以使用了,接口上加上一些权限 注解和日志注解。如果有些特殊的逻辑再生成的service调整即可。后续有时间,把Service的模版也出一个教程。
相关文章:
Mybatis-plus-Generator 3.5.5 自定义模板支持 (DTO/VO 等) 配置
随着项目节奏越来越快,为了减少把时间浪费在新建DTO 、VO 等地方,直接直接基于Mybatis-plus 这颗大树稍微扩展一下,在原来生成PO、 DAO、Service、ServiceImpl、Controller 基础新增。为了解决这个问题,网上找了一堆资料ÿ…...
C#环境下MAC地址获取方法解析
在C#中,获取MAC地址并不是直接支持的,因为出于安全和隐私的考虑,操作系统通常会限制对这类硬件信息的直接访问。不过,仍然可以通过一些方法间接地获取到本地网络接口(比如以太网接口)的MAC地址。 以下是几…...
(k8s)Kubernetes 从0到1容器编排之旅
一、引言 在当今数字化的浪潮中,Kubernetes 如同一艘强大的航船,引领着容器化应用的部署与管理。它以其卓越的灵活性、可扩展性和可靠性,成为众多企业和开发者的首选。然而,要真正发挥 Kubernetes 的强大威力,仅仅掌握…...
Rust Web开发框架对比:Warp与Actix-web
文章目录 Rust Web开发框架对比:Warp与Actix-web引言框架概述Warp框架简介Actix-web框架简介 设计理念Warp的设计理念Actix-web的设计理念 性能比较可扩展性和生态插件和中间件支持社区和文档 使用示例使用Warp构建简单的HTTP服务使用Actix-web构建简单的HTTP服务 学…...
F12抓包12:Performance(性能)前端性能分析
课程大纲 使用场景: ① 前端界面加载性能测试。 ② 导出性能报告给前端开发。 复习:后端(接口)性能分析 ① 所有请求耗时时间轴:“网络”(Network) - 概览。 ② 单个请求耗时:“网络”(Network…...
数据结构(Day13)
一、学习内容 内存空间划分 1、一个进程启动后,计算机会给该进程分配4G的虚拟内存 2、其中0G-3G是用户空间【程序员写代码操作部分】【应用层】 3、3G-4G是内核空间【与底层驱动有关】 4、所有进程共享3G-4G的内核空间,每个进程独立拥有0G-3G的用户空间 …...
链表的快速排序(C/C++实现)
一、前言 大家在做需要排名的项目的时候,需要把各种数据从高到低排序。如果用的快速排序的话,处理数组是十分简单的。因为数组的存储空间的连续的,可以通过下标就可以简单的实现。但如果是链表的话,内存地址是随机分配的…...
css总结(记录一下...)
文字 语法说明word-wrapword-wrap:normal| break-word normal:使用浏览器默认的换行 break-word:允许在单词内换行 text-overflow clip:修剪文本 ellipsis:显示省略符号来代表被修剪的文本 text-shadow可向文本应用的阴影。能够规定水平阴影、垂直阴影、模糊距离,以…...
SpringBoot 处理 @KafkaListener 消息
消息监听容器 1、KafkaMessageListenerContainer 由spring提供用于监听以及拉取消息,并将这些消息按指定格式转换后交给由KafkaListener注解的方法处理,相当于一个消费者; 看看其整体代码结构: 可以发现其入口方法为doStart(),…...
Spring Boot-API版本控制问题
在现代软件开发中,API(应用程序接口)版本控制是一项至关重要的技术。随着应用的不断迭代,API 的改动不可避免,如何在引入新版本的同时保证向后兼容,避免对现有用户的影响,是每个开发者需要考虑的…...
Git 提取和拉取的区别在哪
1. 提取(Fetch) 操作说明:Fetch 操作会从远程仓库下载最新的提交、分支信息等,但不会将这些更改合并到你当前的分支中。它只是将远程仓库的更新信息存储在本地,并不会自动修改你当前的工作区。 使用场景: …...
【数据结构与算法 | 每日一题 | 力扣篇】力扣2390, 2848
1. 力扣2390:从字符串中删除星号 1.1 题目: 给你一个包含若干星号 * 的字符串 s 。 在一步操作中,你可以: 选中 s 中的一个星号。移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。 返回移除 所有 星号之…...
破解信息架构实施的密码:常见挑战与最佳解决方案全指南
信息架构的成功实施是企业数字化转型的关键步骤,但在实际操作中,企业往往会遇到各种复杂的挑战。这些挑战包括 技术整合的难度、数据管理的复杂性、合规性要求的变化 以及 资源限制 等。《信息架构:商业智能&分析与元数据管理参考模型》为…...
CodeChef Starters 151 (Div.2) A~D
codechef是真敢给分,上把刚注册,这把就div2了,再加上一周没打过还是有点不适应的,好在最后还是能够顺利上分 今天的封面是P3R的设置菜单 我抠出来做我自己的游戏主页了( A - Convert string 题意 在01串里面可以翻转…...
Redis学习——数据不一致怎么办?更新缓存失败了又怎么办?
文章目录 引言正文读写缓存的数据一致性只读缓存的数据一致性删除和修改数据不一致问题操作执行失败导致数据不一致解决办法 多线程访问导致数据不一致问题总结 总结参考信息 引言 最近面试快手的时候被问到了缓存不一致怎么解决?一开始还是很懵的,因为…...
跨境电商代购新纪元:一键解锁全球好物,系统流程全揭秘
添加图片注释,不超过 140 字(可选) 在全球化日益加深的今天,跨境电商代购成为了连接消费者与世界各地优质商品的桥梁。本文将在CSDN平台上,深入剖析跨境电商代购系统的功能流程,带您一窥其背后的技术奥秘与…...
Mac 上终端使用 MySql 记录
文章目录 下载安装终端进入 MySql常用操作查看数据库选择一个数据库查看当前选择的数据库Navcat 打开提示报错参考文章 下载安装 先下载社区版的 MySql 安装的过程需要设置 root 的密码,这个是要进入数据库所设定的,所以要记住 终端进入 MySql 首先输…...
461. 汉明距离
一:题目: 两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。 给你两个整数 x 和 y,计算并返回它们之间的汉明距离。 示例 1: 输入:x 1, y 4 输出:2 解释: 1 (0 0…...
开发指南061-nexus权限管理
平台后台服务的核心是组件,管理组件的软件有: Apache的Archiva、JFrog的Artifactory、Sonatype的Nexus。 本平台选择nexus。nexus的权限模型是用户-角色-权限体系:通过组合权限定义角色,通过给用户赋角色来赋权限。有关nexus的权…...
Qt 弹出菜单右键菜单 QMenu 设置不同颜色的子项
概述 在Qt中,可以使用样式表(StyleSheet)来自定义 QMenu 的外观,包括其子项(如菜单项QAction)的颜色。但是,这通常可以设置 QMenu 的整体样式,而不能单独设置某个子项的颜色。不过&…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
