当前位置: 首页 > news >正文

学透Spring Boot — 017. 魔术师—Http消息转换器

本文是我的专栏《学透Spring Boot》的第17篇文章,了解更多请移步我的专栏:

学透 Spring Boot_postnull咖啡的博客-CSDN博客

目录

HTTP请求和响应

需求—新的Media Type

实现—新的Media Type

定义转换器

注册转换器

编写Controller

测试新的mediatype

Http消息转换器实现原理

总结


HTTP请求和响应

很多接口,我们发起HTTP请求,请求参数是json。得到的响应也是json。

但是我们的控制器中,是使用Java对象来接收请求,出参也是Java对象。

而不是JSONObject。

这样的好处是更好操作,不用再次把Json对象转换成Java对象。

这是怎么做到的呢?

是不是和上一篇的Spring MVC Conversion Service 类型转换 一样的原理呢?

是,但不完全是。

需求—新的Media Type

先来实现一个需求,看看能不能实现。

我们希望我们的请求是这样

和普通的请求不太一样,主要有亮点:

  1. 我们的MediaType是自己定义“hehe/nba”
  2. 我们的数据体是自己构造的文本,用###分割字段

一般情况,没人会自定定义媒体类型,用得最多的是xml和json。

我们这里这么做,是为了理解json消息体是怎么解析的。

实现—新的Media Type

定义转换器

首先我们先定义一个新Http消息转换器。

它继承的是HttpMessageConverter接口。

注意这里实现的是HttpMessageConverter接口,和我们上一篇文章的类型转换器不一样,它实现的是Converter接口。

public class CarHttpConverter implements HttpMessageConverter<Car> {private static final String SPLITCHAR = "###";private static final String MY_MEDIA_TYPE1 = "hehe/nba;charset=UTF-8";private static final String MY_MEDIA_TYPE2 = "hehe/nba";@Overridepublic boolean canRead(Class<?> clazz, MediaType mediaType) {if(mediaType == null){return true;}return clazz == Car.class&& (mediaType.equals(MediaType.valueOf(MY_MEDIA_TYPE1)) || mediaType.equals(MediaType.valueOf(MY_MEDIA_TYPE2)));}@Overridepublic boolean canWrite(Class<?> clazz, MediaType mediaType) {if(mediaType == null){return true;}return clazz == Car.class&& (mediaType.equals(MediaType.valueOf(MY_MEDIA_TYPE1)) || mediaType.equals(MediaType.valueOf(MY_MEDIA_TYPE2)));}@Overridepublic List<MediaType> getSupportedMediaTypes() {return List.of(MediaType.valueOf(MY_MEDIA_TYPE1), MediaType.valueOf(MY_MEDIA_TYPE2));}@Overridepublic Car read(Class<? extends Car> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {// 从输入流中读取 CSV 数据并将其转换为 Book 对象InputStreamReader reader = new InputStreamReader(inputMessage.getBody());StringBuilder csvData = new StringBuilder();int character;while ((character = reader.read()) != -1) {csvData.append((char) character);}String[] fields = csvData.toString().split(SPLITCHAR);String type = fields[0];double price = Double.parseDouble(fields[1]);String year = fields[2];return Car.builder().type(type).price(price).year(year).build();}@Overridepublic void write(Car car, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody());String csvData = car.getType() + SPLITCHAR + car.getPrice() + SPLITCHAR + car.getYear();writer.write(csvData);writer.flush();}
}

注册转换器

然后,注册这个Http消息转换器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new CarHttpConverter());}
}

编写Controller

特别注意,我们这里的consum和produce用的media type是我们自定义的type。

consumes 指定接收HTTP请求的mediaytpe

produces 指定发送HTTP响应的mediatype

@RestController
@Log
public class HttpMsgController {@PostMapping(path = "/buyCar", consumes = "hehe/nba", produces = "hehe/nba")public Car buyCar(@RequestBody Car car){car.setYear("2025");return car;}
}

测试新的mediatype

设置content type。hehe/nba是我们自定义的type。

