1. 程式人生 > 程式設計 >SpringBoot自定義HttpMessageConverter操作

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,MOHcfzLmTc
      ediaType 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提供的預設轉換器已經足夠我們使用,但是在一些介面的引數需要加解密,調整返回體的結構等情況下會用到。以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。