一、核心概念

什么是 Controller 代码生成?

MyBatis-Plus 的代码生成器(AutoGenerator)不仅可以生成 Entity、Mapper、Service,还可以自动生成基于 Spring MVC 的 RESTful 风格 Controller 类,包含常见的 CRUD 接口:

  • GET /entity:分页查询
  • GET /entity/{id}:根据 ID 查询
  • POST /entity:新增
  • PUT /entity:更新
  • DELETE /entity/{id}:删除

生成 Controller 的作用

  • 快速搭建后端接口原型
  • 统一接口风格(命名、返回格式)
  • 减少样板代码编写
  • 提高开发效率(尤其在项目初期或管理后台)

二、操作步骤(超详细)

第一步:添加必要依赖

确保 pom.xml 中包含以下依赖:

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- MyBatis-Plus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.6</version>
    </dependency>

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

    <!-- 模板引擎:Velocity(默认) -->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.3</version>
    </dependency>

    <!-- Lombok(可选但推荐) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

⚠️ 注意:lombok 需要在 IDE 中安装插件才能识别注解。


第二步:创建代码生成器主类

创建 src/test/java/com/example/generator/CodeGenerator.java

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.Collections;

public class CodeGenerator {

    public static void main(String[] args) {
        generate();
    }

    private static void generate() {
        FastAutoGenerator.create(
                "jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8",
                "root",
                "your_password"
            )
            // 全局配置
            .globalConfig(builder -> {
                builder.author("Your Name")                    // 作者
                       .outputDir(System.getProperty("user.dir") + "/src/main/java") // 输出到 java 目录
                       .commentDate("yyyy-MM-dd HH:mm:ss")    // 注释日期格式
                       .disableOpenDir();                     // 生成后不打开文件夹
            })

            // 包配置
            .packageConfig(builder -> {
                builder.parent("com.example.demo")            // 父包名
                       .moduleName("system")                  // 模块名(可选)
                       .controller("controller");             // Controller 包路径
            })

            // 策略配置
            .strategyConfig(builder -> {
                builder.controllerBuilder()
                       .enableRestStyle()                     // 使用 @RestController
                       .enableHyphenStyle()                   // URL 驼峰转连字符(如 /user-info)
                       .formatFileName("%sController")        // Controller 类命名格式
                       .build();

                // 指定要生成 Controller 的表
                builder.addInclude("user", "role", "dept")     // 包含的表
                       .addTablePrefix("t_", "sys_");          // 过滤表前缀
            })

            // 执行生成
            .execute();
    }
}

第三步:运行生成器

  1. 右键运行 CodeGenerator.main() 方法
  2. 观察控制台输出:
    ==> 作者: Your Name
    ==> 生成包路径: com.example.demo.system.controller
    ==> 生成表: user, role, dept
    ==> 生成完成!
    
  3. 检查 src/main/java/com/example/demo/system/controller/ 目录下是否生成了:
    • UserController.java
    • RoleController.java
    • DeptController.java

第四步:生成的 Controller 示例(UserController.java)

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping // 分页查询
    public Result<?> selectPage(Page<User> page, User user) {
        Page<User> result = userService.page(page, Wrappers.query(user));
        return Result.ok(result);
    }

    @GetMapping("/{id}") // 根据 ID 查询
    public Result<User> getById(@PathVariable Long id) {
        User user = userService.getById(id);
        return Result.ok(user);
    }

    @PostMapping // 新增
    public Result<User> save(@RequestBody User user) {
        userService.save(user);
        return Result.ok(user);
    }

    @PutMapping // 更新
    public Result<User> update(@RequestBody User user) {
        userService.updateById(user);
        return Result.ok(user);
    }

    @DeleteMapping("/{id}") // 删除
    public Result<?> delete(@PathVariable Long id) {
        userService.removeById(id);
        return Result.ok();
    }
}

⚠️ 注意:Result 是 MP Generator 默认使用的返回类型,实际项目中建议替换为自定义统一返回类。


三、常见错误与解决方案