设置request body,我们的内容是用###做分隔符的。

这是我们约定的格式。

大功告成!

我们没有使用json,但是定了一个一种新的序列化格式!!!hehe/nba!

Http消息转换器实现原理

我们可以debug看看消息转换器注册的代码。

converters列表中包含了我们新定义的转换器,还包括了Jackson的消息转换器。

我们再看看Spring Boot是如何自动配置Jackson的。

找到Spring Boot的配置类列表

怎么定位这个文件,请参考我之前的文章。

列表中包含了Spring MVC的自动配置WebMvcAutoConfiguration

大部分的默认配置在WebMvcConfigurationSupport。

可以看到,当我们的classpath下,有jackson的包,就会自动使用Jackson处理requestbody和response body.

总结

本文我们定义了一个新的content type, 构造新的请求体和响应体。希望通过本文,你对Http 消息转换器有更多的了解。

相关文章:

学透Spring Boot — 017. 魔术师—Http消息转换器

本文是我的专栏《学透Spring Boot》的第17篇文章&#xff0c;了解更多请移步我的专栏&#xff1a; 学透 Spring Boot_postnull咖啡的博客-CSDN博客 目录 HTTP请求和响应 需求—新的Media Type 实现—新的Media Type 定义转换器 注册转换器 编写Controller 测试新的medi…...

stable diffusion 量化加速点

文章目录 一、导出为dynamic shape1)函数讲解(函数导出、输出检查)2)代码展示二、导出为static shape1)函数讲解(略)2)代码展示三、序列化为FP32测速1)测速2)代码四、序列化为FP16测速1)测速2)代码同上五、发现并解决解决CLIP FP16溢出,并测速1)如何找到溢出的算子…...

Xorg内存管理机制深度解析

Xorg内存管理机制深度解析 一、客户端资源生命周期管理 Xorg 采用 客户端绑定型资源管理 机制,所有资源(窗口、像素图、字体等)的生命周期与客户端连接状态强关联。 资源 ID 分配机制: • 每个资源由 32位标识符 表示,格式:0xBBCCDDEE ◦ BB:客户端 ID(ClientIndex)…...

第五期:深入理解 Spring Web MVC [特殊字符]( 前后端交互的综合性练习)

✨ 前言&#xff1a;从理解到实战&#xff0c;彻底掌握 Spring MVC 前后端交互 当我们学习了 Spring MVC 中的各种注解、参数绑定、请求方式、编码处理以及 Cookie/Session 操作之后&#xff0c;下一步就是 —— 动手实践&#xff01; 理论再多&#xff0c;不如亲自敲一次代码…...

ansible可视化自动化平台-semaphore

1、简介 Semaphore UI 是一个开源的CI/CD工具&#xff0c;专注于简化和自动化软件交付流程&#xff0c;可轻松管理和运行 Ansible playbook&#xff0c;提供了一个直观的 Web 用户界面&#xff08;UI&#xff09;&#xff0c;帮助DevOps团队轻松管理任务、部署和流水线。 官网…...

手撕LLM(二):从源码出发,探索LoRA加载、推理全流程

接上回接着说&#xff0c;前面我们通过分析源码&#xff0c;了解了大模型推理的详细流程&#xff0c;包括提示词从输入&#xff0c;到对话模版包装&#xff0c;到tokenID转换&#xff0c;到Embedding词向量转换&#xff1b;通过大模型推理&#xff0c;再将大模型输出进行最后一…...

数据库连接JDBC

概述 ✅概念 JDBC(JavaDataBaseConnectivityjava数据库连接)是⼀种⽤于执⾏SQL语句的JavaAPI&#xff0c;可以为多种关系型数据库提供 统⼀访问&#xff0c;它是由⼀组⽤Java语⾔编写的类和接⼝组成的。 本质 其实就是java官⽅提供的⼀套规范(接⼝)。⽤于帮助开发⼈员快速实现…...

VectorBT:使用PyTorch+Transformer训练和回测股票模型 进阶五

