SpringBoot内容协商(简单使用、源码解读、默认Converters、自定义Converters)

news2024/11/25 19:38:17

目录

  • 1. 内容协商
    • 1.1 简单使用
    • 1.2 源码解读
    • 1.3 WebMvcAutoConfiguration提供几种默认HttpMessageConverters
    • 1.4 自定义HttpMessageConverter支持yaml格式输出

1. 内容协商

1.1 简单使用

一套系统适配多端数据返回

内容协商

  • 基于请求头内容协商:(默认开启)
    1. 客户端向服务端发送请求,携带HTTP标准的Accept请求头application/json(默认支持,因为web场景导入了jackson处理的包jackson-core)、application/xml(需要手动设置)
    2. 服务端根据客户端请求头期望的数据类型进行动态返回
  • 基于请求参数内容协商:(需要手动开启)
    1. 发送请求: GET /get-user?format=json(默认支持)
    2. 匹配到@GetMapping(“/get-user”)
    3. 根据参数协商,返回json类型数据
    4. 发送请求: GET /get-user?format=xml, 返回xml类型数据(需要手动设置)

开启xml支持

  1. 先添加pom.xml依赖
<!-- 添加了依赖前,默认返回json,添加依赖后,默认返回xml -->
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>
  1. 在Bean类上添加xml支持注解
@JacksonXmlRootElement    // 其实不加这个也可以
public class User {
......省略部分......
}

开启基于请求参数内容协商。application.properties参数设置如下

# 开启基于请求参数的内容协商功能。 默认为false功能不开启
spring.mvc.contentnegotiation.favor-parameter=true
# 指定内容协商时使用的参数名。默认是format
spring.mvc.contentnegotiation.parameter-name=type

示例:RestController如下:

package com.hh.springboot3test.controller;

import com.hh.springboot3test.bean.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ControllerTest {

    @GetMapping("/get-user")
    public User user() {
        return new User("jim");
    }
}

通过header头传递accept参数,和返回结果如下:
header头

通过请求参数,返回结果如下:
请求参数结果

1.2 源码解读

  • @ResponseBody由HttpMessageConverter处理:标注了@ResponseBody的返回值,将会由支持它的HttpMessageConverter写给浏览器
  1. 如果controller方法的返回值标注了@ResponseBody注解

    1. 请求进来先来到DispatcherServlet的doDispatch()进行处理
    2. 找到一个HandlerAdapter适配器。利用适配器执行目标方法
    3. RequestMappingHandlerAdapter通过调用invokeHandlerMethod()来执行目标方法
    4. 目标方法执行之前,准备好两个东西
      1. HandlerMethodArgumentResolver:参数解析器,确定目标方法每个参数值
      2. HandlerMethodReturnValueHandler:返回值处理器,确定目标方法的返回值该怎么处理
    5. RequestMappingHandlerAdapter里面的invokeAndHandle()真正执行目标方法
    6. 目标方法执行完成,会返回返回值对象
    7. 找到一个合适的返回值处理器HandlerMethodReturnValueHandler
    8. 最终找到RequestResponseBodyMethodProcessor能处理标注了 @ResponseBody注解的方法
    9. RequestResponseBodyMethodProcessor调用writeWithMessageConverters, 利用MessageConverter把返回值写出去
  2. HttpMessageConverter会先进行内容协商

    1. 遍历所有的MessageConverter看谁支持这种内容类型的数据

    2. 默认MessageConverter有以下
      MessageConverter

    3. 最终因为要json,所以MappingJackson2HttpMessageConverter支持写出json

    4. jackson用ObjectMapper把对象写出去

1.3 WebMvcAutoConfiguration提供几种默认HttpMessageConverters

● EnableWebMvcConfiguration -> DelegatingWebMvcConfiguration -> WebMvcConfigurationSupport -> addDefaultHttpMessageConverters添加了默认的MessageConverter。如下:
- ByteArrayHttpMessageConverter: 支持字节数据读写
- StringHttpMessageConverter: 支持字符串读写
- ResourceHttpMessageConverter:支持资源读写
- ResourceRegionHttpMessageConverter: 支持分区资源写出
- AllEncompassingFormHttpMessageConverter:支持表单xml/json读写
- MappingJackson2HttpMessageConverter: 支持请求响应体Json读写

系统提供默认的MessageConverter功能有限,仅用于json或者普通返回数据。额外增加新的内容协商功能,必须增加新的HttpMessageConverter

1.4 自定义HttpMessageConverter支持yaml格式输出

  1. 添加依赖,用于对Object进行转换
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-yaml</artifactId>
        </dependency>
  1. 编写一个YamlHttpMessageConverter
package com.hh.springboot3test.component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
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;
import java.io.OutputStream;
import java.nio.charset.Charset;


