@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 完成序列化。

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

相关推荐
小蒜学长9 小时前
基于Spring Boot+Vue3的在线医疗咨询系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·在线问诊·在线医疗咨询系统
m0_6399069413 小时前
SpringBoot自动配置原理
java·spring boot·后端
aiks_yuan15 小时前
Spring AI MCP Server 怎么接入 Claude Code:Spring Boot 用 @McpTool 暴露接口(Spring AI 2.0.2 实测)
spring boot
学长毕设16 小时前
基于springboot的实验室设备管理系统
java·spring boot·后端
学长毕设16 小时前
基于springboot的社区养老监护系统的设计与实现
java·spring boot·后端
wno70416 小时前
Springboot国际化信息(i18n)解析
java·spring boot·后端
paopaokaka_luck18 小时前
社区服务平台(加权协同过滤推荐、Jieba中文词频分析、WebSocket实时聊天、求助处理闭环、 活动积分闭环、ECharts多维分析)
java·前端·spring boot·mysql·echarts·mybatis
不会写代码的女程序猿18 小时前
Spring Boot+Layui构建企业级电子招投标系统源码
spring boot·招投标系统·招采系统·电子招投标
仙逆GPT20 小时前
ChatGPT、Codex工程机制:Agent把@Transactional方法改成异步执行,为什么数据会出现部分提交?
spring boot·chatgpt·codex·chatgptplus·chatgptpro
切糕师学AI20 小时前
K8s 滚动更新与 Spring Boot 优雅停机实战:如何做到真正的平滑发布?
spring boot·云原生·容器·kubernetes·k8s