VectorBT&#xff1a;使用PyTorchTransformer训练和回测股票模型 进阶五 本方案基于PyTorch框架与Transformer模型&#xff0c;结合VectorBT回测引擎构建多股票量化交易系统&#xff0c;采用滑动窗口技术构建时序特征&#xff0c;通过自注意力机制捕捉市场规律预测收益率&#…...

DP Alt Mode​​ 与 ​​USB​​ 的关系

DP Alt Mode​​ 与 ​​USB​​ 的关系 1. 物理接口的统一&#xff1a;USB-C 是“万能插座” [USB-C接口物理结构] |-----------------------------------------------| | USB 3.0数据引脚 | DP Alt Mode视频引脚 | 电源引脚 | |-------------------------------------…...

C#“与AI的奇妙结合”

原文&#xff1a;C# 使用通义灵码 - AI 助力 Visual Studio 开发_w3cschool &#xff08;注意&#xff1a;本文章中并不存在任何广告&#xff0c;也不存在任何盈利内容&#xff09; C# 使用通义灵码 C# 作为一种功能强大且灵活多变的编程语言&#xff0c;被广泛应用于各个领…...

企业ITR流程设计与执行详细介绍【附全文阅读】

该方案聚焦企业 ITR 流程,适用于企业的服务管理人员、流程优化负责人、技术支持团队以及中高层管理者等。 ITR 流程的重要性:企业服务面临客户不满、管理者焦虑、服务人员无奈等挑战,缺乏完善的 ITR 流程会影响品牌形象、客户满意度和产品竞争力。ITR 流程能够保障客户满意,…...

Ubuntu 无密码热点(Soft AP)完整配置方案

适用于 Jetson、嵌入式 Linux、RDK 平台。目标&#xff1a;配置一个无密码热点&#xff08;Soft AP&#xff09;&#xff0c;供手机等设备直接连接。实现开机自动启动热点&#xff0c;也支持后续一键切换回 WiFi 客户端模式。 平台&#xff1a;Yahboom RDK X3&#xff08;Jetso…...

【力扣hot100题】(063)搜索二维矩阵

看到这题我就想到之前被我当作这题做的【力扣hot100题】&#xff08;020&#xff09;搜索二维矩阵Ⅱ 其实是完全不一样的两题&#xff0c;个人觉得这道题更简单也更考验基础&#xff0c;那道题思路更难想到但代码更好写。 两个二分查找结束&#xff0c;要注意的是第一个二分查…...

瑞萨RA4M2使用心得-KEIL5的第一次编译

目录 前言 环境&#xff1a; 开发板&#xff1a;RA-Eco-RA4M2-100PIN-V1.0 IDE&#xff1a;keil5.35 一、软件的下载 编辑瑞萨的芯片&#xff0c;除了keil5 外还需要一个软件&#xff1a;RASC 路径&#xff1a;Releases renesas/fsp (github.com) 向下找到&#xff1a; …...

玄机-apache日志分析

靶场任务 1、提交当天访问次数最多的IP&#xff0c;即黑客IP&#xff1a; 查看apache日志 apache访问日志的位置是&#xff1a;/var/log/apache2/access.log.1 匹配正则算法 首先先cat看看 发现地址都在第一行&#xff0c;直接匹配计算输出 cat access.log.1 |grep -Eo &…...

[C++]洛谷B2119 删除单词后缀

题目与解析 题干题目描述输入格式输出格式样例样例输入样例输出 答案解析食用提示AC代码AC代码详细解析头文件部分主程序8~12行代码 12行以后的代码 题干 题目描述 给定一个单词&#xff0c;如果该单词以 er、ly 或者 ing 后缀结尾&#xff0c;则删除该后缀&#xff08;题目保…...

Ubuntu远程连接Mysql数据库(图文详解)

Ubuntu远程连接Mysql数据库 1、版本2、检查有没有Mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.3 查看Mysql运行状态 3、卸载Mysql4、安装4.1 更新4.2 开始安装4.3 安装完后查看状态 5、登录5.1、使用5.2、查看数据库权限5.3 更新权限5.4 再次查看数据库权限5.5 添加新用…...

