Springboot +mybatis-plus 实现代码生成器(自定义默认模板引擎)
2023-09-11 14:20:19 时间
一、前言
1.在MyBatis-Plus的官网就为我们提供了代码生成器的使用教程,它可以为完成最基本的代码生成,但是想要实现自己的效果,还需要我们自己去设置生成模板。
2.AutoGenerator
是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
3.项目架构
二、实现过程
1.添加依赖
MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:
- 添加 代码生成器 依赖
<!--mybatis-plus代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
- 添加 自定义模板引擎 依赖
<!--mybatis-plus逆向功能所需的模板引擎(自定义模板引擎)-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<!--velocity 模板引擎,Mybatis Plus 代码生成器需要(默认模板引擎)-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
注意:如果您选择了非默认引擎,需要在 AutoGenerator 中 设置模板引擎。
AutoGenerator generator = new AutoGenerator();
// set freemarker engine
generator.setTemplateEngine(new FreemarkerTemplateEngine());
// set beetl engine
generator.setTemplateEngine(new BeetlTemplateEngine());
// set custom engine (reference class is your custom engine class)
generator.setTemplateEngine(new CustomTemplateEngine());
// other config
...
2.复制maven包内的模板
maven仓库内搜索mybatis-plus-generator,打开,复制其中的templates目录至自己项目的resources下
由于我们后续使用的是FreemarkerTemplateEngine,仅用到.ftl文件,其他后缀文件可自行删除。
3.自定义模板内容
在上面模板的基础上,修改编写自己所需的模板内容:
controller.java.ftl
package ${package.Controller};
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import ${package.Entity}.${entity};
import ${package.Service}.${table.serviceName};
import java.util.Date;
<#if restControllerStyle>
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
import ${package.ModuleName}.utils.*;
/**
* ${table.comment!} 前端控制器
*
* @author ${author}
* @since ${date}
*/
@Api(tags = "${entity}API")
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
<#if kotlin>
class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
<#else>
<#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass} {
<#else>
public class ${table.controllerName} {
</#if>
@Autowired
private ${table.serviceName} service;
@ApiOperation(value = "分页列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "currentPage",value = "当前页码",paramType = "query",dataType = "int"),
@ApiImplicitParam(name = "pageSize",value = "每页显示个数",paramType = "query",dataType = "int")
})
@PostMapping(value = "/page")
public Result page(@RequestBody ${entity} entity,@RequestParam Integer currentPage,@RequestParam Integer pageSize){
Page<${entity}> page = new Page<>(currentPage,pageSize);
QueryWrapper<${entity}> queryWrapper = new QueryWrapper();
//分页查看列表
IPage<${entity}> pageInfo = service.selectPage(page,queryWrapper);
//返回结果集
return new Result().ok(new PageData<>(pageInfo.getRecords(),pageInfo.getTotal()));
}
/**
* 添加信息
*/
@PostMapping("add")
@ApiOperation("添加信息")
public Result add(@RequestBody ${entity} entity){
entity.setCreate_by(1);
entity.setCreate_time(new Date());
int n = service.add(entity);
if(n>0){
return new Result();
}else{
return new Result().error(400,"添加失败");
}
}
/**
* 编辑信息
*/
@PostMapping("update")
@ApiOperation("添加信息")
public Result update(@RequestBody ${entity} entity){
entity.setUpdate_by(1);
entity.setUpdate_time(new Date());
int n = service.update(entity);
if(n>0){
return new Result();
}else{
return new Result().error(400,"编辑失败");
}
}
/**
* 根据ids删除信息
*/
@PostMapping("del")
@ApiOperation("根据ids删除信息")
public Result del(@RequestBody Integer[] ids){
int n = service.deleteBatchIds(ids);
if(n>0){
return new Result();
}else{
return new Result().error(400,"删除失败");
}
}
}
</#if>
service.java.ftl
package ${package.Service};
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import ${package.Entity}.${entity};
import java.util.List;
/**
* <p>
* ${table.comment!} 服务类
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if kotlin>
interface ${table.serviceName} : ${superServiceClass}<${entity}>
<#else>
public interface ${table.serviceName}{
/**
* 添加信息
* @param entity
* @return
*/
int add(${entity} entity);
/**
* 编辑信息
* @param entity
* @return
*/
int update(${entity} entity);
/**
* 获取列表信息
* @param queryWrapper
* @return
*/
List<${entity}> selectList(Wrapper<${entity}> queryWrapper);
/**
* 分页获取列表信息
* @return
*/
IPage<${entity}> selectPage(Page page, Wrapper<${entity}> queryWrapper);
/**
* 批量删除商品
* @param ids
* @return
*/
int deleteBatchIds(Integer[] ids);
}
</#if>
serviceImpl.java.ftl
package ${package.ServiceImpl};
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* ${table.comment!} 服务实现类
* </p>
*
* @author ${author}
* @since ${date}
*/
@Service
<#if kotlin>
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
}
<#else>
public class ${table.serviceImplName} implements ${table.serviceName} {
@Autowired
private ${table.mapperName} mapper;
/**
* 添加信息
* @param entity
* @return
*/
@Override
public int add(${entity} entity) {
return mapper.insert(entity);
}
/**
* 编辑信息
* @param entity
* @return
*/
@Override
public int update(${entity} entity) {
return mapper.updateById(entity);
}
/**
* 获取列表信息
* @param queryWrapper
* @return
*/
@Override
public List<${entity}> selectList(Wrapper<${entity}> queryWrapper) {
return mapper.selectList(queryWrapper);
}
/**
* 分页获取列表信息
* @param page
* @param queryWrapper
* @return
*/
@Override
public IPage<${entity}> selectPage(Page page, Wrapper<${entity}> queryWrapper) {
return mapper.selectMapsPage(page,queryWrapper);
}
/**
* 批量删除
* @param ids
* @return
*/
@Override
public int deleteBatchIds(Integer[] ids){
return mapper.deleteBatchIds(Arrays.asList(ids));
}
}
</#if>
mapper.java.ftl
package ${package.Mapper};
import ${package.Entity}.${entity};
import ${superMapperClassPackage};
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* ${table.comment!} Mapper 接口
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if kotlin>
interface ${table.mapperName} : ${superMapperClass}<${entity}>
<#else>
@Mapper
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
}
</#if>
entity.java.ftl
package ${package.Entity};
<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if swagger2>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
</#if>
<#if entityLombokModel>
import lombok.Data;
import lombok.EqualsAndHashCode;
<#if chainModel>
import lombok.experimental.Accessors;
</#if>
</#if>
/**
* <p>
* ${table.comment!}
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if entityLombokModel>
@Data
<#if superEntityClass??>
@EqualsAndHashCode(callSuper = true)
<#else>
@EqualsAndHashCode(callSuper = false)
</#if>
<#if chainModel>
@Accessors(chain = true)
</#if>
</#if>
<#if table.convert>
@TableName("${table.name}")
</#if>
<#if swagger2>
@ApiModel(value="${entity}对象", description="${table.comment!}")
</#if>
<#if superEntityClass??>
public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
<#elseif activeRecord>
public class ${entity} extends Model<${entity}> {
<#else>
public class ${entity} implements Serializable {
</#if>
<#if entitySerialVersionUID>
private static final long serialVersionUID = 1L;
</#if>
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field>
<#if field.keyFlag>
<#assign keyPropertyName="${field.propertyName}"/>
</#if>
<#if field.comment!?length gt 0>
<#if swagger2>
@ApiModelProperty(value = "${field.comment}")
<#else>
/**
* ${field.comment}
*/
</#if>
</#if>
<#if field.keyFlag>
<#-- 主键 -->
<#if field.keyIdentityFlag>
@TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
<#elseif idType??>
@TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
<#elseif field.convert>
@TableId("${field.annotationColumnName}")
</#if>
<#-- 普通字段 -->
<#elseif field.fill??>
<#-- ----- 存在字段填充设置 ----->
<#if field.convert>
@TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
<#else>
@TableField(fill = FieldFill.${field.fill})
</#if>
<#elseif field.convert>
@TableField("${field.annotationColumnName}")
</#if>
<#-- 乐观锁注解 -->
<#if (versionFieldName!"") == field.name>
@Version
</#if>
<#-- 逻辑删除注解 -->
<#if (logicDeleteFieldName!"") == field.name>
@TableLogic
</#if>
private ${field.propertyType} ${field.propertyName};
</#list>
<#------------ END 字段循环遍历 ---------->
<#if !entityLombokModel>
<#list table.fields as field>
<#if field.propertyType == "boolean">
<#assign getprefix="is"/>
<#else>
<#assign getprefix="get"/>
</#if>
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
<#if chainModel>
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
<#else>
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
</#if>
this.${field.propertyName} = ${field.propertyName};
<#if chainModel>
return this;
</#if>
}
</#list>
</#if>
<#if entityColumnConstant>
<#list table.fields as field>
public static final String ${field.name?upper_case} = "${field.name}";
</#list>
</#if>
<#if activeRecord>
@Override
protected Serializable pkVal() {
<#if keyPropertyName??>
return this.${keyPropertyName};
<#else>
return null;
</#if>
}
</#if>
<#if !entityLombokModel>
@Override
public String toString() {
return "${entity}{" +
<#list table.fields as field>
<#if field_index==0>
"${field.propertyName}=" + ${field.propertyName} +
<#else>
", ${field.propertyName}=" + ${field.propertyName} +
</#if>
</#list>
"}";
}
</#if>
}
mapper.xml.ftl
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${package.Mapper}.${table.mapperName}">
<#if enableCache>
<!-- 开启二级缓存 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
</#if>
<#if baseResultMap>
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="${package.Entity}.${entity}">
<#list table.fields as field>
<#if field.keyFlag><#--生成主键排在第一位-->
<id column="${field.name}" property="${field.propertyName}" />
</#if>
</#list>
<#list table.commonFields as field><#--生成公共字段 -->
<result column="${field.name}" property="${field.propertyName}" />
</#list>
<#list table.fields as field>
<#if !field.keyFlag><#--生成普通字段 -->
<result column="${field.name}" property="${field.propertyName}" />
</#if>
</#list>
</resultMap>
</#if>
<#if baseColumnList>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
<#list table.commonFields as field>
${field.columnName},
</#list>
${table.fieldNames}
</sql>
</#if>
</mapper>
4.编写代码生成器代码
package com.example.mybatisgenerator.utils;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
/**
* @author qzz
*/
public class CodeGenerateUtils {
/**
* 运行main方法进行代码生成
* @param args
*/
public static void main(String[] args) {
//1.创建代码生成器
AutoGenerator autoGenerator = new AutoGenerator();
//2.全局配置
GlobalConfig gc = new GlobalConfig();
//String projectPath = System.getProperty("user.dir");
//建议直接使用项目绝对路径,以防相对路径找不到出错
gc.setOutputDir("D:\\generator" + "/src/main/java");
//作者
gc.setAuthor("admin");
//生成后是否打开资源管理员
gc.setOpen(false);
//重新生成时文件是否覆盖
gc.setFileOverride(true);
//主键策略
gc.setIdType(IdType.AUTO);
//定义生成的实体类中日期类型
gc.setDateType(DateType.ONLY_DATE);
//开启swagger2模式(Swagger和项目整合用于请求测试)
gc.setSwagger2(true);
//自定义文件命名 注意 %s 会自动填充表实体属性
gc.setControllerName("%sController");
gc.setServiceName("%sService");
gc.setServiceImplName("%sServiceImpl");
gc.setMapperName("%sMapper");
gc.setXmlName("%sMapper");
autoGenerator.setGlobalConfig(gc);
//3.数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/db_test?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);
autoGenerator.setDataSource(dsc);
//4.包配置
PackageConfig pc = new PackageConfig();
//模块名
pc.setParent("com.example");
pc.setModuleName("mybatisgenerator");
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setServiceImpl("service.impl");
pc.setMapper("mapper");
autoGenerator.setPackageInfo(pc);
//5.策略配置
StrategyConfig strategy = new StrategyConfig();
//填写表名,帮助生成实体类等mapper相应代码
strategy.setInclude("test_user");
//数据库表映射到实体的命名策略
strategy.setNaming(NamingStrategy.underline_to_camel);
//生成实体时去掉表前缀
strategy.setTablePrefix(pc.getModuleName()+"_");
//数据库表字段映射到实体的命名策略
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setEntityLombokModel(true);
//restful api 风格控制器
strategy.setRestControllerStyle(true);
//url 中驼峰转连字符
strategy.setControllerMappingHyphenStyle(true);
autoGenerator.setStrategy(strategy);
//6.配置自定义模板
//设置模板引擎 注意!如果您选择了非默认引擎,需要在 AutoGenerator 中 设置模板引擎
autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
// 配置自定义输出模板
//指定自定义模板路径, 位置:/resources/templates/entity.java.ftl(或者是.vm)
// 注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setController("/templates/controller.java");
templateConfig.setService("/templates/service.java");
templateConfig.setServiceImpl("/templates/serviceImpl.java");
templateConfig.setMapper("/templates/mapper.java");
templateConfig.setEntity("/templates/entity.java");
templateConfig.setXml("/templates/mapper.xml");
autoGenerator.setTemplate(templateConfig);
//6.执行
autoGenerator.execute();
}
}
5.测试运行
6.controller模板内的用到的工具类
响应数据:
package com.example.mybatisgenerator.utils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
/**
* 响应数据
* @author qzz
*/
@ApiModel("Result响应")
public class Result<T> implements Serializable {
private static final long serialVersionUID=1L;
/**
* 编码 0:成功 其他值代表失败
*/
@ApiModelProperty(value="编码 0:成功 其他值代表失败")
private int code = 0;
/**
* 消息内容
*/
@ApiModelProperty(value="消息内容")
private String msg = "success";
/**
* 响应数据
*/
@ApiModelProperty(value="响应数据")
private T data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Result<T> ok (T data){
this.setData(data);
return this;
}
public Result<T> error(){
this.code = 500;
this.msg="网络出错,请联系系统管理员";
return this;
}
public Result<T> error(int code,String msg){
this.code = code;
this.msg=msg;
return this;
}
public boolean success(){
return code == 0 ? true : false;
}
}
分页工具类:
package com.example.mybatisgenerator.utils;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 分页工具类
* @author qzz
*/
@Data
public class PageData<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总记录数
*/
private int total;
/**
* 列表数据
*/
private List<T> list;
public PageData(List<T> list, long total){
this.list = list ;
this.total = (int) total;
}
}
三、代码源码
可点击此处进行下载
相关文章
- SpringBoot word文件转pdf
- 关于java中redis操作直接使用jedis和使用springboot封装的RedisTemplate效率对比和主要区别
- SpringBoot:Windows平台下JAR包的启动,停止和日志分割脚本
- B站(云e办)SpringBoot实战练习的Sql文件、前端Vue源码、后端springboot源码
- SpringBoot配置图片访问404SpringBoot配置图片访问路径springboot如何访问图片
- SpringBoot配置自定义包扫描
- SpringBoot是怎么处理请求的
- 每天一个新知识之 SpringBoot+Dubbo 的快速入门
- springboot每个web请求是一个线程吗?
- 《SpringBoot篇》26.SpringBoot整合Jackson超详细教程(附Jackson工具类)
- 《SpringBoot篇》01.Springboot超详细入门(基础篇)
- springboot+redis
- SpringBoot整合Thymleaf实现页面静态化
- SpringBoot中使用@Repository 与 @Mapper的区别
- SpringBoot视图模板库
- SpringBoot开发中的坑 记录一些
- SpringBoot使用thymeleaf模板引擎
- SpringBoot thymeleaf模板版本,thymeleaf模板更换版本
- springboot +nginx +freemarker 模板的简单集成
- spring、springMvc、springBoot和springCloud的联系与区别
- 基于springboot+vue的“考研资讯平台”程序设计实现【毕业论文,源码】
- springBoot项目配置错误问题-@EnableWebMvc注解问题导致SpringBoot默认配置失效
- 浅析SpringBoot使用@RequestBody搭配@Data的注意点
- 基于SpringBoot的金刚模板化接口自动化测试项目(开源)
- springboot+vue点餐平台网站(java源码+文档)
- SpringBoot导出Word方式一:根据Word模板动态生成word(Poi-tl)
- 微信小程序 | 微信公众平台SpringBoot开发实例 │ 模板消息的应用开发
- docker部署SpringBoot项目
- SpringBoot整合Servlet的两种方式
- Java SpringBoot Beetl模板
- SPRINGBOOT配置事物注解和@MAPPER注意
- idea创建web项目,springboot项目,maven项目