MyBatis-Plus 新版代码生成器的使用

文章目录

MyBatis-Plus 代码生成器作用 为:

基于数据库表结构,自动生成 与表对应的实体类、Mapper 接口及 XML 文件、Service 接口与实现类、Controller 控制器等全套基础代码,大幅减少 手动编写重复性代码的工作量,保证代码结构规范统一,且支持自定义生成规则适配不同项目的命名、注解等规范,提升开发效率。

目前 MyBatis-Plus 代码生成器有旧版和新版两种,官网指出:新的代码生成器更加的简洁与强大,推荐大家都升级到新的代码生成器

以下总结 MyBatis-Plus 新版代码生成器使用步骤

1、导入依赖

需要导入的依赖有:

  • MyBatis-Plus 核心依赖;
  • MyBatis-Plus 新版代码生成器依赖;
  • 模板引擎依赖(新版默认内置 Velocity,也可选择 Freemarker/Beetl 等)。

特别注意 :MyBatis-Plus 核心依赖需要根据 Spring Boot 版本来选择,否则会因为兼容性问题报错。可以查看这篇博客:分别与 Spring Boot 2.x/3.x/4.x 版本兼容的最新 MyBatis-Plus 依赖

我项目中使用的 Spring Boot 版本为 4.0.3,并选用了 Freemarker 模板引擎,以下是导入的依赖:

xml 复制代码
<!--    mybatis-plus    -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot4-starter</artifactId>
    <version>3.5.15</version>
</dependency>
<!--    mybatis-plus-generator    -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.15</version>
</dependency>
<!--    freemarker    -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.34</version>
</dependency>

2、编写代码生成器类

可以在项目目录中新建一个专门的包 generator(与 controller、mapper 包同级),然后在 generator 包中创建一个代码生成器类 CodeGenerator.java,这样既不污染业务代码,也方便管理。

CodeGenerator.java 模板代码如下,可直接复制后修改

java 复制代码
package com.sun3285.backend.generator;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.annotation.IdType;

import java.util.Collections;

public class CodeGenerator {
    public static void main(String[] args) {
        // ====================== 1. 数据库配置(必须与 application.yaml 保持一致) ======================
        // 数据库连接地址
        String url = "jdbc:oceanbase://xxx.xxx.xxx.xxx:xxx/xxx?useUnicode=true&characterEncoding=utf8&useSSL=false";
        // 数据库用户名
        String username = "xxx";
        // 数据库密码
        String password = "xxx";

        // ====================== 2. 代码生成核心配置 ======================
        FastAutoGenerator.create(url, username, password)
                // ---------------------- 全局配置:影响所有生成文件的基础配置 ----------------------
                .globalConfig(builder -> {
                    builder.author("Sun3285") // 生成代码的作者注释
                            // 代码输出根目录,需要适配项目结构
                            .outputDir(System.getProperty("user.dir") + "/backend/src/main/java")
                            .enableSpringdoc() // 开启 SpringDoc,无需则删除
                            .commentDate("yyyy-MM-dd"); // 注释中的日期格式
                })
                // ---------------------- 包配置:指定各层代码的包名和输出路径 ----------------------
                .packageConfig(builder -> {
                    builder.parent("com.sun3285.backend") // 父包名,必填,与项目基础包一致
                            .moduleName("") // 子模块名
                            .entity("pojo") // 实体类包名,适配项目的 pojo 目录
                            .mapper("mapper") // Mapper 接口包名,适配项目的 mapper 目录
                            .xml("mapper") // Mapper XML 逻辑包名,仅标识,实际路径由 pathInfo 控制
                            .service("service") // Service 接口包名,适配项目的 service 目录
                            .serviceImpl("service.impl") // Service 实现类包名,适配项目的 service/impl 目录
                            .controller("controller") // Controller 类包名,适配项目的 controller 目录
                            // 指定 Mapper XML 文件输出路径,适配 resources/mapper 目录
                            .pathInfo(Collections.singletonMap(OutputFile.xml,
                                    System.getProperty("user.dir") + "/backend/src/main/resources/mapper"));
                })
                // ---------------------- 策略配置:各层代码的生成规则 ----------------------
                .strategyConfig(builder -> {
                    builder.addInclude("user") // 要生成代码的表名,必填,替换为实际表名,多表用 "," 分隔
                            .addTablePrefix("t_") // 表前缀过滤,如 t_user → User,无则删除
                            // 实体类生成策略
                            .entityBuilder()
                            .enableLombok() // 开启 Lombok 注解,生成 @Data 等,未引入 Lombok 则删除
                            .enableTableFieldAnnotation() // 生成 @TableField 字段注解,便于字段映射
                            .idType(IdType.AUTO) // 主键生成策略,AUTO=自增,ASSIGN_ID=雪花算法
                            // Controller 生成策略
                            .controllerBuilder()
                            .enableRestStyle() // 生成 @RestController,RESTful 风格
                            .enableHyphenStyle() // 接口路径驼峰转连字符,如userInfo → user-info,符合 RESTful 接口规范
                            // Service 生成策略
                            .serviceBuilder()
                            .formatServiceFileName("%sService") // Service 接口命名,如 UserService
                            .formatServiceImplFileName("%sServiceImpl") // Service 实现类命名,如 UserServiceImpl
                            // Mapper 生成策略
                            .mapperBuilder()
                            .enableMapperAnnotation() // 生成 @Mapper 注解
                            .enableBaseResultMap() // 生成通用 ResultMap,便于复杂查询
                            .enableBaseColumnList(); // 生成通用字段列表,便于查询复用
                })
                // ---------------------- 模板引擎配置 ----------------------
                .templateEngine(new FreemarkerTemplateEngine()) // 使用 Freemarker 模板引擎,如果用默认 Velocity,可去掉这一行
                // 执行代码生成
                .execute();
    }
}