回归预测 | Matlab实现NRBO-Transformer-GRU多变量回归预测

回归预测 | Matlab实现NRBO-Transformer-GRU多变量回归预测 目录 回归预测 | Matlab实现NRBO-Transformer-GRU多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.【JCR一区级】Matlab实现NRBO-Transformer-GRU多变量回归预测&#xff0c;牛顿-拉夫逊算法优…...

leetcode122-买卖股票的最佳时机II

leetcode 122 思路 方法一的核心思想是简单的贪心策略。我们每天都看当前价格和下一个价格的差值。如果下一个价格高于当前价格&#xff08;即diff > 0&#xff09;&#xff0c;那么就认为当天可以买入并在第二天卖出&#xff0c;赚取利润。因此&#xff0c;方法一把所有…...

from PIL import Image 安装失败

正确安装 Pillow (PIL) # 通过 Conda 安装 conda install pillow -c conda-forge# 或通过 Pip 安装 pip install pillow验证安装 在 Python 中测试是否成功&#xff1a; from PIL import Image print(Image.__version__) # 应输出类似 "9.5.0" 的版本号常见问题说…...

DPFunc蛋白质功能预测模型复现报告

模型简介 模型的具体介绍见蛋白质功能预测论文阅读记录2025&#xff08;DPFunc、ProtCLIP&#xff09;_protein functions-CSDN博客 复现流程 仓库&#xff1a;CSUBioGroup/DPFunc 时间&#xff1a;2025.4.5 环境配置 python 3.9.21 & CUDA 11.6 Pytorch: 1.12.0 DG…...

在 Ubuntu24.04 LTS 上 Docker Compose 部署基于 Dify 重构二开的开源项目 Dify-Plus

一、安装环境信息说明 硬件资源&#xff08;GB 和 GiB 的主要区别在于它们的换算基数不同&#xff0c;GB 使用十进制&#xff0c;GiB 使用二进制&#xff0c;导致相同数值下 GiB 表示的容量略大于 GB&#xff1b;换算关系&#xff1a;1 GiB ≈ 1.07374 GB &#xff1b;1 GB ≈ …...

双系统ubuntu20.04不能外接显示器的解决办法

一&#xff0c;更换驱动 首先确定是不是英伟达显卡驱动&#xff0c;如果不是的话&#xff0c;设置里找到附加驱动&#xff0c;更改为NVIdia类型的驱动&#xff0c;更改完成之后重启 这里大部分电脑都可以了&#xff0c;如果不行 二、更改启动方式 重启之后进入BIOS设置&…...

高并发内存池:原理、设计与多线程性能优化实践

高并发内存池是一种专门为多线程环境设计的内存管理机制&#xff0c;其核心目标是通过优化内存分配和释放过程&#xff0c;解决传统内存分配器&#xff08;如malloc/free&#xff09;在高并发场景下的性能瓶颈&#xff0c;显著提升多线程程序的内存访问效率。 目录 一、核心设计…...

03.31-04.06 论文速递 聚焦具身智能、复杂场景渲染、电影级对话生成等五大前沿领域

&#x1f31f; 论文速递 | 2025.03.31-04.06 &#x1f4e2; 聚焦具身智能、复杂场景渲染、电影级对话生成等前沿领域 1️⃣ 具身智能体&#xff1a;从脑启发到安全协作系统 论文标题&#xff1a; Advances and Challenges in Foundation Agents: From Brain-Inspired Intellige…...

Django和Celery实现的异步任务案例

推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 先决条件步骤1:安装依赖项步骤2:配置Celery2.1 创建`celery.py`2.2 更新 `__init__.py`步骤3:配置Django设置步骤4:定义Celery任务…...

DAY 38 leetcode 15--哈希表.三数之和

题号15 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 未去重版本 整体思路&#xff1a;先排序再双指针遍…...

