重学SpringBoot3-内容协商机制

重学SpringBoot3-内容协商机制

  • ContentNegotiationConfigurer接口
  • 配置内容协商
    • URL参数
    • Accept头
    • 使用Url扩展名
  • 自定义内容协商格式
    • 步骤1: 注册自定义媒体类型
    • 步骤2: 实现`HttpMessageConverter`接口
    • 步骤3: 使用自定义`HttpMessageConverter`
  • 注意点

在 Spring Boot 3 中,内容协商(Content Negotiation)是一个非常重要的概念,特别是在构建 RESTful API 时。内容协商机制允许客户端和服务器就如何交换资源的数据格式达成协议。简单来说,它允许客户端通过请求头指定它们希望接收响应的格式(如 JSON,XML 等),服务器基于这些信息来决定以什么格式返回数据。

ContentNegotiationConfigurer接口

org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer

ContentNegotiationConfigurer 是 Spring 框架中的一个接口,用于自定义内容协商策略,主要通过以下几种方式来实现:

  1. URL参数: 通过 URL 参数来指定响应格式,例如,?format=json
  2. Accept头: 通过 Accept 请求头来指定希望接收的响应类型,这是HTTP规范推荐的方式。
  3. 扩展名: 通过 URL 的扩展名来指定响应的格式。例如,.json 表示希望响应为 JSON 格式,.xml 表示希望响应为 XML 格式。

配置内容协商

在 Spring Boot 3 中,你可以在 application.propertiesapplication.yml 文件中进行基本的内容协商配置:

# 开启基于请求参数的内容协商功能,默认此功能不开启
spring.mvc.contentnegotiation.favor-parameter=true
# 指定内容协商时使用的参数名。默认是 format
spring.mvc.contentnegotiation.parameter-name=mediaType
# 用于设置支持的内容协商(Content Negotiation)的媒体类型
spring.mvc.contentnegotiation.media-types.json=application/json
spring.mvc.contentnegotiation.media-types.xml=application/xml

或者通过配置类来实现更复杂的逻辑,没错,就是之前讲过的通过重新 WebMvcConfigurer 接口方法实现自定义配置:

public interface WebMvcConfigurer {default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}// 其他方法
}

以下是一个示例,演示如何通过配置类来配置内容协商策略:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.favorParameter(true).parameterName("mediaType").ignoreAcceptHeader(false).useRegisteredExtensionsOnly(false).defaultContentType(MediaType.APPLICATION_JSON).mediaType("json", MediaType.APPLICATION_JSON).mediaType("xml", MediaType.APPLICATION_XML);}
}

在这个配置中:

  • favorParameter(true):允许使用 URL 参数进行内容协商。
  • parameterName("mediaType"):指定 URL 参数的名称。
  • ignoreAcceptHeader(false):不忽略 Accept 头,即同时支持Accept头和URL参数。
  • useRegisteredExtensionsOnly(false):不仅仅基于已注册的扩展进行格式匹配。
  • defaultContentType(MediaType.APPLICATION_JSON):设置默认的响应类型为JSON。
  • mediaType("json", MediaType.APPLICATION_JSON)mediaType("xml", MediaType.APPLICATION_XML):注册 URL 扩展名到 MIME 类型的映射。

注意,如果要支持输出 XML 需要 pom 文件引入 jackson 包:

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

controller代码

URL参数

需要携带查询字符串 ?mediaType=

json格式

xml格式

Accept头

修改请求头使用 postman 或者 apifox 工具。

json格式

xml格式

使用Url扩展名

从Spring Framework 5.3开始,官方推荐使用其他内容协商机制(如请求头Accept)而非扩展名,因为路径扩展可能会引起一些安全和使用上的问题。因此,在实际应用中,建议评估使用扩展名方式的必要性。

配置了基于扩展名的内容协商,配置文件已经不支持这种配置,所有改成新建配置类的方式:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.favorPathExtension(true).favorParameter(false).ignoreAcceptHeader(false).useRegisteredExtensionsOnly(true).mediaType("json", MediaType.APPLICATION_JSON).mediaType("xml", MediaType.APPLICATION_XML);}
}

配置

json格式

xml格式

自定义内容协商格式

自定义内容协商格式主要涉及到两个方面:一是自定义支持的媒体类型(Media Types),二是自定义对这些媒体类型的处理。

在 Spring Boot 3 中,自定义内容协商格式通常需要以下几个步骤:

  1. 注册自定义媒体类型:你可以通过配置类来注册自定义的媒体类型,让 Spring MVC 知道你打算支持哪些额外的格式。
  2. 实现 HttpMessageConverter 接口:对于每种你想支持的媒体类型,你需要提供一个相应的HttpMessageConverter实现,用于序列化和反序列化数据。
  3. 配置 Spring MVC 以使用你的自定义 HttpMessageConverter:最后,你需要在 Spring MVC 配置中注册你的 HttpMessageConverter 实现,以确保Spring MVC 会使用它们进行请求和响应的处理。