错误现象 原因 解决方案
ClassNotFoundException: org.springframework.web.bind.annotation.RestController 缺少 spring-boot-starter-web 添加 Web 依赖
Controller 未生成 .controllerBuilder() 未调用或 .disable(TemplateType.CONTROLLER) 确保启用 Controller 生成
URL 路径带下划线(如 /user_info 未启用 enableHyphenStyle() 添加 .enableHyphenStyle()
生成路径错误(如生成到 test 目录) outputDir 设置错误 设置为 src/main/java
中文乱码 文件编码问题 确保项目编码为 UTF-8
@Autowired 报错 Service 未生成或包扫描问题 检查 Service 是否生成,确认 Spring 扫描路径

四、注意事项

  1. Controller 依赖 Service:必须先生成或存在对应的 UserService 接口及实现类。
  2. 包扫描:确保 Spring Boot 主类能扫描到生成的 Controller(通常父包一致即可)。
  3. 统一返回格式:默认的 Result 类可能不符合项目规范,建议自定义模板替换。
  4. 权限控制:生成的接口无权限校验,需手动添加 @PreAuthorize 或拦截器。
  5. 参数校验:生成的接口无参数校验,需手动添加 @Valid@NotBlank 等。
  6. 异常处理:建议配合 @ControllerAdvice 全局异常处理。
  7. 不要覆盖已有文件:默认会覆盖同名文件,建议首次生成前备份。

五、使用技巧

1. 自定义 Controller 模板

复制默认模板到 resources/templates/controller.java.vm 并修改:

package ${package.Controller};

import org.springframework.web.bind.annotation.*;
import ${package.Service}.${serviceClass};
import ${package.Entity}.${entity};
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.common.Result; // 自定义 Result

import javax.annotation.Resource;

@RestController
@RequestMapping("/${table.entityPath}")
public class ${table.controllerName} {

    @Resource
    private ${serviceClass} ${serviceInstance};

    @GetMapping
    public Result<Page<${entity}>> list(Page<${entity}> page, ${entity} ${entityProperty}) {
        Page<${entity}> data = ${serviceInstance}.page(page, new QueryWrapper<>(${entityProperty}));
        return Result.success(data);
    }

    @GetMapping("/{id}")
    public Result<${entity}> getById(@PathVariable ${keyPropertyType} id) {
        ${entity} data = ${serviceInstance}.getById(id);
        return Result.success(data);
    }

    @PostMapping
    public Result<${entity}> create(@RequestBody ${entity} ${entityProperty}) {
        ${serviceInstance}.save(${entityProperty});
        return Result.success(${entityProperty});
    }

    @PutMapping
    public Result<${entity}> update(@RequestBody ${entity} ${entityProperty}) {
        ${serviceInstance}.updateById(${entityProperty});
        return Result.success(${entityProperty});
    }

    @DeleteMapping("/{id}")
    public Result<Void> delete(@PathVariable ${keyPropertyType} id) {
        ${serviceInstance}.removeById(id);
        return Result.success();
    }
}

在生成器中指定模板:

.templateConfig(builder -> {
    builder.controller("/templates/controller.java.vm");
})

2. 禁用特定方法

.controllerBuilder()
    .disableRestStyle()           // 禁用 @RestController
    .disableHyphenStyle()         // 禁用连字符风格
    .disableRequestMappingAnnot() // 禁用 @RequestMapping
    .build();

3. 添加自定义注解

.controllerBuilder()
    .customAnnotations(
        Collections.singletonList(
            new CustomAnnotation().setAnnotation("@Log(operation = \"查询用户\")")
        )
    )
    .build();

六、最佳实践与性能优化

✅ 最佳实践

实践 说明
✅ 生成后立即审查 检查接口命名、参数、返回值是否符合规范
✅ 添加参数校验 @RequestBody 添加 @Valid@NotBlank
✅ 添加权限注解 @PreAuthorize("hasAuthority('user:add')")
✅ 统一返回格式 使用 Result<T> 包装返回数据
✅ 添加 API 文档 配合 @Api@ApiOperation 生成 Swagger 文档
✅ 分页查询加条件 list 方法中支持动态查询条件
✅ 异常统一处理 使用 @ControllerAdvice 处理业务异常

⚡ 性能优化建议

  • ❌ 不要为所有表生成 Controller(如字典表、中间表)
  • ✅ 对高频查询接口添加缓存(@Cacheable
  • ✅ 分页接口注意 pageSize 上限(防止 pageSize=10000
  • ✅ 删除操作建议改为逻辑删除(避免误删)
  • ✅ 批量操作接口需加限流(防止刷单)

七、完整增强版生成器示例

FastAutoGenerator.create(url, username, password)
    .globalConfig(builder -> {
        builder.author("Admin")
               .outputDir(System.getProperty("user.dir") + "/src/main/java")
               .commentDate("yyyy-MM-dd")
               .disableOpenDir();
    })
    .packageConfig(builder -> {
        builder.parent("com.example.demo")
               .moduleName("system")
               .controller("controller")
               .service("service")
               .serviceImpl("service.impl")
               .entity("entity")
               .mapper("mapper");
    })
    .strategyConfig(builder -> {
        builder.addInclude("user", "role")
               .addTablePrefix("t_");

        // 实体配置
        builder.entityBuilder()
               .enableLombok()
               .enableTableFieldAnnotation()
               .logicDeleteColumnName("deleted")
               .versionColumnName("version");

        // Controller 配置
        builder.controllerBuilder()
               .enableRestStyle()
               .enableHyphenStyle()
               .formatFileName("%sController");

        // Service 配置
        builder.serviceBuilder()
               .formatServiceFileName("%sService")
               .formatServiceImplFileName("%sServiceImpl");
    })
    .templateConfig(builder -> {
        // 可指定自定义模板路径
    })
    .execute();

总结

MyBatis-Plus 生成 Controller 是快速搭建后端接口的利器,特别适合管理后台、CRUD 频繁的场景。通过合理配置 .controllerBuilder(),可生成符合 RESTful 规范的接口。