Java项目之基于ssm的个性化旅游攻略定制系统(源码+文档)

项目简介 个性化旅游攻略定制系统实现了以下功能&#xff1a; 个性化旅游攻略定制系统能够实现对用户上传信息&#xff0c;旅游路线信息&#xff0c;景点项目信息&#xff0c;景点信息&#xff0c;标签分类信息等信息的管理。 &#x1f495;&#x1f495;作者&#xff1a;落落…...

链表和数组的效率

访问元素 • 数组&#xff1a;通过索引直接访问元素&#xff0c;时间复杂度为O(1)&#xff0c;速度很快。例如arr[5]可以立即访问到数组arr中索引为5的元素。 • 链表&#xff1a;需要从链表头开始逐个遍历节点&#xff0c;直到找到目标元素&#xff0c;平均时间复杂度为O(n)…...

经典回溯问题———组合的输出

题目如下 思路 代码如下...

WPS宏开发手册——附录

目录 系列文章7、附录 系列文章 使用、工程、模块介绍 JSA语法 JSA语法练习题 Excel常用Api Excel实战 常见问题 附录 7、附录 颜色序列&#xff1a;在excel中设置颜色&#xff0c;只能设置颜色序号&#xff0c;不能直接设置rgb颜色 1、黑色 (Black)…...

【leetcode100】买卖股票的最佳时机

1、题目描述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。如果你…...

uniapp小程序登录失效后操作失灵问题

一开始我在请求返回失效验证时做了登录失效处理然后用uni.switchTab跳转主页的逻辑&#xff0c;结果发现在一天后重新打开小程序或者其他登录挤掉登录验证时有概率导致整个页面失灵无法操作。 经过排查发现&#xff0c;在小程序跳转新页面的时候如果遇到**(过快还是过多&#…...

找树左下角的值(DFS 深度优先搜索)| LeetCode 513

✨ 题目描述 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 提示&#xff1a; 二叉树中至少有一个节点。 &#x1f4c4; 示例 示例 1 输入: root [2,1,3] 输出: 1示例 2 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7&#x1f5…...

【力扣hot100题】(060)分割回文串

每次需要判断回文串&#xff0c;这点比之前几题回溯题目复杂一些。 还有我怎么又多写了循环…… class Solution { public:vector<vector<string>> result;string s;bool palindromic(string s){for(int i0;i<s.size()/2;i) if(s[i]!s[s.size()-1-i]) return …...

中国钧瓷收藏市场现状和风险警示

一、数据权威性与综合维度 本榜单由钧瓷联合体、钧瓷频道及钧瓷数据库三方协同制作&#xff0c;通过10项规则综合评估匠人影响力&#xff0c;涵盖知名度、用户评价、平台指数等多元维度&#xff0c;避免单一指标&#xff08;如拍卖价格&#xff09;的片面性。榜单每月更新&…...

forms实现任务文档功能

说明&#xff1a; forms实现任务文档功能 效果图&#xff1a; step1:C:\Users\wangrusheng\RiderProjects\WinFormsApp26\WinFormsApp26\Form1.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; u…...

字符串的replace、replaceAll、split()方法

参考 字符串的replace、replaceAll、split()方法_字符串replace-CSDN博客...

Kotlin语言进阶:协程、Flow、Channel详解(二)

Kotlin语言进阶:协程、Flow、Channel详解(二) 一、Flow基础 1.1 什么是Flow Flow是Kotlin提供的用于处理异步数据流的解决方案,它建立在协程之上,具有以下特点: 冷流特性:只有在收集时才会开始发射数据背压处理:自动处理生产者和消费者速度不匹配的问题组合操作:提…...

VBA知识学习

文章目录 打开开发工具编写第一个VBA使用VBA调试器 VBA语法 打开开发工具 文件->选项->自定义功能区->开发工具 编写第一个VBA 点击开发工具 ->点击Visual Basic 选择sheet1->右键->插入->模块 Sub 第一个VBA程序()MsgBox "Hello World!&quo…...

JAVA EE_多线程-初阶(二)

