第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整合到Spring Boot里,最后在业务层发挥作用。
4.6 避坑指南与最佳实践
最后,我分享几个实际项目中踩过的坑,你注意一下:
- 表名大小写问题:MySQL在Linux下默认区分大小写,Windows不区分。生成器生成的实体类默认是驼峰命名,如果表名是
order_item,实体类就是OrderItem。建议在策略配置里加上addTablePrefix或addFieldPrefix来统一处理。 - 不要频繁跑生成器:生成器每次都会覆盖文件。如果你在生成的Service里加了自定义方法,跑一次生成器就全没了。我的做法是:生成器只跑一次,后续手动修改。如果表结构变了,也只重新生成实体类和Mapper,Service和Controller手动改。
- Lombok的坑:生成器默认开启Lombok,这很好。但要注意,如果你在实体类里用了
@Data,那@EqualsAndHashCode会默认包含所有字段。如果两个实体类互相引用,可能会造成循环调用。建议在@Data里加上callSuper=false,或者手动排除某些字段。 - XML文件路径:生成器默认把XML放到
src/main/resources/mapper下。如果你改了路径,记得同步修改application.yml里的mapper-locations配置。
我的经验:生成器是个好工具,但别过度依赖。它帮你解决的是「80%的重复工作」,剩下20%的复杂逻辑还是得自己写。我见过一些团队,生成器跑完就直接用,连生成的代码看都不看——结果出了问题找半天。记住:生成器生成的代码,你至少要读一遍。
好,这一章的内容就到这。你跟着把代码生成器配好,跑一遍,看看生成的代码长什么样。下一章咱们开始写真正的业务逻辑——订单创建的核心流程。
公众号:蓝海资料掘金营,微信deep3321