Skip to content

Spring MVC 中的 Controller 是什么?如何定义一个 Controller? ​

  • 标签:后端、Spring

🏛 业务架构师 ​

Controller 是 Spring MVC 里HTTP 请求与业务逻辑之间的适配层:接收请求、校验参数、调用 Service、组装响应。定义方式:

java
@RestController
@RequestMapping("/api/orders")
public class OrderController {

    private final OrderService orderService;   // 构造器注入

    @GetMapping("/{orderId}")
    public Result<OrderVO> detail(@PathVariable Long orderId) {
        return Result.ok(orderService.getDetail(orderId));
    }

    @PostMapping
    public Result<Long> create(@Validated @RequestBody OrderCreateDTO dto) {
        return Result.ok(orderService.create(dto));
    }
}

@RestController = @Controller + @ResponseBody,直接返回 JSON。

架构师视角,Controller 的**"薄"是团队代码质量的第一体检指标**:

  1. 只做四件事:参数校验、权限上下文读取、调用 Service、结果组装。出现 if/else 业务判断、直接操作数据库,就是越界——业务规则必须沉淀在 Service,否则同样的规则没法被定时任务、MQ 消费者复用;
  2. DTO 与领域模型分离:入参/出参用 DTO 隔离,防止内部表结构通过接口泄漏,字段变更不破坏契约;
  3. 统一返回结构与错误码:Controller 不写 try-catch 兜底,异常交给全局处理——保证所有接口对外行为一致。

一句话:Controller 是系统的"门面",门面的纪律性决定了整个代码库的演进秩序。

🏗 系统架构师 ​

定义:@Controller(页面)或 @RestController(REST,等价 Controller 加 ResponseBody)标注类,@RequestMapping 及其组合注解声明路由,方法即 Handler。

java
@RestController
@RequestMapping("/orders")
public class OrderController {
    @PostMapping
    public Result<OrderVO> create(@Valid @RequestBody CreateOrderDTO dto) {...}
}

架构定位:Controller 是协议适配层,不是业务层。我评审 Controller 只看三条:

  1. 薄:参数校验 → 调一个应用服务 → 组装 VO,没有 if 业务分支;
  2. 无状态:不存成员变量,天然支持水平扩展;
  3. 契约先行:入参 DTO 与出参 VO 和领域模型隔离——API 演进(加字段、版本化)不反向侵入领域层;出参不直接吐实体,防止内部表结构变化变成破坏性 API 变更。

Controller 写厚是分层失守的第一张多米诺骨牌:业务逻辑混进去后无法复用、无法测试,改 API 就得改业务。

💻 全栈开发专家 ​

Controller 是 MVC 里的 C——接请求、参数校验、调 Service、组装响应,不写业务逻辑(薄 Controller 原则):

java
@RestController                                 // = @Controller + @ResponseBody
@RequestMapping("/api/v1/orders")
@Validated
public class OrderController {

    private final OrderService orderService;
    public OrderController(OrderService orderService) { this.orderService = orderService; }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Result<OrderVO> create(@RequestBody @Valid OrderCreateReq req) {
        return Result.ok(orderService.create(req));
    }

    @GetMapping("/{id}")
    public Result<OrderVO> detail(@PathVariable Long id) {
        return Result.ok(orderService.get(id));
    }
}

要点:@Controller 返回视图名(模板渲染),@RestController 直接序列化 JSON,前后端分离无脑后者;类上 @RequestMapping 收敛路径前缀。

我的 code review 三条规约:Controller 只做协议层转换(DTO 与 VO 之间),复杂逻辑下沉 Service;DTO 与实体分离,避免实体直接出网(字段泄露和序列化事故);一个 Controller 对应一个资源,URL 用复数名词。看到 500 行的 Controller,基本就是职责漏了,面试拿这条说事很加分。