SpringBoot自定义MessageConverter与内容协商管理器contentNegotiationManager详解
作者:Decade0712 发布时间:2023-11-28 11:35:54
1、自定义消息转换器MessageConverter
在WebMvcAutoConfiguration类中有一个方法configureMessageConverters(),它会配置默认的MessageConverter
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.messageConvertersProvider.ifAvailable((customConverters) -> {
converters.addAll(customConverters.getConverters());
});
}
假设我们现在有一个新的需求
想要后端返回我们自己定义的格式的数据,就叫x-decade,格式为使用分号拼接Person对象属性值
那么就要新建一个MessageConverter了
package com.decade.converters;
import com.decade.pojo.Person;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class DecadeConverter implements HttpMessageConverter<Person> {
// 只考虑写出,所以这里默认写false
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return clazz.isAssignableFrom(Person.class);
}
/**
* 统计当前converter能支持哪些类型
* @return 返回支持的媒体类型
*/
@Override
public List<MediaType> getSupportedMediaTypes() {
return MediaType.parseMediaTypes("application/x-decade");
}
// 只考虑写出,所以这里默认写null
@Override
public Person read(Class<? extends Person> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
public void write(Person person, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
// 自定义想要写出的数据格式
String result = person.getName() + ";" + person.getAge() + ";" + person.getBirth();
// 写出
final OutputStream body = outputMessage.getBody();
body.write(result.getBytes());
}
}
我们发现,WebMvcConfigurer接口类下面有2个关于配置MessageConverter的方法
// 会覆盖默认的MessageConverter
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
// 不会覆盖,只会在默认的MessageConverter后面追加我们自定义的
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
所以,我们选择在自定义配置类中重写extendMessageConverters()方法
package com.decade.config;
import com.decade.converters.DecadeConverter;
import org.springframework.context.annotation.Bean;
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(proxyBeanMethods = false)
public class MyMvcConfig implements WebMvcConfigurer {
@Bean
public WebMvcConfigurer createConvert() {
return new WebMvcConfigurer() {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new DecadeConverter());
}
};
}
}
我们在请求头中设置Accept为我们自定义的格式application/x-decade
验证结果如下
2、自定义内容协商管理器contentNegotiationManager
问题:我们新建的x-decade格式是否只能通过postman调用才会生效呢?如果我们要使用浏览器参数方式,怎么才能生效呢?
因为我们之前的【Spring Boot】响应处理
它默认只能处理xml和json格式,所以为了解决这个问题,我们就要自定义内容协商管理器了
首先我们还是要在自定义配置类中重写相关方法
package com.decade.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.accept.ParameterContentNegotiationStrategy;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration(proxyBeanMethods = false)
public class MyMvcConfig implements WebMvcConfigurer {
@Bean
public WebMvcConfigurer createConvert() {
return new WebMvcConfigurer() {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
// 设置支持的浏览器参数类型
Map<String, MediaType> mediaTypes = new HashMap<>();
mediaTypes.put("json", MediaType.APPLICATION_JSON);
mediaTypes.put("xml", MediaType.APPLICATION_XML);
mediaTypes.put("decade", MediaType.parseMediaType("application/x-decade"));
final ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(mediaTypes);
// 为了继续支持请求头参数类型,还需要往里面塞请求头内容协商管理器
final HeaderContentNegotiationStrategy headerContentNegotiationStrategy = new HeaderContentNegotiationStrategy();
configurer.strategies(Arrays.asList(strategy, headerContentNegotiationStrategy));
}
};
}
}
可以看到,系统中的内容协商管理器下面还是原来的2种:获取请求头中的Accept和获取请求参数中的format
但是获取请求参数format,除了能识别原来的json和xml,还能识别我们自定义的application/x-decade,它使用decade与之对应
可以看到,我们自定义的媒体类型成功加入服务器能解析出来的类型
我们写一个接口进行验证
@GetMapping(value = "/testPerson")
@ResponseBody
public Person testPerson() {
Person person = new Person();
person.setName("decade");
person.setAge(24);
person.setBirth(new Date());
return person;
}
由验证结果可以知道,我们从postman和浏览器都可以获得我们指定格式的数据
来源:https://blog.csdn.net/Decade0712/article/details/126690183
猜你喜欢
- 前言坚持是一件比较难的事,坚持并不是自欺欺人的一种自我麻痹和安慰,也不是做给被人的,我觉得,坚持的本质并没有带着过多的功利主义,如果满是功利
- 引言最近在工作中结合线程池使用 InheritableThreadLocal 出现了获取线程变量“错误&rdqu
- 1. 概述官方JavaDocsApi: javax.swing.JTextAreaJTextArea,文本区域。JTextArea 用来编辑
- 昨天有朋友在公众号发消息说看不懂await,async执行流,其实看不懂太正常了,因为你没经过社会的毒打,没吃过牢饭就不知道自由有多重要,没
- java缓冲流本身不具IO功能,只是在别的流上加上缓冲提高效率,像是为别的流装上一种包装。当对文件或其他目标频繁读写或操作效率低,效能差。这
- Spring Boot产生环形注入***************************APPLICATION FAILED TO STAR
- 一、输入输出流对象cout:标准输出流cerr:标准出凑 和cout(只是用于如果是错误时要输出的)cin :&nb
- 本文实例讲述了java生成XML的方法。分享给大家供大家参考,具体如下:下拉框的生成,我是通过javascript读取xml文件生成的。Xm
- 定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。类型:行为类模式类图:例子:例如
- @ConditionalOnProperty作用及用法在spring boot中有时候需要控制配置类是否生效,可以使用@Conditiona
- 背景在接口请求过程中,传递json对象,springboot转换为实体VO对象后,所有属性都为null。post请求:后台接收请求:当时就懵
- 前几篇主要集中在注册中心eureka的使用上,接下来可以创建服务提供者provider来注册到eureka。demo源码见: https:/
- 一、Java后端使用MultipartFile@PostMapping(value = "/upload")  
- 目录1.搭建环境2.项目搭建3.配置maven4.项目结构5.配置 MapperScan 注解6.创建实体7.创建接口8.测试8.1 upd
- 前言前面一篇我们介绍了使用 shared_preferences实现简单的键值对存储,然而我们还会面临更为复杂的本地存储。比如资讯类 App
- 1. 并行和并发有什么区别?并行:多个处理器或多核处理器同时处理多个任务。并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执
- 表述在一次服务更新后发现每天凌晨0点3秒服务准时挂,开始的时候认为是maven依赖中存在system.exit(3)类似这样的代码,但是我想
- 注:作者使用IDEA + Gradle注:需要有一定的java SpringBoot and SSM+Springcloud基础程序测试错误
- 本文实例为大家分享了java实现简单斗地主的具体代码,供大家参考,具体内容如下第一种方法 /** * @param args */ /**
- 第一种方法:string s=abcdeabcdeabcde;string[] sArray=s.Split(c) ;foreach(str