3、关键配置调整

将第 2 步代码生成器类中的部分配置,按照项目的具体情况进行调整

常见的配置主要分为以下 4 个部分:

  • 全局配置(globalConfig)
  • 包配置(packageConfig)
  • 策略配置(strategyConfig)
  • 模板引擎配置(templateEngine)

配置调整的方法可参考以下途径:

  1. 最直接:看第 2 步中代码生成器类中的注释,已对每个配置做了详细的注释;
  2. 最详细 :MyBatis-Plus 官方文档,点此进入
  3. 最直观 :B 站视频教程,点此进入

下面对配置中的一些常见问题进行总结

  1. 在生成器里面配置的数据源信息 url、username 和 password,和已经在 application.yaml 中配置的数据源信息有关系吗?

    • 本质是两个独立的配置,但目标都是对接同一个数据库,只是作用阶段、使用方完全不同,无直接关联;

      配置位置 作用阶段 使用方 核心目的
      代码生成器类 代码生成阶段(运行 main 方法时) MyBatis-Plus 代码生成器 让生成器连接数据库,读取表结构信息(字段名、类型、主键等),从而生成对应实体类以及 Mapper 等代码
      application.yaml 项目运行阶段(启动 Spring Boot 时) Spring Boot + MyBatis-Plus 让项目运行时能连接数据库,执行 CRUD 操作,如调用 userService.list()
    • 必须保证两者的数据库 url、username 和 password 完全一致,否则生成的代码可能适配错数据库,或项目运行时连不上库;

    • 最佳实践 :可以直接复制 application.yaml 的数据源信息到生成器即可,避免重复编写出错。

  2. System.getProperty("user.dir") 是什么意思?.outputDir(...) 配置后,代码输出根目录是到 java 这一层吗?

    • System.getProperty("user.dir") 用于获取当前项目的工作根目录,即项目文件夹的路径;
    • 拼接 /xxx/src/main/java 后,输出根目录 为:项目根目录/xxx/src/main/java,生成器会在此目录下,按包配置 中配置的包路径及包名自动创建多级子包并放入对应代码,并非仅到 java 层。
  3. .moduleName("") 子模块名什么时候需要配置?

    • 仅在多模块项目 中使用:当项目拆分为 backend-corebackend-api 等子模块时,需指定子模块名,让生成器将代码输出到对应子模块的源码目录;
    • 如果是单模块项目,只有一个模块的情况下,直接留空即可,配置值会额外创建子包,破坏现有结构。
  4. .xml("mapper") 是 Mapper XML 逻辑包名,若改为 .xml("mapper.xml"),是否需要在 mapper 包下新建 xml 子包放 XML?

    • 不需要.xml("mapper")逻辑包名 ,仅影响 XML 文件的 namespace 命名,不决定实际存储路径
    • XML 文件的实际位置.pathInfo(...) 控制,始终输出到 resources/mapper 目录;改为 .xml("mapper.xml") 只会让 namespace 变成 com.xxx.xxx.mapper.xml.xxxMapper,不符合规范,建议保持 xml("mapper")
  5. 已手动编写 user 表代码,再次执行生成器会覆盖还是报错?

    • 跳过该表,不覆盖也不报错,控制台提示:文件已存在,跳过生成;
    • 建议手动修改过的表,执行前在 addInclude 中移除该表名。
  6. 数据库已配置主键自增,为什么还要配 .idType(IdType.AUTO)

    • 数据库自增是存储层规则idType(IdType.AUTO)MyBatis-Plus 框架识别规则
      • 不配置时,框架默认策略可能导致插入数据时主键赋值冲突,自增失效;
      • 配置后,框架明确识别主键为数据库自增,插入时自动跳过主键赋值,保证框架与数据库行为一致。
  7. .enableHyphenStyle() 驼峰转连字符符合 RESTful 规范,能举个例子吗?

    • 该配置会将接口路径的驼峰命名转为小写 + 连字符,示例:
      • 未开启getUserInfo() 生成接口路径 /userInfo/{id}
      • 开启后getUserInfo() 生成接口路径 /user-info/{id},更符合 RESTful 规范的可读性要求。
    java 复制代码
    // 开启 enableHyphenStyle() 后生成的 Controller 方法
    @GetMapping("/user-info/{id}")
    public Result<User> getUserInfo(@PathVariable Long id) {
        return Result.success(userService.getById(id));
    }
  8. .formatServiceFileName("%sService") 中的 %s 是什么意思?

    • %s字符串占位符 ,代表表名对应的实体类名 ,例如:
      • user → 实体类 User → 替换 %s 后生成 UserService
      • 若改为 I%sService,则生成 IUserService,可灵活适配团队命名规范。
  9. .enableBaseResultMap().enableBaseColumnList() 有什么用?能举例吗?

    • enableBaseResultMap():生成通用 ResultMap复用字段映射关系,避免复杂查询时重复写映射配置:

      xml 复制代码
      <resultMap id="BaseResultMap" type="com.sun3285.backend.pojo.User">
          <id column="id" property="id" jdbcType="BIGINT"/>
          <result column="user_name" property="userName" jdbcType="VARCHAR"/>
          <result column="age" property="age" jdbcType="INTEGER"/>
      </resultMap>
      <!-- 复杂查询时直接复用 -->
      <select id="getUserWithOrder" resultMap="BaseResultMap">
          SELECT u.id, u.user_name, u.age, o.order_no 
          FROM user u LEFT JOIN order o ON u.id = o.user_id 
          WHERE u.id = #{id}
      </select>
    • enableBaseColumnList():生成通用字段列表 SQL 片段,避免重复写字段名

      xml 复制代码
      <sql id="Base_Column_List">
          id, user_name, age
      </sql>
      <!-- 查询时直接复用 -->
      <select id="listUserByAge" resultType="com.sun3285.backend.pojo.User">
            SELECT <include refid="Base_Column_List"/> 
          FROM user 
            WHERE age > #{age}
      </select>
  10. 代码生成器只能在项目初期用一次吗?后期加新表还能用吗?

    • 不是,全生命周期都可使用
      • 初期:批量生成所有基础表代码,快速搭建项目骨架;
      • 后期 :新增表时,仅在 addInclude 中指定新表名,如 addInclude("new_table"),执行生成器即可单独生成该表的全套代码。

