spring mvc @ResponseBody 注解转换为 JSON 的原理与实现详解

news2025/4/12 15:02:12

在这里插入图片描述

@ResponseBody 注解转换为 JSON 的原理与实现详解


1. 核心作用

@ResponseBody 是 Spring MVC 的一个注解,用于将方法返回的对象直接序列化为 HTTP 响应体(如 JSON 或 XML),而不是通过视图解析器渲染为视图(如 HTML)。

  • 关键作用
    • 跳过视图解析阶段,直接返回数据。
    • 触发 消息转换器(HttpMessageConverter) 将对象转换为指定格式(如 JSON)。

2. 工作流程详解
步骤 1:方法返回对象
@RestController
public class UserController {
    @GetMapping("/user")
    public User getUser() {
        return new User("John", 25); // 返回 Java 对象
    }
}
步骤 2:触发消息转换
  • Spring 检测到 @ResponseBody:跳过视图解析,直接进入消息转换阶段。
  • 选择合适的 HttpMessageConverter
    • 根据 返回对象类型请求的 Accept 头(如 application/json)选择转换器。
    • 默认情况下,Spring Boot 自带的 Jackson 库 提供的 MappingJackson2HttpMessageConverter 会被选中。
步骤 3:Jackson 序列化对象
  • Jackson 的 ObjectMapper:负责将 Java 对象转换为 JSON 字符串。
  • 序列化过程
    1. 遍历对象的 getter 方法字段
    2. 根据注解(如 @JsonProperty)和配置(如日期格式)处理属性。
    3. 忽略 transient 字段或 @JsonIgnore 标记的字段。
// 示例 JSON 输出
{
  "name": "John",
  "age": 25
}

3. 完整代码示例

3.1 实体类(User.java)
public class User {
    private String name;
    private int age;

    // 构造函数、getter 和 setter 方法
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 省略 getter/setter
}
3.2 控制器(UserController.java)
import org.springframework.web.bind.annotation.*;

@RestController // 等效于 @Controller + @ResponseBody
public class UserController {

    @GetMapping("/user")
    public User getUser() {
        return new User("John", 25); // 直接返回对象,由 @ResponseBody 触发转换
    }

    @PostMapping("/user")
    public User createUser(@RequestBody User user) {
        // 处理 POST 请求,将 JSON 反序列化为 User 对象
        return user;
    }
}
3.3 测试请求
# GET 请求获取 JSON
curl http://localhost:8080/user
# 输出:{"name":"John","age":25}

# POST 请求发送 JSON
curl -X POST -H "Content-Type: application/json" -d '{"name":"Jane","age":30}' http://localhost:8080/user

4. 消息转换器(HttpMessageConverter)详解

Spring MVC 通过 HttpMessageConverter 完成对象到 HTTP 响应的转换。

  • 核心接口HttpMessageConverter<T>

    • canRead():判断是否支持反序列化(如 JSON → 对象)。
    • canWrite():判断是否支持序列化(如对象 → JSON)。
    • write():实际执行序列化操作。
  • 常用实现类

    类名作用默认支持格式
    MappingJackson2HttpMessageConverterJSON 转换(依赖 Jackson 库)application/json
    MappingJackson2XmlHttpMessageConverterXML 转换(需额外配置)application/xml
    StringHttpMessageConverter字符串转换text/plain

5. Jackson 配置与自定义

通过自定义 ObjectMapper 可控制 JSON 序列化行为:

5.1 配置示例
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.text.SimpleDateFormat;

@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        // 设置日期格式
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // 忽略未找到的字段(反序列化时)
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        return mapper;
    }
}
5.2 常用注解
注解作用
@JsonProperty指定 JSON 键名(覆盖字段名)。
@JsonFormat定制日期/数字格式。
@JsonInclude控制字段是否参与序列化(如 @JsonInclude(JsonInclude.Include.NON_NULL))。
@JsonIgnore忽略字段。

6. 常见问题与解决方案

Q1:为什么 JSON 中没有某个字段?
  • 可能原因
    • 字段没有 getter 方法。
    • 字段被 @JsonIgnoretransient 修饰。
    • @JsonInclude 配置排除了该字段(如 NON_NULL 且值为 null)。
Q2:如何处理循环引用?
  • 解决方案
    @JsonManagedReference // 主对象(单向引用)
    @JsonBackReference // 被引用对象(忽略反向引用)
    
Q3:如何自定义序列化逻辑?
  • 自定义序列化器
    public class CustomSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException {
            gen.writeString(new SimpleDateFormat("yyyy-MM-dd").format(value));
        }
    }
    
