@RestController 详解:从源码到实践
一、什么是 @RestController?
@RestController 是 Spring 4.0 引入的注解,它是 @Controller 和 @ResponseBody 的组合。用于标记一个类为 RESTful 风格的控制器,类中所有方法的返回值直接作为 HTTP 响应体返回,无需通过视图解析器渲染。
二、与 @Controller 的本质区别
传统 Web 应用中,@Controller 配合视图解析器(如 Thymeleaf、JSP)使用。方法返回字符串代表视图名称,Spring 根据名称找到对应的模板文件,渲染成 HTML 后返回给浏览器。这个过程中,数据通过 Model 对象传递到视图层。
java
@Controller
public class UserController {
@GetMapping("/user")
public String getUser(Model model) {
model.addAttribute("name", "张三");
return "userView"; // 返回视图名,渲染 userView.html
}
}
@RestController 改变了这套逻辑。它把 @ResponseBody 的作用范围从单个方法提升到整个类,所有方法返回值跳过视图解析器,直接写入 HTTP 响应体。
java
@RestController
public class UserController {
@GetMapping("/user")
public User getUser() {
return new User("张三"); // 直接输出 JSON
}
}
@RestController 的源码定义:
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(annotation = Controller.class)
String value() default "";
}
从源码可以看出,@RestController 本身被 @Controller 和 @ResponseBody 标记。@AliasFor 允许你像 @Controller 一样指定 Bean 名称,例如 @RestController("userController")。
三、底层工作原理
Spring MVC 的核心是 DispatcherServlet。当一个 HTTP 请求到达时,DispatcherServlet 通过 HandlerMapping 找到能处理该请求的 HandlerMethod(即 Controller 中的方法),然后委托给 HandlerAdapter 执行。
@RestController 的方法由 RequestMappingHandlerAdapter 处理。这个适配器内部维护了一个 HandlerMethodReturnValueHandler 列表,每个处理器负责处理不同类型的返回值。
对于 @RestController,关键处理器是 RequestResponseBodyMethodProcessor。它的处理流程:
- 执行 Controller 方法,得到返回对象
- 遍历已注册的
HttpMessageConverter列表 - 根据返回类型和请求的
Accept头,选择能处理该类型的转换器 - 调用转换器的
write()方法,将对象序列化并写入HttpServletResponse的输出流
HttpMessageConverter 是 Spring 处理对象序列化的核心接口。常见实现:
| 转换器 | 作用 |
|---|---|
MappingJackson2HttpMessageConverter |
使用 Jackson 将对象序列化为 JSON |
MappingJackson2XmlHttpMessageConverter |
将对象序列化为 XML |
StringHttpMessageConverter |
处理字符串返回值 |
ByteArrayHttpMessageConverter |
处理字节数组 |
ResourceHttpMessageConverter |
处理文件资源 |
当 @RestController 返回 User 对象时,请求头 Accept: application/json 存在,RequestMappingHandlerAdapter 会选择 MappingJackson2HttpMessageConverter,最终输出 {"id":1,"name":"张三"}。
四、返回 String 的陷阱
@RestController 返回 String 时,不会自动添加双引号变成 JSON 格式。因为 StringHttpMessageConverter 的优先级高于 MappingJackson2HttpMessageConverter,它直接把字符串作为 text/plain 写入响应体。
java
@RestController
public class TestController {
@GetMapping("/test")
public String test() {
return "hello"; // 返回纯文本 "hello",不是 JSON
}
}
如果希望返回 JSON 格式的字符串,几种处理方式:
- 手动拼接 JSON 字符串(不推荐)
- 返回
Object类型,让 Jackson 处理 - 使用
ResponseEntity并指定Content-Type
五、ResponseEntity 进阶用法
ResponseEntity 允许精确控制 HTTP 响应的状态码、响应头和响应体,是 RESTful API 开发中更推荐的返回方式。
java
@GetMapping("/user/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
if (user == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(user);
}
ResponseEntity 的常见构建方式:
java
// 200 OK 带响应体
return ResponseEntity.ok(user);
// 201 Created(常用于 POST 请求)
return ResponseEntity.status(HttpStatus.CREATED).body(user);
// 204 No Content(常用于 DELETE 请求)
return ResponseEntity.noContent().build();
// 404 Not Found
return ResponseEntity.notFound().build();
// 自定义状态码和响应头
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.header("X-Error-Code", "1001")
.body(errorInfo);
六、扩展:自定义消息转换器
当默认的 JSON 序列化不满足需求时,可以自定义 HttpMessageConverter。
例如,需要处理 application/x-protobuf 格式的请求和响应,可以编写一个 ProtobufHttpMessageConverter 并注册到 Spring 容器中。
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
converters.add(new ProtobufHttpMessageConverter());
// 注意顺序,先添加的优先级更高
}
}
七、总结
@RestController 是 Spring Boot 前后端分离架构的基石注解。它通过组合 @Controller 和 @ResponseBody,将方法返回值直接转换为 HTTP 响应体,底层依赖 HttpMessageConverter 完成序列化。
理解它的原理,关键在于理清 DispatcherServlet → HandlerAdapter → HandlerMethodReturnValueHandler → HttpMessageConverter 这条调用链。掌握了这些,你不仅会用 @RestController,更能在遇到序列化异常、返回格式不符合预期时,快速定位问题源头。