RestController
本章紧接
@Controller的视图渲染模式。在现代 Web 开发中,前后端分离已成为主流——前端(Vue/React)通过 AJAX 调用后端 API,后端只返回 JSON 数据,不再渲染 HTML 页面。@RestController正是为这种场景设计的组合注解,它让每个方法的返回值直接序列化到响应体。理解@RestController,就理解了 Spring MVC 的 RESTful API 开发模式。
定义与作用
@RestController 是 Spring 4.0 引入的类级组合注解,它的职责可以用一句话概括:标记一个类为 RESTful 风格的控制器,使其所有方法的返回值直接通过 HttpMessageConverter 序列化写入 HTTP 响应体。
@RestController 的源码定义非常简洁:
@Controller
@ResponseBody
public @interface RestController {
}
它等价于同时标注 @Controller 和 @ResponseBody。这意味着:
- 类被注册为 Spring MVC 控制器(具备
@Controller的所有特性) - 类的每个方法默认都带有
@ResponseBody(返回值不走 ViewResolver)
生活类比:快递直发 vs 中转仓储
@Controller像传统电商:商品(数据)先送到仓库(ViewResolver),打包成精美礼盒(HTML 页面),再发给客户。客户收到的是完整页面。@RestController像快递直发:商品(JSON 数据)直接打包发货,不经过仓库中转。客户(前端框架)收到 raw 数据,自己决定如何展示。
核心原理
@Controller vs @RestController 的处理流程对比
图解:
@Controller的返回值进入 ViewResolver 流程,最终生成 HTML@RestController的返回值进入 HttpMessageConverter 流程,最终生成 JSON/XML- 两者在 HandlerMapping 查找、HandlerAdapter 调用阶段完全一致,区别只在返回值处理阶段
使用场景决策流程
适用位置与常用属性
@RestController 是类级注解,没有额外属性,但通常与以下注解配合使用:
配合使用的注解
| 注解 | 作用 | 与 @RestController 的关系 |
|---|---|---|
@RequestMapping | 声明请求映射规则 | 标注在类或方法上 |
@GetMapping | 处理 GET 请求 | @RequestMapping(method=GET) 的简写 |
@PostMapping | 处理 POST 请求 | @RequestMapping(method=POST) 的简写 |
@PutMapping | 处理 PUT 请求 | @RequestMapping(method=PUT) 的简写 |
@DeleteMapping | 处理 DELETE 请求 | @RequestMapping(method=DELETE) 的简写 |
@PathVariable | 绑定 URL 路径变量 | RESTful URL 参数提取 |
@RequestBody | 绑定请求体到对象 | JSON 反序列化 |
@Controller vs @RestController 对比表
| 对比维度 | @Controller | @RestController |
|---|---|---|
| 注解组成 | @Component 的特化 | @Controller + @ResponseBody |
| 方法默认行为 | 返回值作为视图名 | 返回值序列化到响应体 |
| 返回 String 时 | 解析为视图名 | 直接作为文本内容返回 |
| 返回对象时 | 尝试解析为视图名(通常 404) | 序列化为 JSON |
| 适用架构 | 传统 MVC(后端渲染页面) | 前后端分离(RESTful API) |
| HTTP 响应类型 | text/html | application/json |
| 模板引擎 | 需要(Thymeleaf/JSP) | 不需要 |
完整示例
场景
飞翔科技开发新版员工管理系统,前端使用 Vue 3 框架,后端只提供 RESTful API。后端工程师小崔使用 @RestController 开发所有接口。
控制器代码
package com.feixiang.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
// 容器已注入该 Bean,本教程不展开 Service 实现
@Autowired
private EmployeeService employeeService;
// 查询所有员工
@GetMapping
public List<Employee> listAll() {
return employeeService.findAll();
}
// 根据 ID 查询员工
@GetMapping("/{id}")
public Employee getById(@PathVariable Long id) {
return employeeService.findById(id);
}
// 创建员工
@PostMapping
public Employee create(@RequestBody Employee employee) {
return employeeService.save(employee);
}
// 更新员工
@PutMapping("/{id}")
public Employee update(@PathVariable Long id,
@RequestBody Employee employee) {
return employeeService.update(id, employee);
}
// 删除员工
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) {
employeeService.delete(id);
}
}
HTTP 请求示例 1:查询员工列表
curl -X GET http://localhost:8080/api/employees \
-H "Accept: application/json"
实际响应:
[
{
"id": 1001,
"name": "张伟",
"department": "技术部",
"position": "高级工程师"
},
{
"id": 1002,
"name": "李娜",
"department": "市场部",
"position": "市场经理"
}
]
分析:
listAll()返回List<Employee>@RestController使@ResponseBody对所有方法生效MappingJackson2HttpMessageConverter自动将 List 序列化为 JSON 数组- 响应头
Content-Type: application/json
HTTP 请求示例 2:创建新员工
curl -X POST http://localhost:8080/api/employees \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "王强",
"department": "技术部",
"position": "初级工程师"
}'
实际响应:
{
"id": 1003,
"name": "王强",
"department": "技术部",
"position": "初级工程师"
}
分析:
@RequestBody将请求体 JSON 反序列化为Employee对象create()返回保存后的Employee@RestController确保返回值自动序列化为 JSON- 前端 Vue 应用可直接将响应数据绑定到页面
易错场景与面试考点
误区一:@RestController 下返回 String 被当作视图名
错误认知:"@RestController 的某个方法返回 String,Spring MVC 会去找同名视图。"
纠正:@RestController 对所有方法都生效了 @ResponseBody,返回 String 时直接作为文本内容写入响应体,不会走 ViewResolver。
@RestController
public class TestController {
@GetMapping("/hello")
public String hello() {
return "hello"; // 浏览器看到纯文本 "hello",不是视图名
}
}
如果需要返回视图名,必须使用 @Controller,或在方法上显式去掉 @ResponseBody(但类级 @RestController 无法局部取消)。
误区二:混合使用 @Controller 和 @RestController
错误认知:"一个项目里可以同时用 @Controller 和 @RestController,随便混用没问题。"
纠正:虽然技术上可以混用,但架构上应该统一:
- 前后端分离项目:全部使用
@RestController - 传统服务端渲染项目:全部使用
@Controller - 混合项目(少量页面 + 大量 API):使用
@Controller,在需要返回 JSON 的方法上单独加@ResponseBody
// 混合项目的推荐做法
@Controller
public class MixedController {
// 返回页面
@GetMapping("/page")
public String page() {
return "page";
}
// 返回 JSON
@GetMapping("/api/data")
@ResponseBody
public Data data() {
return dataService.get();
}
}
面试高频:@Controller 和 @RestController 的区别与选择
标准回答:
@Controller是 Spring MVC 的 Web 层注解,方法返回值默认作为视图名由 ViewResolver 解析为 HTML 页面@RestController是@Controller + @ResponseBody的组合注解,所有方法返回值默认通过 HttpMessageConverter 序列化为 JSON/XML 写入响应体- 选择依据:前后端分离项目用
@RestController,传统服务端渲染项目用@Controller @RestController下返回String直接作为文本内容,不会解析为视图名
小结
@RestController 是 Spring MVC 开发 RESTful API 的首选注解,它通过组合 @Controller 和 @ResponseBody,让所有方法的返回值直接序列化到响应体。在前后端分离架构中,它是后端控制器的标准写法。
本章与全局的关系:本章讲解了 @RestController 的数据直写模式。下一章"RequestMapping"将深入讲解请求映射的核心注解 @RequestMapping,它是所有 HTTP 方法映射注解的元注解。