随着项目节奏越来越快,为了减少把时间浪费在新建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>
@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模版代码
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模版:
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的模版也出一个教程。