SpringBoot自定義HttpMessageConverter操作
簡介
我們使用**@RequestBody可以將請求體中的JSON字符串綁定到相應(yīng)的bean,使用@ResponseBody**可以使返回結(jié)果不會被解析為跳轉(zhuǎn)路徑,而是直接寫入 HTTP response body 中,而整個數(shù)據(jù)綁定的過程其實是HttpMessageConverter在起作用。
MediaType
MediaType,即是Internet Media Type,互聯(lián)網(wǎng)媒體類型;也叫做MIME類型,在Http協(xié)議消息頭中,使用Content-Type來表示具體請求中的媒體類型信息。
@RequestBody的簡單實用
@requestBody注解常用來處理content-type不是默認的application/x-www-form-urlcoded編碼的內(nèi)容,比如說:application/json或者是application/xml等。一般情況下來說常用其來處理application/json類型。
1、解析json
Content-Type: application/json
請求數(shù)據(jù)格式
{
"question": "aaa",
"fromUser": "bbb"
}
2、解析xml
Content-Type: application/xml
請求數(shù)據(jù)格式
<?xml version='1.0' encoding="utf-8"?> <Request> <question>aaa</question> <fromUser>bbb</fromUser> </Request>
上面兩種方式都是可以把數(shù)據(jù)映射到Bean中的。
3、原理
Spring會根據(jù)MediaType查找合適的HttpMessageConverter的實現(xiàn)類進行序列化的操作
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, MediaType mediaType);
boolean canWrite(Class<?> clazz, MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
| 方法 | 作用 |
|---|---|
| getSupportedMediaTypes | 獲取支持的MediaType |
| read | 讀取request的body |
| write | 把數(shù)據(jù)寫到response的body中 |
@ResponseBody
ResponseBody中的使用和RequestBody類似
自定義HttpMessageConverter
1、目的
SpringBoot提供一系列的HttpMessageConverter,滿足了我們的絕大部分需求,如果有特性需求,我們可以編寫自定義的轉(zhuǎn)換器
2、步驟
編寫Converter類,需要實現(xiàn)HttpMessageConverter,或者繼承已經(jīng)存在的實現(xiàn)類,并重寫上文中的關(guān)鍵方法
編寫WebConfig(extends WebMvcConfigurerAdapter)
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
/**
* 自定義message_convert
*/
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// 把converter添加到converters的最后(SpringBoot會使用第一個匹配到的Converter)
converters.add(new XxxConverter());
// 把converter添加到converters的最前面
// converters.add(0, new XxxConverter());
}
}
到此為止,我們自定義的Converter已經(jīng)生效了
3、自定義MediaType
雖然我們已經(jīng)編寫Converter,但是我們一般會為自定義的Converter指定可以處理的媒體類型,可以指定自定義的媒體類型
在自定義的Converter中新增自定義的MediaType,并且根據(jù)需要修改canRead,canWrite;
public class XxxConverter implements HttpMessageConverter<Serializable> {
public static final String CUSTOM_MEDIA = "application/custom-media";
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return true;
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return true;
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return Lists.newArrayList(MediaType.parseMediaType(CUSTOM_MEDIA));
}
@Override
public Serializable read(Class<? extends Serializable> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
public void write(Serializable serializable, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
}
}
這里一定要修改getSupportedMediaTypes方法,SpringBoot是根據(jù)這個方法的返回,以及Controller—@RequestMapping中指定的MediaType,判斷是否可用于當前請求/返回。
在Controller的@RequestMapping中指定consumes或者produces
@RestController
@RequestMapping(produces = CUSTOM_MEDIA, consumes = CUSTOM_MEDIA)
@Validated
public class HomeController {
@GetMapping(HOME)
JsonResult info(@RequestHeader("userId") Long userId) {
return JsonResult.ok();
}
}
consumes是指定請求的MediaType,需要調(diào)用方設(shè)置成我們提供的application/custom-media
produces是指定返回的MediaType,如果我們設(shè)置成application/custom-media,那么方法返回的數(shù)據(jù)就會通過自定義的XxxConverter進行轉(zhuǎn)換。
問題
注意:如果我們修改了produces的MediaType,那么HTTP返回中的MediaType也會是我們自定義的類型,除非和調(diào)用方約定好,否則調(diào)用方是沒有辦法解析的。
解決辦法:
public class XxxConverter implements HttpMessageConverter<Serializable> {
......
@Override
public void write(Serializable serializable, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
// 最后把Content-Type改成APPLICATION_JSON_UTF8_VALUE,要不然請求方會無法解析
((ServletServerHttpResponse) outputMessage)
.getServletResponse().setHeader("Content-Type",APPLICATION_JSON_UTF8_VALUE);
}
}
總結(jié)
一般情況下,SpringBoot提供的默認轉(zhuǎn)換器已經(jīng)足夠我們使用,但是在一些接口的參數(shù)需要加解密,調(diào)整返回體的結(jié)構(gòu)等情況下會用到。以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring?Lifecycle?和?SmartLifecycle區(qū)別面試精講
這篇文章主要為大家介紹了Spring?Lifecycle和SmartLifecycle的區(qū)別面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10
java數(shù)據(jù)結(jié)構(gòu)與算法之希爾排序詳解
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之希爾排序,結(jié)合實例形式分析了希爾排序的概念、原理、實現(xiàn)方法與相關(guān)注意事項,需要的朋友可以參考下2017-05-05
如何獲取springboot打成jar后的classpath
這篇文章主要介紹了如何獲取springboot打成jar后的classpath問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
sentinel整合ribbon與fallback流程分步講解
這篇文章主要介紹了sentinel整合ribbon與fallback分步流程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-08-08