Q4:如何禁用 HTML 转义?
  • 配置
    @Bean
    public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.getObjectMapper().disable(SerializationFeature.ESCAPE_NON_ASCII);
        return converter;
    }
    

7. 总结表格
环节关键组件职责
触发转换@ResponseBody告知 Spring 直接返回数据,跳过视图解析。
选择转换器HttpMessageConverter根据返回类型和 Accept 头选择合适的转换器。
序列化JacksonObjectMapper将 Java 对象转换为 JSON 字符串。
配置扩展自定义 ObjectMapper精细控制序列化格式、日期、忽略策略等。

总结

@ResponseBody 通过结合 HttpMessageConverter 和 Jackson,将 Java 对象无缝转换为 JSON 响应。掌握其工作原理和配置方法,可以灵活处理 RESTful API 的数据格式化需求。对于复杂场景(如自定义序列化、处理循环引用),可通过 Jackson 的注解和配置进一步优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2330956.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

skynet.rawcall使用详解及应用场景

目录 核心特性函数原型使用场景场景 1&#xff1a;高性能二进制传输&#xff08;如文件转发&#xff09;场景 2&#xff1a;自定义序列化协议&#xff08;如 Protocol Buffers&#xff09;场景 3&#xff1a;跨服务共享内存&#xff08;避免拷贝&#xff09; 配套接收方实现与 …

使用SpringSecurity下,发生重定向异常

使用SpringSecurity下&#xff0c;发生空转异常 环境信息&#xff1a; Spring Boot 3.4.4 &#xff0c; jdk 17 &#xff0c; springSecurity 6.4.4 问题背景&#xff1a; 没有自定义controller &#xff0c;改写了login 页面&#xff0c;并且进行了成功后的跳转处理&#xf…

Elasticsearch | ES索引模板、索引和索引别名的创建与管理

关注&#xff1a;CodingTechWork 引言 在使用 Elasticsearch (ES) 和 Kibana 构建数据存储和分析系统时&#xff0c;索引模板、索引和索引别名的管理是关键步骤。本文将详细介绍如何通过 RESTful API 和 Kibana Dev Tools 创建索引模板、索引以及索引别名&#xff0c;并提供具…

力扣hot100_回溯(2)_python版本

一、39. 组合总和&#xff08;中等&#xff09; 代码&#xff1a; class Solution:def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:ans []path []def dfs(i: int, left: int) -> None:if left 0:# 找到一个合法组合ans.append(pa…

LPDDR4内存颗粒命名规则全解析:三星、镁光、海力士、南亚、长鑫等厂商型号解码与选型指南

由于之前DDR的系列选型文章有很好的反馈&#xff0c;所以补充LPDDR4低功耗内存的选型和命名规则&#xff0c;总结了目前市面上常用的内存&#xff0c;供硬件工程师及数码爱好者参考。 在智能手机、平板电脑和低功耗设备中&#xff0c;LPDDR4 SDRAM凭借其高带宽、低功耗特性成为…

【杂谈】Godot4.4导出到Android平台(正式导出)

学博而后可约&#xff0c;事历而后知要。 目录 一、准备二、Gradle构建三、配置Java SDK四、配置Android SDK五、配置密钥 一、准备 本文在前文【杂谈】Godot4.4导出到安卓平台&#xff08;调试导出&#xff09;的基础上&#xff0c;进行正式导出。调试导出并不是真正的编译导…

基于AI设计开发出来的业务系统是什么样的?没有菜单?没有表格?

基于AI设计开发出的业务系统仍然会包含菜单、表格等传统UI元素&#xff0c;但AI技术会显著改变它们的实现方式和交互逻辑。以下是具体分析&#xff1a; 一、传统元素的持续存在 功能刚需性 • 菜单承担着系统导航的核心功能&#xff0c;表格则是结构化数据展示的基础载体。根…

数字足迹管理(DFM):你的网络隐身指南

数字足迹管理&#xff08;DFM&#xff09;&#xff1a;你的网络隐身指南 ‌你可能不知道&#xff0c;你的姓名、电话、住址正在网上被“明码标价”‌ ——而这一切&#xff0c;可能只是因为你点过外卖、寄过快递&#xff0c;甚至注册过一个网站。 一、什么是数字足迹管理&#…

如何避免“过度承诺”导致的验收失败

如何避免“过度承诺”导致的验收失败&#xff1f;关键在于&#xff1a; 评估可行性、设置合理目标、高频沟通反馈、阶段性验收、做好风险管理。其中设置合理目标至关重要&#xff0c;很多团队往往在项目初期为迎合客户或领导而报出“最理想方案”&#xff0c;忽略了资源、技术及…

