Fork me on GitHub

MP代码生成器

官网

MyBatis-Plus + FastAutoGenerator + Freemarker 模板体系代码生成
https://baomidou.com/reference/new-code-generator-configuration/

一、POM 依赖

<dependencies>
    <!-- MyBatis-Plus 依赖 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.5</version>
    </dependency>

    <!-- MyBatis-Plus Generator -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.5.5</version>
    </dependency>

    <!-- FreeMarker 模板引擎 -->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.32</version>
    </dependency>

    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
    </dependency>
</dependencies>

二、CodeGenerator代码生成

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

public class CodeGenerator {

    /* ========== 常改参数 START ========== */
    // 数据库配置
    private static final String DB_URL = "jdbc:mysql://IP:3306/DBNAME?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&zeroDateTimeBehavior=convertToNull";
    private static final String DB_USERNAME = "root";
    private static final String DB_PASSWORD = "root";

    // 作者信息
    private static final String AUTHOR = "秋";

    // 父包名(会拼接 entity、mapper、service 等)
    private static final String PARENT_PACKAGE = "com.baomidou.mybatisplus";

    // 模块名(会拼到输出路径)
    private static final String MODULE_NAME = "autumn-module-manage";

    // 需要生成的表(支持多个)
    private static final List<String> TABLES = Arrays.asList("user", "role");

    // 是否使用 Freemarker 模板
    private static final boolean USE_FREEMARKER = true;
    /* ========== 常改参数 END ========== */

    public static void main(String[] args) {

        // 输出路径
        String outputDir = Paths.get(System.getProperty("user.dir"))
                + "/" + MODULE_NAME + "/src/main/java";

        FastAutoGenerator.create(DB_URL, DB_USERNAME, DB_PASSWORD)
                // ========== 全局配置 ==========
                .globalConfig(builder -> builder
                        .author(AUTHOR)  // 设置作者
                        .dateType(DateType.ONLY_DATE)  // 设置日期类型
                        .commentDate("yyyy-MM-dd")  // 设置注释日期格式
                        .outputDir(outputDir)  // 设置输出目录
                        .enableSwagger()  // 启用 Swagger 模式
                )

                // ========== 包配置 ==========
                .packageConfig(builder -> builder
                        .parent(PARENT_PACKAGE)
                        .entity("entity")
                        .mapper("mapper")
                        .service("service")
                        .serviceImpl("service.impl")
                        .xml("mapper.xml")
                )

                // ========== 策略配置 ==========
                .strategyConfig(builder -> builder
                        .addInclude(TABLES) // 多表生成,设置需要生成的表名
                        .controllerBuilder()
                            .enableRestStyle() // REST 风格
                            .enableHyphenStyle() // 驼峰转连字符
                        .serviceBuilder()
                          //.enableFileOverride() // 覆盖已有文件
                        .entityBuilder()
                            .enableLombok() // 启用 Lombok
                            .enableTableFieldAnnotation() // 开启字段注解
                            .enableFileOverride() // 覆盖已有文件
                        .mapperBuilder()
                            .enableBaseResultMap()     // ✅ 开启 BaseResultMap 生成
                            .enableBaseColumnList()    // ✅ 开启 BaseColumnList 生成
                )

                // ========== 模板配置(可选) ==========
                .templateConfig(builder -> {
                    builder.controller("/templates/controller.java");
                    // 如果以后想自定义 Service、Mapper、XML 模板,可以解开下面的注释
                    // .service("/templates/service.java")
                    // .serviceImpl("/templates/serviceImpl.java")
                    // .entity("/templates/entity.java")
                    // .mapper("/templates/mapper.java")
                    // .xml("/templates/mapper.xml")
                })

                // ========== 模板引擎(Freemarker模版) ==========
                .templateEngine(USE_FREEMARKER
                        ? new FreemarkerTemplateEngine()
                        : new com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine()
                )

                .execute();
    }
}

三、自定义 Freemarker 模板(可选)

这步不写也行,只是生成的controller内容为空
新建目录:

src/main/resources/templates/

空模版文件
https://github.com/baomidou/generator/blob/develop/mybatis-plus-generator/src/main/resources/templates/controller.java.ftl

controller.java.ftl(带分页)

在该目录下创建 controller.java.ftl,内容如下:

package ${package.Controller};

import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};


/**
* ${table.comment!} 控制器
*/
@RestController
@RequestMapping("/${table.entityPath}")
public class ${table.controllerName} {

    @Autowired
    private ${table.serviceName} ${table.serviceName?uncap_first};

    @GetMapping("/list")
    public List<${entity}> list() {
        return ${table.serviceName?uncap_first}.list();
    }

