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

内容协商源码解析与自定义 MessageConverter

目录

内容协商

1、引入xml依赖

2、postman分别测试返回json和xml

 3、开启浏览器参数方式内容协商功能

4、内容协商原理

5、自定义 MessageConverter

综上


内容协商

根据客户端接收能力不同,返回不同媒体类型的数据。

若客户端无法解析服务端返回的内容,即媒体类型未匹配,那么相应406。

1、引入xml依赖

默认没有返回xml的能力 

 <dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId>
</dependency>

2、postman分别测试返回json和xml

只需要改变请求头中Accept字段。(Http协议中规定的,告诉服务器,该客户端可以接收的数据类型。)

 3、开启浏览器参数方式内容协商功能

spring:mvc:contentnegotiation:# 开启请求参数内容协商模式favor-parameter: true# 修改parameterName,默认为formatparameter-name: xx

发请求格式:

http://localhost:8080/test/person?format=json

http://localhost:8080/test/person?format=xml

注意:1.如果没有定义参数名字,默认parameterName为format。

           2.引入jackson转换xml包后,则支持json、xml两种媒体类型。(如果需要其他类型数据,可自定义MessageConverter,实现多协议数据兼容)

浏览器端不传参数或者是没匹配到,就是"*/*",都能匹配,然后按权重匹配。

4、内容协商原理

内容协商的内容在返回值处理器 RequestResponseBodyMethodProcessor->writeWithMessageConverters() 方法中

  • 1、判断当前响应头中是否已经保存了 MediaType,如果有则该 MediaType 作为 selectedMediaType。

  • 2、否则,先获取浏览器可接受的所有MediaType: acceptableType

获取的原理:调用返回值处理器的内容协商管理器来获取到当前请求头中 Accept 字段的值,封装到 List 中,并按权重进行排序。

  • 3、获取支持当前返回值类型的 MessageConverter 所支持的所有 MediaType:producibleTypes

获取的原理:获取当前处理器中保存的所有 MessageConverter,匹配支持当前返回值类型的 MessageConverter,将这些 MessageConverter 支持的所有 MediaType 返回。

  • 4、对两种类型进行最佳匹配,筛选出所有可以使用的 MediaType:mediaTypesToUse

对 mediaTypesToUse 按权重进行排序,优先选中优先级较高的作为选定的 MediaType:selectedMediaType。如果匹配到不是具体的 MediaType(带通配符 *),则 selctedMediaType = application/octet-stream。

 

  • 5、遍历循环所有当前系统的 MessageConverter,匹配支持将当前返回值类型 转换为 selectedMediaType 的 MessageConverter,并使用其 write() 方法将当前返回值写入到响应体中。

5、自定义 MessageConverter

实现多协议数据兼容。json、xml、xx-media。

如何新增一个自定义的xx-media格式?

使用spring boot可以基于配置文件快速修改媒体类型。

spring:mvc:contentnegotiation:# 开启请求参数内容协商模式favor-parameter: true# 修改parameterName,默认为formatparameter-name: xx# 自定义媒体类型media-types:xx-media: application/xx-media

 或者如果不修改xml文件,还可以通过重写configureContentNegotiation方法来实现

@Configuration
public class WebConfig {@Beanpublic WebMvcConfigurer webMvcConfigurer () {return new WebMvcConfigurer() {@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.mediaType("xx-media", MediaType.parseMediaType("application/xx-media"));}@Overridepublic void extendMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new CustomConverter());}};}
}

 配置完,可以看到客户端、浏览器可接收的媒体类型如下:

 

无论使用xml形式,还是重写configureContentNegotiation都需要写一个自定义converter。

举个例子,只处理写数据。

public class CustomConverter implements HttpMessageConverter<User> {@Overridepublic boolean canRead(Class clazz, MediaType mediaType) {return false;}@Overridepublic boolean canWrite(Class clazz, MediaType mediaType) {return clazz.isAssignableFrom(User.class);}@Overridepublic List<MediaType> getSupportedMediaTypes() {return MediaType.parseMediaTypes("application/xx-media");}@Overridepublic User read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {return null;}@Overridepublic void write(User user, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {// 自定义协议数据写出String data = user.getName() + "---" +user.getSex() + "---" + user.getAge();//写出去OutputStream body = outputMessage.getBody();body.write(data.getBytes());}
}

 请求结果显示如下:

综上

无论使用浏览器参数访问形式,还是通过postman修改请求头的accept接收值,都可以支持application/xml、application/json、application/xx-media类型的数据。

 ​​​​​​       

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 100个C++面试题
  • C#实现Winform程序右下角弹窗消息提示
  • Web组成架构
  • Spring Boot项目中JPA操作视图会改变原表吗?
  • Spring源码十九:Bean实例化流程二
  • 离线下载linux mysql和mysql基本库
  • JS实现:统计字符出现频率/计算文字在文本中的出现次数
  • 【大规模训练】混合专家系统
  • 【算法】平衡二叉树
  • 【CUDA|CUDNN】安装
  • CANoe:为什么两个VLAN接口不能设置同一个网络的IP地址呢?
  • Django 常见的操作符
  • 修复 Ubuntu 24.04 Dock 丢失应用程序图标
  • 数据结构--二叉树相关习题5(判断二叉树是否是完全二叉树 )
  • uniapp如何发送websocket请求
  • [LeetCode] Wiggle Sort
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • 230. Kth Smallest Element in a BST
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • css属性的继承、初识值、计算值、当前值、应用值
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • 从零开始学习部署
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 一道面试题引发的“血案”
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • # 职场生活之道:善于团结
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • #include<初见C语言之指针(5)>
  • #数据结构 笔记三
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (1)svelte 教程:hello world
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (七)Activiti-modeler中文支持
  • (三)SvelteKit教程:layout 文件
  • (十八)Flink CEP 详解
  • (四)stm32之通信协议
  • (四)图像的%2线性拉伸
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .md即markdown文件的基本常用编写语法
  • .NET Core 实现 Redis 批量查询指定格式的Key
  • .Net MVC + EF搭建学生管理系统
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .net web项目 调用webService