@RestController 详解:从源码到实践

@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。它的处理流程:

  1. 执行 Controller 方法,得到返回对象
  2. 遍历已注册的 HttpMessageConverter 列表
  3. 根据返回类型和请求的 Accept 头,选择能处理该类型的转换器
  4. 调用转换器的 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 完成序列化。

理解它的原理,关键在于理清 DispatcherServletHandlerAdapterHandlerMethodReturnValueHandlerHttpMessageConverter 这条调用链。掌握了这些,你不仅会用 @RestController,更能在遇到序列化异常、返回格式不符合预期时,快速定位问题源头。

相关推荐
考虑考虑6 小时前
Springboot环境变量占位符语法
spring boot·后端·spring
边境悍匪9 小时前
蜗牛学苑 Java 智能体学习 Day42|项目周开发技术汇总 1 思维导图复盘
java·开发语言·spring boot·学习·spring
xcl092510 小时前
本地电竞服务交易系统架构设计与实战:从同城匹配到订单履约
java·spring boot
白宇横流学长13 小时前
基于springboot的个人博客系统的设计与实现【源码+文档】
java·spring boot
雪芽蓝域zzs17 小时前
第 2 章:MySQL8.0 安装与基础配置
spring boot
行百里er18 小时前
Spring Insight 里如何把 Span 画成瀑布时间线
spring boot·后端·监控
专业程序开发源18 小时前
springboot旅游推荐系统82074-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·php·课程设计·旅游
user_admin_god18 小时前
第 11 篇:实践三 —— 表单 / 合同字段抽取
java·人工智能·spring boot·语言模型
IT枫斗者枫哥19 小时前
Spring Boot Excel 导入实战:把“导入失败”改成逐行错误报告
java·spring boot
杨运交19 小时前
[073][示例]基于Redis分布式锁的定时任务调度实践
spring boot