紧跟数字人热潮:123 数字人分身克隆系统源码部署与风口洞察

在当今数字化浪潮中&#xff0c;数字人技术无疑已成为最具活力与潜力的领域之一&#xff0c;正以迅猛之势席卷多个行业&#xff0c;重塑着人们的交互方式与商业运作模式。C 站作为技术交流的前沿阵地&#xff0c;汇聚了众多关注前沿科技的开发者与技术爱好者&#xff0c;今天来…

QT控件 修改QtTreePropertyBrowser自定义属性编辑器源码,添加第一列标题勾选,按钮,右键菜单事件等功能

头阵子遇到一个需要修改QtTreePropertyBrowser控件的需求&#xff0c;QT开发做这么久了&#xff0c;这个控件倒是第一次用&#xff0c;费了点时间研究&#xff0c;在这里做个简单的总结。 QtTreePropertyBrowser控件 是 Qt 解决方案 (Qt Solutions) 中的一个组件&#xff0c;用…

开源模型应用落地-模型上下文协议(MCP)-从数据孤岛到万物互联(一)

一、前言 当开发者还在为每个AI工具编写臃肿的API适配器时&#xff0c;一场关于「连接」的技术革命已悄然降临。模型上下文协议&#xff08;MCP&#xff09;正在用一套全新的交互语法&#xff0c;重新定义人工智能与物理世界的对话方式。MCP协议如同为AI系统装上了“万能接口”…

【区块链安全 | 第三十八篇】合约审计之获取私有数据(二)

文章目录 前言漏洞代码代码审计攻击步骤修复建议审计思路 前言 在【区块链安全 | 第三十七篇】合约审计之获取私有数据&#xff08;一&#xff09;中&#xff0c;介绍了私有数据、访问私有数据实例、Solidity 中的数据存储方式等知识&#xff0c;本文通过分析具体合约代码进行…

mac 苍穹外卖 后端初始 SkyApplication 报错

报错内容 java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field com.sun.tools.javac.tree.JCTree qualid deepseek 解决 打开 File > Project Structure > Project SDK, 选择 JDK17。我没有 JDK17就下载了一…

Proximal Policy Optimization (PPO)

2.1 策略梯度方法 策略梯度方法计算策略梯度的估计值并将其插入到随机梯度上升算法中。最常用的梯度估计器的形式如下&#xff1a; g ^ E t [ ∇ θ log ⁡ π θ ( a t ∣ s t ) A ^ t ] (1) \hat{g} \mathbb{E}_t \left[ \nabla_{\theta} \log \pi_{\theta}(a_t | s_t) \h…

微信小程序:动态表格实现,表头单元格数据完全从data中获取,宽度自定义,自定义文本框,行勾选,样式效果,横向滚动表格(解决背景色不足的问题)等

一、样式效果 二、代码 1、wxml <view class"line flex flex-center"><view class"none" wx:if"{{info.length 0}}">暂无料号</view><view wx:else class"table-container"><!-- 动态生成表头 -->&…

python-Leetcode 65.搜索旋转排序数组

题目&#xff1a; 整数数组nums按升序排列&#xff0c;数组中的值互不相同 在传递给函数之前&#xff0c;nums在预先未知的某个小标K上进行了旋转&#xff0c;使数组变为[nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]&#xff0c;小标从0开始计数。…

Django学习记录-1

Django学习记录-1 虽然网上教程都很多&#xff0c;但是感觉自己记录一下才属于自己&#xff0c;之后想找也方面一点&#xff0c;文采不佳看的不爽可绕道。 参考贴 从零开始的Django框架入门到实战教程(内含实战实例) - 01 创建项目与app、加入静态文件、模板语法介绍&#xff…

K8s私有仓库拉取镜像报错解决:x509 certificate signed by unknown authority

前言 在Kubernetes环境中使用自签名证书的私有Harbor镜像仓库时&#xff0c;常会遇到证书验证失败的问题。本文将详细讲解如何解决这个常见的证书问题。 环境信息&#xff1a; Kubernetes版本&#xff1a;1.28.2容器运行时&#xff1a;containerd 1.6.20私有仓库&#xff1a…

LabVIEW 长期项目开发

LabVIEW 凭借其图形化编程的独特优势&#xff0c;在工业自动化、测试测量等领域得到了广泛应用。对于长期运行、持续迭代的 LabVIEW 项目而言&#xff0c;其开发过程涵盖架构设计、代码管理、性能优化等多个关键环节&#xff0c;每个环节都对项目的成功起着至关重要的作用。下面…