在Java企业级开发中,持久层框架的选择直接影响着开发效率和代码质量。MyBatis作为一款优秀的ORM框架,配合MyBatis-Plus的增强工具包,能够显著简化数据库操作代码的编写。而MyBatis-Plus代码生成器则是这个生态中的效率利器,它能够根据数据库表结构自动生成Entity、Mapper、Service等基础代码,让开发者从重复的CRUD编码中解放出来。
我曾在多个Spring Boot项目中实践过这套生成方案,相比传统的手写模式,它能将基础代码的编写时间缩短80%以上。特别是在表结构频繁调整的初期开发阶段,重新生成代码比手动修改要可靠得多。下面我将结合实战经验,详细解析如何基于Spring Boot 3环境配置和使用这套生成工具。
要使用MyBatis-Plus代码生成器,你的项目需要满足以下基础条件:
注意:MyBatis-Plus 3.5.x版本已全面支持Spring Boot 3,但如果你仍在使用Spring Boot 2.x,建议使用MyBatis-Plus 3.4.x版本以避免兼容性问题。
在pom.xml中需要添加以下两个核心依赖:
xml复制<!-- MyBatis-Plus代码生成器核心包 -->
<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>
<scope>compile</scope>
</dependency>
为什么选择FreeMarker而不是Velocity?从我的使用经验来看,FreeMarker模板在复杂场景下更稳定,且错误信息更友好。此外,MyBatis-Plus官方示例也主要采用FreeMarker,社区支持更好。
根据项目实际需要,你可能还需要添加这些依赖:
xml复制<!-- Lombok简化实体类代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot Starter JDBC(如果尚未引入) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 数据库驱动(以MySQL为例) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
MyBatis-Plus提供了两种代码生成方式:传统的AutoGenerator和新的FastAutoGenerator。后者采用链式API设计,配置更加简洁直观。以下是基础生成器示例:
java复制import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.nio.file.Paths;
public class CodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/your_db?useSSL=false",
"username",
"password")
.globalConfig(builder -> {
builder.author("YourName")
.outputDir(Paths.get(System.getProperty("user.dir"))
+ "/src/main/java")
.disableOpenDir();
})
.execute();
}
}
这段代码已经可以运行,但只会生成最基础的代码结构。我们需要继续完善各项配置。
全局配置(GlobalConfig)控制生成的元信息和文件输出位置:
java复制.globalConfig(builder -> {
builder.author("Developer") // 作者署名(会出现在类注释中)
.enableSwagger() // 开启Swagger注解(按需)
.dateType(DateType.TIME_PACK) // 使用java.time包下的时间类
.commentDate("yyyy-MM-dd") // 注释日期格式
.outputDir(projectPath + "/src/main/java") // 输出目录
.disableOpenDir() // 禁用生成后打开目录
.fileOverride(); // 覆盖已有文件(慎用)
})
几个实用技巧:
fileOverride()方法在生产环境要谨慎使用,建议先在临时目录生成,确认无误后再手动复制包配置(PackageConfig)决定了生成的Java类所在的包结构:
java复制.packageConfig(builder -> {
builder.parent("com.example.project") // 父包名
.moduleName("system") // 模块名(可选)
.entity("domain.entity") // 实体类包
.mapper("repository") // Mapper接口包
.service("service") // Service接口包
.serviceImpl("service.impl") // Service实现类包
.controller("web") // Controller包(如需生成)
.pathInfo(Collections.singletonMap(OutputFile.xml,
projectPath + "/src/main/resources/mapper")); // XML位置
})
在实际项目中,我推荐采用领域驱动设计(DDD)的包结构方式,例如:
domain包下放置实体类和值对象infrastructure包下放Mapper和Repositoryapplication包下放Serviceinterfaces包下放Controller策略配置(StrategyConfig)是最复杂的部分,它控制着生成哪些代码以及如何生成:
java复制.strategyConfig(builder -> {
builder.addInclude("user", "role") // 要生成的表
.addTablePrefix("t_", "sys_") // 过滤表前缀
.addFieldPrefix("f_") // 过滤字段前缀
// 实体类策略
.entityBuilder()
.enableLombok() // 使用Lombok
.enableChainModel() // 链式模型
.enableRemoveIsPrefix() // 去除is前缀
.enableTableFieldAnnotation() // 字段注解
.versionColumnName("version") // 乐观锁字段
.logicDeleteColumnName("deleted") // 逻辑删除字段
.naming(NamingStrategy.underline_to_camel) // 命名转换
.columnNaming(NamingStrategy.underline_to_camel)
.addTableFills(new Column("create_time", FieldFill.INSERT)) // 自动填充
// Mapper策略
.mapperBuilder()
.enableMapperAnnotation() // @Mapper注解
.enableBaseResultMap() // 生成resultMap
.enableBaseColumnList() // 生成columnList
// Service策略
.serviceBuilder()
.formatServiceFileName("%sService") // 服务接口命名
.formatServiceImplFileName("%sServiceImpl")
// Controller策略
.controllerBuilder()
.enableRestStyle(); // 使用@RestController
})
特别说明几个实用配置:
addTablePrefix可以去除表前缀,使生成的实体类名更简洁enableRemoveIsPrefix会处理布尔类型字段的is前缀(如is_deleted → deleted)MyBatis-Plus默认使用FreeMarker模板,所有模板文件都存在于generator的jar包中。如果需要自定义模板,可以:
java复制.templateConfig(builder -> {
builder.entity("/templates/entity.java") // 自定义实体模板
.mapper("/templates/mapper.java")
.service("/templates/service.java")
.serviceImpl("/templates/serviceImpl.java");
})
我曾在金融项目中定制过模板,主要修改包括:
通过injectionConfig可以在生成过程中注入自定义变量:
java复制.injectionConfig(builder -> {
builder.beforeOutputFile((tableInfo, objectMap) -> {
objectMap.put("customField", "value"); // 注入自定义变量
}).customMap(Collections.singletonMap("test", "value"));
})
这些变量可以在自定义模板中通过${customField}引用。
对于多模块项目,可能需要从不同数据库生成代码。我的建议方案是:
java复制// 主库生成
FastAutoGenerator.create(mainDataSource)
.packageConfig(builder -> builder.parent("com.example.main"))
.outputDir(mainModulePath)
.execute();
// 从库生成
FastAutoGenerator.create(slaveDataSource)
.packageConfig(builder -> builder.parent("com.example.slave"))
.outputDir(slaveModulePath)
.execute();
问题1:生成的字段类型不正确
java复制.entityBuilder()
.idType(IdType.AUTO) // 主键策略
.convertFileName(entityName -> entityName + "DO") // 添加后缀
.columnOverride(tableField -> {
if (tableField.getType() == Types.DECIMAL) {
tableField.setColumnType("BigDecimal");
}
});
问题2:Lombok注解不生效
java复制.entityBuilder()
.enableLombok()
.enableChainModel();
问题3:生成的Service缺少自定义方法
java复制// 启用缓存配置
.dataSourceConfig(builder -> builder.schema("your_schema").enableCache())
// 并行生成(Java 8+)
Arrays.asList("table1", "table2").parallelStream().forEach(table -> {
FastAutoGenerator.create(dataSource)
.strategyConfig(builder -> builder.addInclude(table))
.execute();
});
为确保生成的代码质量,建议执行以下检查:
可以将代码生成配置为Maven插件,在构建时自动执行:
xml复制<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.example.CodeGenerator</mainClass>
</configuration>
</plugin>
在持续集成环境中,可以采用以下策略:
生成的代码是否提交到版本库存在争议。我的建议是:
对于团队项目,可以在README中明确标注哪些是生成代码,哪些是手工代码,避免混淆。