4、执行代码生成

直接运行 CodeGenerator.java 类的 main 方法。

执行成功后,会按照第 3 步中的相应配置,在对应包下生成以下文件:

  • pojo 包:实体类,如 User.java
  • mapper 包:Mapper 接口,如 UserMapper.java
  • resources/mapper 包:Mapper XML 文件,如 UserMapper.xml
  • service 包:Service 接口,如 UserService.java
  • service/impl 包:Service 实现类,如 UserServiceImpl.java
  • controller 包:Controller 类,如 UserController.java

代码生成器执行前

代码生成器执行后

5、其他配置

  1. 在启动类上添加 Mapper 扫描:

    • 打开项目启动类 xxxApplication.java
    • 添加 @MapperScan 注解,如 @MapperScan("com.xxx.xxx.mapper")

在以下场景可不配置

  • Mapper 接口上都加了 @Mapper 注解;
  • 代码生成器中已开启 .enableMapperAnnotation() 配置(会自动在 Mapper 接口上生成 @Mapper 注解)。

但出于规范管理的考虑,建议配置 ,可以明确指定的扫描路径,同时避免遗漏,防止某个 Mapper 接口忘记添加 @Mapper 注解。

  1. 在 application.yml 中配置 MyBatis-Plus:

    yaml 复制代码
    mybatis-plus:
      mapper-locations: classpath*:/mapper/**/*.xml  # 为默认值,扫描 xxxMapper.xml 文件
      type-aliases-package: com.sun3285.backend.pojo  # 实体类包名

mapper-locations

  • 可省场景 :XML 文件放在了 resources/mapper 目录(或子目录)下;
  • 不可省场景:XML 文件放在了其他路径,此时必须配置指定路径。

type-aliases-package

  • 不配置 :无妨,XML 中 resultType 可以使用实体类的全限定名,如:resultType="com.sun3285.backend.pojo.User"
  • 配置 :更好,可以简化 XML 配置,无需写全限定名,例如:resultType="User"
相关推荐
丶小鱼丶2 小时前
数据结构和算法之【链表】
java·数据结构·算法
一直都在5722 小时前
新Java基础(二十五):异常类
java·开发语言
礼拜天没时间.2 小时前
力扣热题100实战 | 第31期:下一个排列——数组规律的极致探索
java·算法·leetcode·字典序·原地算法·力扣热题100
xiaoye37082 小时前
java后端面试一般问什么?
java·面试
UrbanJazzerati2 小时前
从“加载中”到完整下载:破解PDF异步加载与反爬的完整指南
后端·面试
badhope2 小时前
OpenClaw卸载命令全解析
java·linux·人工智能·python·sql·数据挖掘·策略模式
兆子龙2 小时前
Raft 共识算法与 etcd 实践:从选主到日志复制的完整链路
后端·架构
Hello.Reader2 小时前
Flink Task Lifecycle 一篇讲透 StreamTask 与 Operator 生命周期
java·大数据·flink
Dinwork2 小时前
Skills 开发指南-结合示例详细讲解skills原理和使用方法
后端