public class MyYamlHttpMessageConverter extends AbstractHttpMessageConverter<Object> {

    //把对象转成yaml
    private ObjectMapper objectMapper = null;

    public MyYamlHttpMessageConverter() {
        // 告诉SpringBoot这个MessageConverter支持哪种媒体类型  
        super(new MediaType("text", "yaml", Charset.forName("UTF-8")));

        YAMLFactory factory = new YAMLFactory()
                .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);
        this.objectMapper = new ObjectMapper(factory);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        // 只要是对象类型,不是基本类型,则都支持
        return true;
    }

    // @RequestBody。对接收的yaml格式参数进行解析,这里不处理
    @Override
    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    // @ResponseBody。把对象以yaml格式传输出去
    @Override
    protected void writeInternal(Object methodReturnValue, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

        // try-with写法,自动关流
        try (OutputStream os = outputMessage.getBody()) {
            this.objectMapper.writeValue(os, methodReturnValue);
        }

    }
}
  1. 在application.properties中,新增媒体类型
# 新增一种媒体类型
spring.mvc.contentnegotiation.media-types.yaml=text/yaml
  1. 通过WebMvcConfigurer,将MyYamlHttpMessageConverter添加到conveters
package com.hh.springboot3test.config;

import com.hh.springboot3test.component.MyYamlHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    // 添加一个能把对象转为yaml的messageConverter
    @Override 
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MyYamlHttpMessageConverter());
    }
}
  1. 测试。访问http://localhost:8080/get-user?type=yaml。效果如下:
    yaml内容协商效果

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

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

相关文章

学习笔记|秩相关分析|Spearman相关分析|Kendall相关分析|规范表达|《小白爱上SPSS》课程:SPSS第十九讲:秩相关分析怎么做?

目录 学习目的软件版本原始文档秩相关分析一、实战案例二、统计策略三、SPSS操作四、结果解读五、规范表达1、规范图表2、规范文字 六、划重点&#xff1a; 学习目的 SPSS第十九讲&#xff1a;秩相关分析怎么做&#xff1f; 软件版本 IBM SPSS Statistics 26。 原始文档 《…

DC电源模块隔离电路的影响

BOSHIDA DC电源模块隔离电路的影响 DC电源模块隔离电路是电子设备中常用的一种电路。它的作用是在设备中两个电路之间建立一定的隔离&#xff0c;以保证两个电路之间不会传递电流或信号。这种隔离电路的影响可以从以下几个方面来分析。 首先&#xff0c;隔离电路可以提高安全性…

人工智能:一种现代的方法 第二章 智能体

文章目录 前言人工智能&#xff1a;一种现代的方法 第二章 智能体2.1 环境与智能体2.2 理性概念2.3环境的性质2.3.1任务环境的规范描述&#xff1a;PEAS2.3.2环境的性质 2.4智能体结构 前言 本章属于本书的开篇&#xff0c;有两个不便于理解的地方一是讲述的概念过于抽象&…

再不记录就忘啦在浙工商的第一年啦!

再不记录就快忘啦在浙工商的第一年啦&#xff01; 文章目录 再不记录就快忘啦在浙工商的第一年啦&#xff01;&#x1f6a9;这是前言&#xff01;&#xff01;&#xff01;&#x1f468;‍&#x1f680;杭漂选手新生入场【2019.08-2019.10】&#x1f9d8;‍♂️开始步入适应期【…

[机缘参悟-118] :如何做到:从无到有,从0到1设计一个新系统或产品?如何做到总是能快速的解决复杂技术难题?

目录 前言&#xff1a; 一、在软件工程化理论和实践上 二、在担任过的嵌入系统的岗位角色上&#xff08;横向、广度&#xff09; 三、在嵌入式设备的功能分层上&#xff08;纵向、深度&#xff09; 四、在嵌入式通信产品/设备类型上 五、在软硬件产品的项目管理上 六、在…

ActiveMq学习⑨__基于zookeeper和LevelDB搭建ActiveMQ集群

引入消息中间件后如何保证其高可用&#xff1f; 基于zookeeper和LevelDB搭建ActiveMQ集群。集群仅提供主备方式的高可用集群功能&#xff0c;避免单点故障。 http://activemq.apache.org/masterslave LevelDB&#xff0c;5.6版本之后推出了LecelDB的持久化引擎&#xff0c;它使…

css-inpu边框

效果图&#xff1a; input {width: 225px;height: 25px;background-color: #1469bd00;border: #aca9a97d solid 1px;color: white;font-size: 15pt;box-sizing: conte-box; }input:focus {border-style: solid;border-color: #03a9f4;box-shadow: 0 0 15px #03a9f4;outline: …

基于分钟级降水预报API 的智能农业水资源管理探究

