乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 SpringMVC概述与DispatcherServlet

    • 本章导读:Spring MVC概述与DispatcherServlet
    • Spring MVC 是什么
    • MVC 设计模式
    • 前端控制器模式
    • DispatcherServlet
    • 核心组件协作
  • 第2章 控制器与请求映射

    • 本章导读:控制器与请求映射
    • Controller
    • RestController
    • RequestMapping
    • GetMapping
    • PostMapping
    • PutMapping
    • DeleteMapping
    • PathVariable
    • RESTful
    • 请求映射原理
  • 第3章 请求参数获取与转换

    • 本章导读:请求参数获取与转换
    • RequestParam
    • RequestBody
    • RequestHeader
    • CookieValue
    • Model
    • ModelAttribute
    • 数据绑定原理
    • 数据校验
  • 第4章 响应数据与视图解析

    • 本章导读:响应数据与视图解析
    • ResponseBody
    • ResponseEntity
    • ModelAndView
    • ViewResolver
    • HttpMessageConverter
    • forward与redirect
  • 第5章 拦截器过滤器与跨域

    • 本章导读:拦截器、过滤器与跨域
    • HandlerInterceptor
    • WebMvcConfigurer
    • CrossOrigin
    • 登录验证实战
  • 第6章 文件上传与异常处理

    • 本章导读:文件上传与异常处理
    • MultipartFile
    • 文件下载
    • ExceptionHandler
    • ControllerAdvice
    • RestControllerAdvice
    • ResponseStatus
  • 第7章 高级特性与最佳实践

    • 本章导读:高级特性与最佳实践
    • SessionAttributes
    • SessionAttribute
    • RedirectAttributes
    • MockMvc测试
    • 国际化
    • 最佳实践
  • 第8章 扩展与异步机制

    • 本章导读:扩展与异步机制
    • 异步请求处理
    • 自定义参数解析器
    • 内容协商

ResponseBody

本章开启"响应数据与视图解析"篇章。如果说前面的章节都在讲解"请求怎么进来、数据怎么进来",那么从本章开始,我们聚焦"数据怎么出去"。@ResponseBody 是 Spring MVC 中最核心的响应注解——它让方法的返回值直接成为 HTTP 响应体,跳过视图解析,是 RESTful API 和前后端分离架构的基石。


定义与作用

@ResponseBody 用于将 Controller 方法的返回值直接序列化为 HTTP 响应体,不经过视图解析器(ViewResolver)渲染。

在传统的 Spring MVC 中,Controller 方法返回 String 时,Spring 会把它当作"视图名",交给 ViewResolver 查找对应的 JSP/Thymeleaf 模板。而标注了 @ResponseBody 后,这个 String 就直接写入 HTTP 响应体,客户端收到的是原始字符串。

当返回类型是 Java 对象时,@ResponseBody 会触发 HttpMessageConverter,将对象序列化为 JSON(默认)或 XML,写入响应体。

生活类比:直邮 vs 转交

想象飞翔科技的客户服务:

  • 传统视图渲染(无 @ResponseBody):客服收到客户问题后,把问题转交给设计部(ViewResolver),设计部排版做成精美手册(HTML 模板),再寄给客户
  • @ResponseBody:客服直接拿起电话,把答案口述给客户(返回值直接写入响应体)。如果答案是结构化数据(如报表),客服用传真机(Jackson)把报表转成标准格式(JSON)发过去

@ResponseBody 的核心价值是消除中间环节,让数据直达客户端。


核心原理

序列化过程

关键节点:

  1. 跳过视图解析:@ResponseBody 存在时,DispatcherServlet 不会调用 ViewResolver
  2. Content-Type 协商:根据请求的 Accept 头或注解的 produces 属性,选择对应的 HttpMessageConverter
  3. Jackson 序列化:默认使用 MappingJackson2HttpMessageConverter,依赖 Jackson 库将 Java 对象转为 JSON
  4. 直接写入响应:序列化后的数据通过 HttpServletResponse.getOutputStream() 直接写入

@ResponseBody vs 视图渲染对比


适用位置与常用属性

@ResponseBody 可以标注在 方法 或 类 上。

使用位置作用范围
方法仅当前方法返回值直接写入响应体
类该类所有方法的返回值都直接写入响应体(@RestController 的本质)

常用组合:

注解组合效果
@Controller + 方法级 @ResponseBody仅该方法返回 JSON
@RestController类中所有方法默认返回 JSON(等价于类上 @ResponseBody)
@ResponseBody + produces = "application/xml"返回 XML 格式

完整示例

场景

飞翔科技员工管理系统的前后端完全分离,前端黄骊使用 Vue.js 开发,所有数据通过 AJAX 以 JSON 格式交互。后端小崔使用 @ResponseBody 返回员工数据。

代码实现

package com.feixiang.web;

import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;

@RestController  // 等价于 @Controller + @ResponseBody
@RequestMapping("/api/employees")
public class EmployeeController {

