第4章:MyBatis-Plus整合与逆向工程

好,咱们继续往下走。上一章我们把Spring Boot搭起来了,数据库也连上了。但说实话,光有这些还不够——你总不能让团队里每个人手写几百个Mapper接口和XML吧?那太原始了。

这一章,我带你搞定两件事:整合MyBatis-Plus配置代码生成器。说白了,就是让框架替我们把那些重复的CRUD代码自动生成出来。你想想看,一个订单系统少说几十张表,每张表都要写增删改查,那得写到猴年马月去?

本章核心目标:

  • 整合MyBatis-Plus到Spring Boot项目
  • 配置代码生成器(逆向工程)
  • 自动生成Mapper、Service、Controller基础代码
  • 理解生成后的代码结构

4.1 为什么选MyBatis-Plus?

我个人习惯,做新项目时首选MyBatis-Plus。原因很简单:它把MyBatis最烦人的部分给解决了

MyBatis本身是个好东西,SQL映射灵活,性能也好。但问题在于——你每张表都得写一个Mapper接口,一个XML文件,一个实体类。这些代码90%都是重复的。我在项目中遇到过,一个中等规模的订单系统,光基础CRUD代码就写了将近2000行。后来重构时换成MyBatis-Plus,直接砍掉了70%的样板代码。

MyBatis-Plus的核心优势就三点:

  • 无侵入:它不会动你原有的MyBatis代码,想用原生MyBatis随时可以
  • 自动CRUD:继承一个BaseMapper,基本的增删改查全有了
  • 条件构造器:写复杂查询不用拼SQL,用Lambda表达式搞定

我的建议:如果你是从零开始做新项目,直接上MyBatis-Plus。如果是老项目改造,也可以逐步替换,它兼容性做得很好。

4.2 整合MyBatis-Plus到Spring Boot

好,咱们动手。第一步,在 pom.xml 里加依赖。注意版本号要跟Spring Boot版本匹配,我这边用的是Spring Boot 2.7.x,MyBatis-Plus 3.5.x。

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

<!-- 代码生成器 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.3.1</version>
</dependency>

<!-- 模板引擎(生成代码用) -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>

依赖加完后,在 application.yml 里配置一下MyBatis-Plus。嗯,这里要注意,MyBatis-Plus的配置项跟原生MyBatis不太一样,别搞混了。

mybatis-plus:
  # 实体类扫描路径
  type-aliases-package: com.ordertrading.entity
  # Mapper XML文件路径
  mapper-locations: classpath*:mapper/**/*.xml
  # 全局配置
  global-config:
    db-config:
      # 主键策略:自增
      id-type: auto
      # 表名前缀(如果有统一前缀可以配置)
      # table-prefix: t_
  # 日志输出
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

避坑指南:我曾经遇到过一个问题——配置了 mapper-locations 但路径写错了,结果启动时一直报找不到Mapper。后来发现是路径里的通配符写成了 ** 而不是 *。记住:classpath*:mapper/**/*.xml 表示递归扫描所有子目录。

最后,在启动类上加 @MapperScan 注解,告诉Spring去哪里找Mapper接口。

@SpringBootApplication
@MapperScan("com.ordertrading.mapper")
public class OrderTradingApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderTradingApplication.class, args);
    }
}

到这里,MyBatis-Plus就整合完了。你可以写个简单的测试,比如注入一个BaseMapper,试试能不能查到数据。

4.3 配置代码生成器

整合完MyBatis-Plus,接下来就是重头戏——代码生成器。说白了,就是让工具根据数据库表结构,自动生成实体类、Mapper接口、Service、Controller这些基础代码。

我习惯把代码生成器写成一个独立的测试类,放在 src/test/java 目录下。这样不会污染主代码,想生成的时候跑一下就行。

先看完整的生成器代码,我一行一行给你讲。

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;

import java.util.Collections;

public class CodeGenerator {
    public static void main(String[] args) {
        // 1. 配置数据源
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/order_trading?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai",
                "root", "your_password")
            // 2. 全局配置
            .globalConfig(builder -> {
                builder.author("你的名字") // 作者
                       .outputDir("src/main/java") // 输出目录
                       .commentDate("yyyy-MM-dd") // 注释日期格式
                       .enableSwagger() // 开启Swagger注解
                       .fileOverride(); // 文件覆盖(谨慎使用)
            })
            // 3. 包配置
            .packageConfig(builder -> {
                builder.parent("com.ordertrading") // 父包名
                       .entity("entity") // 实体类包名
                       .mapper("mapper") // Mapper包名
                       .service("service") // Service包名
                       .serviceImpl("service.impl") // ServiceImpl包名
                       .controller("controller") // Controller包名
                       .pathInfo(Collections.singletonMap(OutputFile.xml, "src/main/resources/mapper")); // XML输出路径
            })
            // 4. 策略配置
            .strategyConfig(builder -> {
                builder.addInclude("order", "order_item", "product", "user") // 要生成的表
                       .addTablePrefix("t_") // 表前缀过滤
                       .entityBuilder()
                           .enableLombok() // 使用Lombok
                           .enableTableFieldAnnotation() // 字段注解
                       .serviceBuilder()
                           .formatServiceFileName("%sService") // Service文件名格式
                           .formatServiceImplFileName("%sServiceImpl") // ServiceImpl文件名格式
                       .controllerBuilder()
                           .enableRestStyle() // 启用REST风格
                           .enableHyphenStyle(); // 启用驼峰转连字符
            })
            // 5. 模板引擎
            .templateEngine(new VelocityTemplateEngine())
            .execute();
    }
}

