SpringBoot自定義HttpMessageConverter操作
目錄
- 簡介
- MediaType
- @RequestBody的簡單實用
- 1、解析on
- 2、解析xml
- 3、原理
- @ResponseBody
- 自定義HttpMessageConverter
- 1、目的
- 2、步驟
- 3、自定義MediaType
- 問題
- 解決辦法:
- 總結
簡介
我們使用**@RequestBody可以將請求體中的JSON字串繫結到相應的bean,使用@ResponseBody**可以使返回結果不會被解析為跳轉路徑,而是直接寫入 HTTP response body 中,而整個資料繫結的過程其實是HttpMessageConverter在起作用。
MediaType
MediaType,即是Internet Media Type,網際網路媒體型別;也叫做MIME型別,在Http協議訊息頭中,使用Content-Type來表示具體請求中的媒體型別資訊。
@RequestBody的簡單實用
@requestBody註解常用來處理content-type不是預設的application/x-www-form-urlcoded編碼的內容,比如說:application/json或者是application/xml等客棧。一般情況下來說常用其來處理application/json型別。
1、解析json
Content-Type: application/json
請求資料格式
{ "question": "aaa","fromUser": "bbb" }
2、解析xml
Content-Type: application/xml
請求資料格式
<?xml version='1.0' encoding="utf-8"?> <Request> <question>aaa</question> <fromUser>bbb</fromUser> </Request>
上面兩種方式都是可以把資料對映到Bean中的。
3、原理
Spring會根據MediaType查詢合適的HttpMessageConverter的實現類進行序列化的操作
public interface HttpMessageConverter<T> { boolean canRead(Class<?> clazz,MOHcfzLmTcediaType mediaType); boolean canWrite(Class<?> clazz,MediaType mediaType); List<MediaType> getSupportedMediaTypes(); T read(Class<? extends T> clahttp://www.cppcns.comzz,HttpInputMessage inputMessage) throws IOException,HttpMessageNotReadableException; void write(T t,MediaType contentType,HttpOutputMessage outputMessage) throws IOException,HttpMessageNotWritableException; }
方法 | 作用 |
---|---|
getSupportedMediaTypes | 獲取支援的MediaType |
read | 讀取request的body |
write | 把資料寫到response的body中 |
@ResponseBody
ResponseBody中的使用和RequestBody類似
自定義HttpMessageConverter
1、目的
SpringBoot提供一系列的HttpMessageConverter,滿足了我們的絕大部分需求,如果有特性需求,我們可以編寫自定義的轉換器
2、步驟
編寫Converter類,需要實現HttpMessageConverter,或者繼承已經存在的實現類,並重寫上文中的關鍵方法
編寫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已經生效了
3、自定義MediaType
雖然我們已經編寫Converter,但是我們一般會為自定義的Converter指定可以處理的媒體型別,可以指定自定義的媒體型別
在自定義的Converter中新增自定義的MediaType,並且根據需要修改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,HttpOutputMessage outputMessage) throws IOException,HttpMessageNotWritableException { } }
這裡一定要修改getSupportedMediaTypes方法,SpringBoot是根據這個方法的返回,以及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,需要呼叫方設定成我們提供的application/custom-media
produces是指定返回的MediaType,如果我們設定成application/custom-media,那麼方法返回的資料就會通過自定義的XxxConverter進行轉換。
問題
注意:如果我們修改了produces的MediaType,那麼HTTP返回中的MediaType也會是我們自定義的型別,除非和呼叫方約定好,否則呼叫方是沒有辦法解析的。
解決辦法:
public class XxxConverter implements HttpMessageConverter<Serializable> {
......
@Override
public void write(Serializable serializable,HttpMessageNotWritableException {
// 最後把Content-Type改成APPLICATION_JSON_UTF8_VALUE,要不然請求方會無法解析
((ServletServerHttpResponse) outputMessage)
.getServletResponse().setHeader("Content-Type",APwww.cppcns.comPLICATION_JSON_UTF8_VALUE);
}
}
總結
一般情況下,SpringBoot提供的預設轉換器已經足夠我們使用,但是在一些介面的引數需要加解密,調整返回體的結構等情況下會用到。以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。