步骤1: 注册自定义媒体类型

假设你想添加对 application/yaml 这种媒体类型的支持,首先需要在配置类中注册这种媒体类型:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.mediaType("yaml", MediaType.valueOf("application/x-yaml"));}
}

或者使用配置文件:

spring.mvc.contentnegotiation.media-types.yaml=application/x-yaml

还需要引入 Jackson 库的 YAML 数据格式支持:

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

步骤2: 实现HttpMessageConverter接口

接下来,需要创建一个 HttpMessageConverter 实现,用于处理 YAML 格式的数据。这里需要实现 readwrite 方法,分别用于反序列化和序列化数据。例如,使用 YamlMapper(这是一个假设的类,实际上你可能需要使用例如SnakeYAML之类的库):

package com.coderjia.springboot304web.config;import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;import java.io.IOException;/*** @author CoderJia* @create 2024/3/9 下午 10:32* @Description**/
public class YamlHttpMessageConverter extends AbstractHttpMessageConverter<Object> {private final YAMLMapper yamlMapper = new YAMLMapper();public YamlHttpMessageConverter() {super(MediaType.valueOf("application/x-yaml"));}@Overrideprotected boolean supports(Class<?> clazz) {// 这里简化了实现,实际上你可能需要更复杂的逻辑来决定你的converter支持哪些类return true;}@Overrideprotected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {// 从HttpInputMessage中读取并解析YAML格式的数据return yamlMapper.readValue(inputMessage.getBody(), clazz);}@Overrideprotected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {// 将给定的对象写入HttpOutputMessage的body中yamlMapper.writeValue(outputMessage.getBody(), object);}
}

步骤3: 使用自定义HttpMessageConverter

最后,需要在 Spring MVC 配置中注册这个新的 HttpMessageConverter。这通常是在一个配置类中完成,通过重写 configureMessageConverters方法:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.mediaType("yaml", MediaType.valueOf("application/x-yaml"));}@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new YamlHttpMessageConverter());}}

这样,当客户端请求以 application/x-yaml 格式接收数据时(比如,通过设置Accept: application/x-yaml头),Spring MVC 就会使用你的 YamlHttpMessageConverter 来序列化响应数据为YAML格式:

yaml格式

注意点

内容协商的配置和实现方式可能因 Spring Boot 版本的不同而略有变化。上述示例适用于 Spring Boot 3,但在实际应用中,还需要根据具体的需求和环境来调整配置。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【每日刷题】栈与队列-LC394、LC347、LC215

题外话&#xff1a;感觉脑子没长到栈这块…最近刷栈的题都好难啊…哭哭…坚持坚持&#xff01;多刷几遍就好了&#xff01;&#xff01; 1. LC394.字符串解码 题目链接 先说数据结构。 维护两个栈&#xff1a;一个栈存之前的字符串&#xff0c;另一个栈存之后的字符串的重复…

腾讯云轻量服务器流量用完了怎么办?停机吗?

腾讯云轻量服务器流量用完了怎么办&#xff1f;超额流量另外支付流量费&#xff0c;流量价格为0.8元/GB&#xff0c;会自动扣你的腾讯云余额&#xff0c;如果你的腾讯云账号余额不足&#xff0c;那么你的轻量应用服务器会面临停机&#xff0c;停机后外网无法访问&#xff0c;继…

探索React中的类组件和函数组件

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

类与对象-对象特性

师从黑马程序员 对象的初始化和清理 构造函数和析构函数 用于完成对象的初始化和清理工作 如果我们不提供构造和析构&#xff0c;编译器会提供编译器提供的构造函数和析构函数是空实现 构造函数&#xff1a;主要用于创建对象时为对象的成员属性赋值&#xff0c;构造函数由编…

每日学习笔记:C++ STL 的Vector

Vector定义 Vector的大小与容量 Vector的函数 操作注意事项 Vector当作C数组 vector<bool>

瑞芯微第二代8nm高性能AIOT平台 RK3576 详细介绍

RK3576处理器 RK3576瑞芯微第二代8nm高性能AIOT平台&#xff0c;它集成了独立的6TOPS&#xff08;Tera Operations Per Second&#xff0c;每秒万亿次操作&#xff09;NPU&#xff08;神经网络处理单元&#xff09;&#xff0c;用于处理人工智能相关的任务。此外&#xff0c;R…

【C语言】深入理解指针(进阶篇)

一、数组名的理解 数组名就是地址&#xff0c;而且是数组首元素的地址。 任务&#xff1a;运行以下代码&#xff0c;看数组名是否是地址。 #include <stdio.h> int main() {int arr[] { 1,2,3,4,5,6,7,8,9,0 };printf("&arr[0] %p\n", &arr[0]);pri…

