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依赖:

java 复制代码
  <!--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-->

构建代码:

java 复制代码
 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模版代码,已经调试过输出美化内容,有需要的可以直接复制

java 复制代码
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>
    @Serial
    private 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模版代码

java 复制代码
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>
    @Serial
    private 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模版:

java 复制代码
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>
    @Serial
    private 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的模版也出一个教程。

相关推荐
cmdch20177 小时前
Mybatis加密解密查询操作(sql前),where要传入加密后的字段时遇到的问题
数据库·sql·mybatis
王ASC8 小时前
SpringMVC的URL组成,以及URI中对/斜杠的处理,解决IllegalStateException: Ambiguous mapping
java·mvc·springboot·web
撒呼呼8 小时前
# 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)
数据库·spring boot·spring·mvc·springboot
秋恬意10 小时前
什么是MyBatis
mybatis
CodeChampion10 小时前
60.基于SSM的个人网站的设计与实现(项目 + 论文)
java·vue.js·mysql·spring·elementui·node.js·mybatis
灰色孤星A15 小时前
瑞吉外卖项目学习笔记(四)@TableField(fill = FieldFill.INSERT)公共字段填充、启用/禁用/修改员工信息
java·学习笔记·springboot·瑞吉外卖·黑马程序员·tablefield·公共字段填充
ZWZhangYu1 天前
【MyBatis源码分析】使用 Java 动态代理,实现一个简单的插件机制
java·python·mybatis
程序员大金1 天前
基于SSM+Vue的个性化旅游推荐系统
前端·vue.js·mysql·java-ee·tomcat·mybatis·旅游
奔跑草-2 天前
【服务器】MyBatis是如何在java中使用并进行分页的?
java·服务器·mybatis
秋恬意2 天前
接口绑定有几种实现方式
mybatis