跑一下这个main方法,控制台会输出生成日志。生成完成后,你会在 src/main/java/com/ordertrading 下看到这些目录:

  • entity — 实体类,对应数据库表
  • mapper — Mapper接口
  • service — Service接口
  • service/impl — Service实现类
  • controller — Controller

同时在 src/main/resources/mapper 下会生成对应的XML文件。

我的习惯:生成器跑完后,我会先检查一下生成的实体类。看看字段类型对不对,比如数据库的 decimal 类型有没有映射成 BigDecimal。如果不对,可以在策略配置里加类型转换规则。

4.4 生成代码长什么样?

咱们拿 order 表举个例子。假设表结构是这样的:

字段名 类型 说明
id bigint 主键
order_no varchar(32) 订单号
user_id bigint 用户ID
total_amount decimal(18,2) 总金额
status tinyint 状态
create_time datetime 创建时间

生成的实体类大概长这样:

@Data
@EqualsAndHashCode(callSuper = false)
@TableName("order")
public class Order implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    private String orderNo;

    private Long userId;

    private BigDecimal totalAmount;

    private Integer status;

    private LocalDateTime createTime;
}

Mapper接口更简单:

public interface OrderMapper extends BaseMapper<Order> {
    // 基础CRUD已经继承自BaseMapper,不用写任何方法
    // 如果有特殊查询,在这里加自定义方法
}

Service接口和实现类也是类似的模板代码。Controller会生成RESTful风格的接口,比如 /order 的增删改查。

重点:生成器生成的只是基础代码。真正复杂的业务逻辑,比如订单的创建流程、状态机转换、库存扣减,这些还是得你手动写。生成器帮你省掉的是那些「体力活」——增删改查、分页查询、简单的条件过滤。

4.5 知识体系总览

为了让你对整个流程有个直观的认识,我画了一张图。这张图展示了从数据库到代码生成的完整链路。

MyBatis-Plus 整合与逆向工程流程 MySQL 数据库 order_trading 读取表结构 代码生成器 FastAutoGenerator 生成代码 Entity 实体类 Mapper 接口 + XML Service + Impl Controller 依赖注入 MyBatis-Plus 整合层 BaseMapper / IService / 条件构造器 业务应用层 订单创建 / 状态流转 / 库存扣减 / 支付回调 流程:数据库 → 代码生成器 → 生成基础代码 → MyBatis-Plus整合 → 业务开发

这张图把整个流程串起来了。你从左边数据库开始,中间经过代码生成器,右边得到一堆基础代码。然后这些代码通过MyBatis-Plus整合到Spring Boot里,最后在业务层发挥作用。

4.6 避坑指南与最佳实践

最后,我分享几个实际项目中踩过的坑,你注意一下:

  • 表名大小写问题:MySQL在Linux下默认区分大小写,Windows不区分。生成器生成的实体类默认是驼峰命名,如果表名是 order_item,实体类就是 OrderItem。建议在策略配置里加上 addTablePrefixaddFieldPrefix 来统一处理。
  • 不要频繁跑生成器:生成器每次都会覆盖文件。如果你在生成的Service里加了自定义方法,跑一次生成器就全没了。我的做法是:生成器只跑一次,后续手动修改。如果表结构变了,也只重新生成实体类和Mapper,Service和Controller手动改。
  • Lombok的坑:生成器默认开启Lombok,这很好。但要注意,如果你在实体类里用了 @Data,那 @EqualsAndHashCode 会默认包含所有字段。如果两个实体类互相引用,可能会造成循环调用。建议在 @Data 里加上 callSuper=false,或者手动排除某些字段。
  • XML文件路径:生成器默认把XML放到 src/main/resources/mapper 下。如果你改了路径,记得同步修改 application.yml 里的 mapper-locations 配置。

我的经验:生成器是个好工具,但别过度依赖。它帮你解决的是「80%的重复工作」,剩下20%的复杂逻辑还是得自己写。我见过一些团队,生成器跑完就直接用,连生成的代码看都不看——结果出了问题找半天。记住:生成器生成的代码,你至少要读一遍

好,这一章的内容就到这。你跟着把代码生成器配好,跑一遍,看看生成的代码长什么样。下一章咱们开始写真正的业务逻辑——订单创建的核心流程。


公众号:蓝海资料掘金营,微信deep3321