SpringBoot自定義HttpMessageConverter操作
簡(jiǎn)介
我們使用**@RequestBody可以將請(qǐng)求體中的JSON字符串綁定到相應(yīng)的bean,使用@ResponseBody**可以使返回結(jié)果不會(huì)被解析為跳轉(zhuǎn)路徑,而是直接寫(xiě)入 HTTP response body 中,而整個(gè)數(shù)據(jù)綁定的過(guò)程其實(shí)是HttpMessageConverter在起作用。
MediaType
MediaType,即是Internet Media Type,互聯(lián)網(wǎng)媒體類型;也叫做MIME類型,在Http協(xié)議消息頭中,使用Content-Type來(lái)表示具體請(qǐng)求中的媒體類型信息。
@RequestBody的簡(jiǎn)單實(shí)用
@requestBody注解常用來(lái)處理content-type不是默認(rèn)的application/x-www-form-urlcoded編碼的內(nèi)容,比如說(shuō):application/json或者是application/xml等。一般情況下來(lái)說(shuō)常用其來(lái)處理application/json類型。
1、解析json
Content-Type: application/json
請(qǐng)求數(shù)據(jù)格式
{ "question": "aaa", "fromUser": "bbb" }
2、解析xml
Content-Type: application/xml
請(qǐng)求數(shù)據(jù)格式
<?xml version='1.0' encoding="utf-8"?> <Request> <question>aaa</question> <fromUser>bbb</fromUser> </Request>
上面兩種方式都是可以把數(shù)據(jù)映射到Bean中的。
3、原理
Spring會(huì)根據(jù)MediaType查找合適的HttpMessageConverter的實(shí)現(xiàn)類進(jì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ù)寫(xiě)到response的body中 |
@ResponseBody
ResponseBody中的使用和RequestBody類似
自定義HttpMessageConverter
1、目的
SpringBoot提供一系列的HttpMessageConverter,滿足了我們的絕大部分需求,如果有特性需求,我們可以編寫(xiě)自定義的轉(zhuǎn)換器
2、步驟
編寫(xiě)Converter類,需要實(shí)現(xiàn)HttpMessageConverter,或者繼承已經(jīng)存在的實(shí)現(xiàn)類,并重寫(xiě)上文中的關(guān)鍵方法
編寫(xiě)WebConfig(extends WebMvcConfigurerAdapter)
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { /** * 自定義message_convert */ @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { // 把converter添加到converters的最后(SpringBoot會(huì)使用第一個(gè)匹配到的Converter) converters.add(new XxxConverter()); // 把converter添加到converters的最前面 // converters.add(0, new XxxConverter()); } }
到此為止,我們自定義的Converter已經(jīng)生效了
3、自定義MediaType
雖然我們已經(jīng)編寫(xiě)Converter,但是我們一般會(huì)為自定義的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ù)這個(gè)方法的返回,以及Controller—@RequestMapping中指定的MediaType,判斷是否可用于當(dāng)前請(qǐng)求/返回。
在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是指定請(qǐng)求的MediaType,需要調(diào)用方設(shè)置成我們提供的application/custom-media
produces是指定返回的MediaType,如果我們?cè)O(shè)置成application/custom-media,那么方法返回的數(shù)據(jù)就會(huì)通過(guò)自定義的XxxConverter進(jìn)行轉(zhuǎn)換。
問(wèn)題
注意:如果我們修改了produces的MediaType,那么HTTP返回中的MediaType也會(huì)是我們自定義的類型,除非和調(diào)用方約定好,否則調(diào)用方是沒(méi)有辦法解析的。
解決辦法:
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,要不然請(qǐng)求方會(huì)無(wú)法解析 ((ServletServerHttpResponse) outputMessage) .getServletResponse().setHeader("Content-Type",APPLICATION_JSON_UTF8_VALUE); } }
總結(jié)
一般情況下,SpringBoot提供的默認(rèn)轉(zhuǎn)換器已經(jīng)足夠我們使用,但是在一些接口的參數(shù)需要加解密,調(diào)整返回體的結(jié)構(gòu)等情況下會(huì)用到。以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)刪除排序數(shù)組中重復(fù)元素的方法小結(jié)【三種方法比較】
這篇文章主要介紹了Java實(shí)現(xiàn)刪除排序數(shù)組中重復(fù)元素的方法,結(jié)合實(shí)例形式對(duì)比分析了三種常見(jiàn)的數(shù)組元素刪除算法操作技巧,需要的朋友可以參考下2019-02-02關(guān)于MybatisPlus配置雙數(shù)據(jù)庫(kù)驅(qū)動(dòng)連接數(shù)據(jù)庫(kù)問(wèn)題
這篇文章主要介紹了MybatisPlus配置雙數(shù)據(jù)庫(kù)驅(qū)動(dòng)連接數(shù)據(jù)庫(kù)的具體實(shí)現(xiàn),具體的業(yè)務(wù)邏輯,在service層的類或者方法上面添加@DataSource注解來(lái)指定該業(yè)務(wù)需要用到的數(shù)據(jù)源,需要的朋友可以參考下2022-01-01java加密MD5實(shí)現(xiàn)及密碼驗(yàn)證代碼實(shí)例
這篇文章主要介紹了java加密MD5實(shí)現(xiàn)及密碼驗(yàn)證代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12java代碼實(shí)現(xiàn)銀行管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java代碼實(shí)現(xiàn)銀行管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12JAVA加密算法數(shù)字簽名實(shí)現(xiàn)原理詳解
這篇文章主要介紹了JAVA加密算法數(shù)字簽名實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Java實(shí)現(xiàn)的權(quán)重算法(按權(quán)重展現(xiàn)廣告)
這篇文章主要介紹了Java實(shí)現(xiàn)的權(quán)重算法(按權(quán)重展現(xiàn)廣告),本文講解了算法實(shí)現(xiàn)原理和實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04java(swing)+ mysql實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)源碼
這篇文章主要分享了java mysql實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)的源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11多線程計(jì)數(shù),怎么保持計(jì)數(shù)準(zhǔn)確的方法
這篇文章主要介紹了多線程計(jì)數(shù)的方法,有需要的朋友可以參考一下2014-01-01