    /**
     * 返回单个员工 JSON
     */
    @GetMapping("/{id}")
    public Employee getEmployee(@PathVariable Long id) {
        return new Employee(id, "张三", "技术部", 25000);
    }

    /**
     * 返回员工列表 JSON
     */
    @GetMapping
    public List<Employee> listEmployees() {
        return Arrays.asList(
            new Employee(1L, "张三", "技术部", 25000),
            new Employee(2L, "李四", "产品部", 22000)
        );
    }

    /**
     * 返回纯文本字符串
     */
    @GetMapping("/status")
    @ResponseBody  // 即使类上有 @RestController,显式标注更清晰
    public String getStatus() {
        return "系统运行正常";
    }
}

// Employee.java
package com.feixiang.web;

public class Employee {
    private Long id;
    private String name;
    private String department;
    private Integer salary;

    public Employee() {}
    public Employee(Long id, String name, String department, Integer salary) {
        this.id = id;
        this.name = name;
        this.department = department;
        this.salary = salary;
    }

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getDepartment() { return department; }
    public void setDepartment(String department) { this.department = department; }
    public Integer getSalary() { return salary; }
    public void setSalary(Integer salary) { this.salary = salary; }
}

HTTP 请求示例

示例 1:返回 JSON 对象

curl "http://localhost:8080/api/employees/1" \
     -H "Accept: application/json"

响应:

{
  "id": 1,
  "name": "张三",
  "department": "技术部",
  "salary": 25000
}

示例 2:返回 JSON 数组

curl "http://localhost:8080/api/employees" \
     -H "Accept: application/json"

响应:

[
  {
    "id": 1,
    "name": "张三",
    "department": "技术部",
    "salary": 25000
  },
  {
    "id": 2,
    "name": "李四",
    "department": "产品部",
    "salary": 22000
  }
]

示例 3:返回纯文本

curl "http://localhost:8080/api/employees/status"

响应:

系统运行正常

注意响应的 Content-Type 为 text/plain;charset=UTF-8,因为返回类型是 String,Spring 使用 StringHttpMessageConverter 处理。


易错场景与面试考点

误区一:@Controller 方法返回 String 被当视图名

现象:

@Controller
public class TestController {
    @GetMapping("/test")
    @ResponseBody
    public String test() {
        return "success";  // 客户端收到 "success" 文本
    }

    @GetMapping("/page")
    public String page() {
        return "success";  // Spring 查找 success.html 模板
    }
}

关键点:同一个 Controller 中,有 @ResponseBody 的方法返回原始数据,没有的方法返回视图名。两者可以共存,但容易混淆。

最佳实践:RESTful API 类统一使用 @RestController,传统页面渲染类使用 @Controller,不要在同一个类中混用两种模式。

误区二:返回 null 导致 404

现象:@ResponseBody 方法返回 null,客户端收到 HTTP 200 但响应体为空。

解释:@ResponseBody 对 null 的处理取决于 HttpMessageConverter。Jackson 会将 null 序列化为 JSON 的 null(字符串 "null"),但某些情况下可能输出空响应体。这不是 404——404 是 ViewResolver 找不到视图时的行为,@ResponseBody 根本不经过 ViewResolver。

误区三:循环引用导致 JSON 序列化失败

现象:Employee 对象关联 Department,Department 又关联 List<Employee>,序列化时无限递归,栈溢出。

解决:使用 Jackson 的 @JsonIgnore 或 @JsonManagedReference / @JsonBackReference:

public class Employee {
    private String name;
    
    @JsonIgnore  // 序列化时忽略该字段
    private Department department;
}

面试高频:@RestController 和 @Controller + @ResponseBody 的区别

标准回答:

  1. @RestController 是组合注解,等价于 @Controller + @ResponseBody
  2. 标注在类上时,该类所有方法的返回值都直接写入响应体,不经过视图解析
  3. @Controller 单独使用时,方法返回 String 被当作视图名,需要视图模板支持
  4. 在 @Controller 类中,可以给个别方法加 @ResponseBody 实现混合模式(部分返回 JSON,部分返回页面)
  5. 前后端分离项目推荐统一使用 @RestController

小结

@ResponseBody 是 Spring MVC 实现 RESTful API 的核心注解。它让 Controller 方法的返回值跳过视图解析,直接通过 HttpMessageConverter 序列化为 HTTP 响应体。配合 Jackson,Java 对象可以自动转为 JSON 输出。

核心要点:

  • @RestController = @Controller + @ResponseBody,是开发 API 的首选
  • 返回 Java 对象时,默认序列化为 JSON(依赖 Jackson)
  • 返回 String 时,默认输出纯文本(text/plain)
  • 注意循环引用问题,使用 @JsonIgnore 等注解处理

本章与全局的关系:本章讲解了"如何将数据直接输出为响应体"。下一节 ResponseEntity 将在此基础上,讲解如何完整控制 HTTP 响应——包括状态码、响应头和响应体。

上一页
本章导读:响应数据与视图解析
下一页
ResponseEntity