前言 随着农业现代化的发展&#xff0c;越来越多的农业生产活动需要依赖于科学技术的支持。其中&#xff0c;智能农业水资源管理就是依托新型技术手段&#xff0c;实现对水资源的更加精准预报、科学调度的一种管理模式。而基于分钟级降水预报API的智能农业水资源管理&#xff…

【elasticsearch+kibana基于windows docker安装】

创建网络&#xff1a;es和kibana容器互联 docker network create es-net加载镜像 docker pull elasticsearch:7.12.1运行 docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.typesingle-node" -e ES_JAVA_OPTS"-Xms512m -Xmx512m" -v $…

有趣的数学 sign是什么函数

在数学中&#xff0c;函数sign指的是符号函数&#xff0c;它的定义如下&#xff1a;对于任意实数x&#xff0c;若x>0&#xff0c;则sign(x)1&#xff1b;若x0&#xff0c;则sign(x)0&#xff1b;若x<0&#xff0c;则sign(x)-1&#xff1b;简单来说&#xff0c;sign函数就…

node版本管理神器|nvm安装使用教程

文章目录 导文安装前提下载安装包进行安装第一步&#xff0c;下载安装包&#xff0c;[nvm下载地址](https://github.com/coreybutler/nvm-windows/releases)第二步&#xff0c;进行安装&#xff0c;点击nvm-setup.exe文件&#xff0c;接受用户协议第三步&#xff0c;选择安装目…

是时候扔掉你的密码了

引言 “密码是人类历史的不朽篇章&#xff0c;它的早期迹象几乎与文字的诞生同期”。正如密码史学家乔尔里维尔所说&#xff0c;密码&#xff0c;作为信息的保护工具&#xff0c;已经存在了数千年。古代人类早期就开始认识到信息的重要性&#xff0c;同时也意识到了保护这些信息…

Win11安装网络打印机

https://support.microsoft.com/zh-cn/windows/%E5%9C%A8-windows-%E4%B8%AD%E5%AE%89%E8%A3%85%E6%89%93%E5%8D%B0%E6%9C%BA-cc0724cf-793e-3542-d1ff-727e4978638b

辐射骚扰整改思路及方法:辐射超标与问题定位 ?

某产品首次EMC测试时&#xff0c;辐射、静电、浪涌均失败。本篇文章就“辐射超标与问题定位”问题进行详细讨论。 一、辐射超标 50MHz 、100MHz 、130MHz 、200MHz&#xff0c;4个频点明显超标&#xff0c;其中130MHz 左右最明显&#xff0c;超出 19dB&#xff1b;后将电路板…

CRM软件:打造高效率团队

对于一家企业来说团队配合紧密&#xff0c;沟通无障碍是业绩增长的基础&#xff0c;要做到高效率团队协作除了需要管理者制定策略还要依赖数字化工具的加成&#xff0c;比如利用CRM软件打造高效团队。 直观展示工作进度 大多数企业每个月都要制作工作报告、频繁召开会议不断的…

plt.imshow()的用法和参数介绍

函数说明 plt.imshow()是Matplotlib中的一个函数&#xff0c;用于显示图像。它可以传递一个二维或三维数组作为image参数&#xff0c; 并将图像数据显示为图形&#xff0c;并对图像进行不同的可视化设置。 关于二维/三维数组的解释说明 image支持的数组形状包括&#xff1a;…

马斯克的AI大模型登场

(有兴趣的可以直接访问官网&#xff1a;Announcing Grok (x.ai)) 对于大火的人工智能&#xff0c;一向冲锋在前的马斯克却表现得慎之又慎。今年4月&#xff0c;马斯克成立xAI&#xff0c;加入AI大战。经过半年多的酝酿&#xff0c;当地时间11月4日&#xff0c;马斯克旗下社交媒…

如何使用 Loadgen 来简化 HTTP API 请求的集成测试

引言 在编写 HTTP 服务的过程中&#xff0c;集成测试 1 是保证程序正确性的重要一环&#xff0c;如下图所示&#xff0c;其基本的流程就是不断向服务发起请求然后校验响应的状态和数据等&#xff1a; 为大量的 API 和用例编写测试是一件繁琐的工作&#xff0c;而 Loadgen 2 正…

-- Could NOT find livox_ros_driver (missing: livox_ros_driver_DIR)

原因 缺少livox_ros_driver 包 解决办法如下 livox_ros_driver 地址 https://github.com/Livox-SDK/livox_ros_driver 下载下来放入ros的工作目录

pyspark连接mysql数据库报错

使用pyspark连接mysql数据库代码如下 spark_conf SparkConf().setAppName("MyApp").setMaster("local")spark SparkSession.builder.config(confspark_conf).getOrCreate()url "jdbc:mysql://localhost:3306/test?useUnicodetrue&characterE…