数据结构——算法的空间复杂度

【本节内容】 1.空间复杂度 2.常见空间复杂度 1.空间复杂度 空间复杂度也是一个数学表达式&#xff0c;是对一个算法在运行过程中临时占用额外存储空间大小的量度。 空间复杂度不是程序占用了多少bytes的空间&#xff0c;因为这个也没太大意义&#xff0c;所以空间复杂度算…

动态规划课堂4-----子数组系列

目录 引入&#xff1a; 例题1&#xff1a;最大子数组和 例题2&#xff1a;环形子数组的最大和 例题3&#xff1a;乘积最大子数组 例题4&#xff1a;乘积为正数的最长子数组 总结&#xff1a; 结语&#xff1a; 引入&#xff1a; 在动态规划&#xff08;DP&#xff09;子…

java中移位<< >> <<< |数据类型转换

移位 x64转换二进制&#xff1a;100 0000 左移2位 &#xff1a; 1000 0000 0 对应十进制 i 256 >>右移 <<左移 >>无符号位右移 关于右移一位相当于整除2 数据类型及其转换 基本数据类型&#xff0c;数据类型范围 byte(-128~127)&#xff08;-2^7~2…

【开源】SpringBoot框架开发教学资源共享平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课程资源模块2.4 课程作业模块2.5 课程评价模块 三、系统设计3.1 用例设计3.2 类图设计3.3 数据库设计3.3.1 课程档案表3.3.2 课程资源表3.3.3 课程作业表3.3.4 课程评价表 四、系统展…

mysql如何开启手动提交事务

在mysql中&#xff0c;有一个变量autocommit&#xff0c;表示自动提交&#xff0c;默认为1&#xff0c;表示开启自动提交。通过以下命令查询 select autocommit;当autocommit为1时&#xff0c;任何一条sql语句都是一个事务&#xff0c;执行完由mysql自动提交。如果想自己决定什…

Java 抽象类和接口

登神长阶 第三阶 抽象类和接口 &#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&#x1f340;&…

LVS负载均衡集群基础概念

目录 一、集群 1、集群概述 1.1 什么是集群 1.2 集群系统扩展方式 1.2.1 Scale UP&#xff08;纵向扩展&#xff09; 1.2.2 Scale OUT&#xff08;横向扩展&#xff09; 1.2.3 区别 1.3 分布式系统 1.4 分布式与集群 1.5 集群设计原则 1.6 集群设计实现 1.6.1 基础…

存储引擎的简介

简介&#xff1a; 1.在mysql存储引擎可以说就是指表的类型&#xff0c;可以称为表处理器&#xff0c;以表的形式存储。 2.他的功能就是接收上层传下来的指令&#xff0c;然后对表中的数据进行提取写入操作。 目的&#xff1a; 为了管理方便&#xff0c;我们把连接管理&#xf…

并查集(蓝桥杯 C++ 题目 代码 注解)

目录 介绍&#xff1a; 模板&#xff1a; 题目一&#xff08;合根植物&#xff09;&#xff1a; 代码&#xff1a; 题目二&#xff08;蓝桥幼儿园&#xff09;&#xff1a; 代码&#xff1a; 题目三&#xff08;小猪存钱罐&#xff09;&#xff1a; 代码&#xff1a; …

AWS的CISO:GenAI只是一个工具,不是万能钥匙

根据CrowdStrike的年度全球威胁报告,尽管研究人员预计人工智能将放大对防御者和攻击者的影响,但威胁参与者在其行动中使用人工智能的程度有限。该公司上个月在报告中表示:“在整个2023年,很少观察到GenAI支持恶意计算机网络运营的开发和/或执行。” 对于GenAI在网络安全中的…

《vtk9 book》 官方web版 第3章 - 计算机图形基础 (3 / 6)

3.8 演员几何 我们已经看到了光照属性如何控制演员的外观&#xff0c;以及相机如何结合变换矩阵将演员投影到图像平面上。剩下的是定义演员的几何形状&#xff0c;以及如何将其定位在世界坐标系中。 建模 计算机图形学研究中的一个重要主题是建模或表示物体的几何形状。…

贪心算法(蓝桥杯 C++ 题目 代表 注解)

介绍&#xff1a; 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在每一步选择中都采取当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望最终能够得到全局最好或最优的结果的算法。它通常用来解决一些最优化问题&#xff0c;如最小生…

扩展CArray类,增加Contain函数

CArray不包含查找类的函数&#xff0c;使用不便。考虑扩展CArray类&#xff0c;增加Contain函数&#xff0c;通过回调函数暴露数组元素的比较方法&#xff0c;由外部定义。该方法相对重载数组元素的“”符号更加灵活&#xff0c;可以根据需要配置不同的回调函数进行比较 //类型…