    /**
     * 分页查询
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param query 查询条件 默认全部equal
     * @return 分页结果
     */
    @GetMapping("/page")
    public IPage<${entity}> page(
    @RequestParam(defaultValue = "1") int pageNum,
    @RequestParam(defaultValue = "10") int pageSize,
    ${entity} query) {
        return ${table.serviceName?uncap_first}.page(
            new Page<>(pageNum, pageSize),
            new QueryWrapper<>(query)
        );
    }

    @GetMapping("/pageList")
    public IPage<${entity}> pageList(
    @RequestParam(defaultValue = "1") int pageNum,
    @RequestParam(defaultValue = "10") int pageSize,
    ${entity} query) {
        LambdaQueryWrapper<${entity}> wrapper = new LambdaQueryWrapper<>();
        // 如果有 name 字段,自动模糊查询
<#--    <#if table.fields?seq_contains("name")>-->
        wrapper.like(query.getName() != null && !query.getName().trim().isEmpty(),
        ${entity}::getName, query.getName());
<#--    </#if>-->
        return ${table.serviceName?uncap_first}.page(new Page<>(pageNum, pageSize), wrapper);
    }

    @GetMapping("/{id}")
    public ${entity} getById(@PathVariable Long id) {
        return ${table.serviceName?uncap_first}.getById(id);
    }

    @PostMapping("/add")
    public boolean add(@RequestBody ${entity} entity) {
        return ${table.serviceName?uncap_first}.save(entity);
    }

    @PutMapping("/update")
    public boolean update(@RequestBody ${entity} entity) {
        return ${table.serviceName?uncap_first}.updateById(entity);
    }

    @DeleteMapping("/delete/{id}")
    public boolean delete(@PathVariable Long id) {
        return ${table.serviceName?uncap_first}.removeById(id);
    }
}

分页配置文件

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // MySQL 使用 MySqlDialect
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

service.java.ftl

package ${package.Service};

import com.baomidou.mybatisplus.core.metadata.IPage;
import ${package.Entity}.${entity};
import ${superServiceClassPackage};

/**
 * <p>
 * ${table.comment!} 服务类
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if kotlin>
interface ${table.serviceName} : ${superServiceClass}<${entity}>
<#else>
public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {

    /**
    * 分页查询
    * @param pageNum 页码
    * @param pageSize 每页大小
    * @param query 查询条件
    * @return 分页结果
    */
    IPage<${entity}> pageList(int pageNum, int pageSize, ${entity} query);
}
</#if>

serviceImpl.java.ftl

package ${package.ServiceImpl};

import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
import ${superServiceImplClassPackage};
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

/**
 * <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} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {

    @Override
    public IPage<${entity}> pageList(int pageNum, int pageSize, ${entity} query) {
        return this.page(
            new Page<>(pageNum, pageSize),
            new QueryWrapper<>(query)
        );
    }
}
</#if>

entity.java.ftl

package ${package.Entity};

<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if springdoc>
import io.swagger.v3.oas.annotations.media.Schema;
<#elseif 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>

/**
 * <p>
 * ${table.comment!}
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if entityLombokModel>
@Getter
@Setter
    <#if chainModel>
@Accessors(chain = true)
    </#if>
</#if>
<#if table.convert>
@TableName("${schemaName}${table.name}")
</#if>
<#if springdoc>
@Schema(name = "${entity}", description = "$!{table.comment}")
<#elseif swagger>
@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}> {
<#elseif entitySerialVersionUID>
public class ${entity} implements Serializable {
<#else>
public class ${entity} {
</#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 springdoc>
    @Schema(description = "${field.comment}")
        <#elseif swagger>
    @ApiModelProperty("${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 field.versionField>
    @Version
    </#if>
    <#-- 逻辑删除注解 -->
    <#if field.logicDeleteField>
    @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
    public 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.java.ftl

默认生成的不带@Mapper注解,也可以在启动类上添加@MapperScan注解。
然后再启动类上添加注解@MapperScan(basePackages = {"com.autumn..dal.mysql","com.autumn..mapper"})

package ${package.Mapper};

import ${package.Entity}.${entity};
import ${superMapperClassPackage};
import org.apache.ibatis.annotations.Mapper;
<#if mapperAnnotationClass??>
import ${mapperAnnotationClass.name};
</#if>

/**
 * <p>
 * ${table.comment!} Mapper 接口
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if mapperAnnotationClass??>
@${mapperAnnotationClass.simpleName}
</#if>
<#if kotlin>
interface ${table.mapperName} : ${superMapperClass}<${entity}>
<#else>
@Mapper
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {

}
</#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="${cacheClassName}"/>

</#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>
posted @ 2025-08-20 21:26  秋夜雨巷  阅读(17)  评论(0)    收藏  举报