SpringBoot自定義MessageConverter與內(nèi)容協(xié)商管理器contentNegotiationManager詳解
1、自定義消息轉(zhuǎn)換器MessageConverter
在WebMvcAutoConfiguration類中有一個方法configureMessageConverters(),它會配置默認的MessageConverter
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.messageConvertersProvider.ifAvailable((customConverters) -> {
converters.addAll(customConverters.getConverters());
});
}
假設(shè)我們現(xiàn)在有一個新的需求
想要后端返回我們自己定義的格式的數(shù)據(jù),就叫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);
}
/**
* 統(tǒng)計當前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 {
// 自定義想要寫出的數(shù)據(jù)格式
String result = person.getName() + ";" + person.getAge() + ";" + person.getBirth();
// 寫出
final OutputStream body = outputMessage.getBody();
body.write(result.getBytes());
}
}我們發(fā)現(xiàn),WebMvcConfigurer接口類下面有2個關(guān)于配置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());
}
};
}
}我們在請求頭中設(shè)置Accept為我們自定義的格式application/x-decade

驗證結(jié)果如下

2、自定義內(nèi)容協(xié)商管理器contentNegotiationManager
問題:我們新建的x-decade格式是否只能通過postman調(diào)用才會生效呢?如果我們要使用瀏覽器參數(shù)方式,怎么才能生效呢?
因為我們之前的【Spring Boot】響應(yīng)處理
它默認只能處理xml和json格式,所以為了解決這個問題,我們就要自定義內(nèi)容協(xié)商管理器了
首先我們還是要在自定義配置類中重寫相關(guān)方法
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) {
// 設(shè)置支持的瀏覽器參數(shù)類型
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);
// 為了繼續(xù)支持請求頭參數(shù)類型,還需要往里面塞請求頭內(nèi)容協(xié)商管理器
final HeaderContentNegotiationStrategy headerContentNegotiationStrategy = new HeaderContentNegotiationStrategy();
configurer.strategies(Arrays.asList(strategy, headerContentNegotiationStrategy));
}
};
}
}可以看到,系統(tǒng)中的內(nèi)容協(xié)商管理器下面還是原來的2種:獲取請求頭中的Accept和獲取請求參數(shù)中的format
但是獲取請求參數(shù)format,除了能識別原來的json和xml,還能識別我們自定義的application/x-decade,它使用decade與之對應(yīng)

可以看到,我們自定義的媒體類型成功加入服務(wù)器能解析出來的類型

我們寫一個接口進行驗證
@GetMapping(value = "/testPerson")
@ResponseBody
public Person testPerson() {
Person person = new Person();
person.setName("decade");
person.setAge(24);
person.setBirth(new Date());
return person;
}由驗證結(jié)果可以知道,我們從postman和瀏覽器都可以獲得我們指定格式的數(shù)據(jù)


到此這篇關(guān)于SpringBoot自定義MessageConverter與內(nèi)容協(xié)商管理器contentNegotiationManager詳解的文章就介紹到這了,更多相關(guān)SpringBoot MessageConverter內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Springboot項目報錯:java:錯誤:不支持發(fā)行版本?17
這篇文章主要給大家介紹了關(guān)于解決Springboot項目報錯:java:錯誤:不支持發(fā)行版本17的相關(guān)資料,這個錯誤意味著你的Spring Boot項目正在使用Java 17這個版本,但是你的項目中未配置正確的Java版本,需要的朋友可以參考下2023-08-08