1.线程安全 1.1.观察线程不安全 实例&#xff1a; package thread; public class text18 {//定义一个成员变量count,初始值为0private static int count0;public static void main(String[] args) throws InterruptedException {Thread t1new Thread(()->{for(int i0;i&l…...

【Linux】进程预备知识——冯诺依曼、操作系统

目录&#xff1a; 一、冯诺依曼体系结构 &#xff08;一&#xff09;什么是冯诺依曼 &#xff08;二&#xff09;为什么需要冯诺依曼 &#xff08;三&#xff09;冯诺依曼如何操作 二、操作系统概念 &#xff08;一&#xff09;对下硬件管理 &#xff08;二&#xff09;…...

Java入门首周精要:从基础语法到面向对象核心解析

文章目录 Java入门首周精要&#xff1a;从基础语法到面向对象核心解析1.Java类名与文件名的一致性规则2.Java和C语言中char类型的区别3.Java中的注释4.Java中的‘’‘’运算符5.Java的输入输出6.方法&#xff08;重载&重写&#xff09;方法的重载方法的重写 7.面向对象&…...

嵌入式AI开源生态指南:从框架到应用的全面解析

嵌入式AI开源生态指南&#xff1a;从框架到应用的全面解析 引言 随着人工智能技术的迅速发展&#xff0c;将AI能力部署到边缘设备上的需求日益增长。嵌入式AI通过在资源受限的微控制器上运行机器学习模型&#xff0c;实现了无需云连接的本地智能处理&#xff0c;大幅降低了延…...

MCP server的stdio和SSE分别是什么?

文章目录 一、Stdio:本地进程间通信的核心二、SSE:远程通信与实时推送的利器三、Stdio vs SSE:关键差异对比四、如何选择?场景驱动的决策指南五、实战建议与避坑指南实际操作结语在AI应用开发中,MCP(Model Context Protocol)协议正成为连接大模型与外部资源的核心桥梁。…...

哈希表(闭散列)的实现

目录 概念及定义 闭散列的介绍 闭散列底层实现 哈希表的定义 哈希表的构造 哈希表扩容 哈希表插入 哈希表删除 哈希表查找 概念及定义 哈希表&#xff0c;也成为散列表&#xff0c;在C中unordered_set和unordered_map的底层实现依靠的都是哈希表。 map和set的底层是红…...

Shiro学习(六):Shiro整合CAS实现单点登录

一、单点登录介绍 单点登录&#xff08;Single Sign On&#xff09;&#xff0c;简称为 SSO&#xff0c;是比较流行的企业业务整合的解决方案之一。 SSO的定义是在多个[应用]&#xff0c;用户只需要登录一次就可以访问所有相互信任的应用系统。 一般这种单点登录的实现方案&…...

HAProxy-ACL实战篇

HAProxy-ACL实战篇 IP说明172.25.254.101客户端172.25.254.102haproxy服务器172.25.254.103web1172.25.254.104web2 ACL示例-域名匹配 # 172.25.254.102 [rootRocky ~]# cat /etc/haproxy/conf.d/test.cfg frontend magedu_http_portbind 172.25.254.102:80mode httpbalanc…...

以下是针对该 Ansible 任务的格式检查和优化建议

以下是针对该 Ansible 任务的格式检查和优化建议&#xff1a; 目录 一、格式检查原始代码问题分析修正后的标准格式 二、推荐增强功能1. 添加可执行权限2. 显式指定 Shell 解释器3. 添加错误处理 三、完整 Playbook 示例四、验证脚本兼容性五、常见错误总结 一、格式检查 原始…...

C++语言的测试覆盖率

C语言的测试覆盖率分析与实践 引言 在软件开发过程中&#xff0c;测试覆盖率是一项重要的质量指标&#xff0c;它帮助开发者评估代码的测试效果&#xff0c;确保软件的可靠性与稳定性。尤其在C语言的开发中&#xff0c;由于其复杂的特性和丰富的功能&#xff0c;测试覆盖率的…...