最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解自定義SpringMVC的Http信息轉(zhuǎn)換器的使用

 更新時間:2017年11月30日 09:30:49   作者:等風(fēng)de帆  
這篇文章主要介紹了詳解自定義SpringMVC的Http信息轉(zhuǎn)換器的使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

在SpringMVC中,可以使用@RequestBody和@ResponseBody兩個注解,分別完成請求報文到對象和對象到響應(yīng)報文的轉(zhuǎn)換,底層這種靈活的消息轉(zhuǎn)換機制。使用系統(tǒng)默認(rèn)配置的HttpMessageConverter進行解析,然后把相應(yīng)的數(shù)據(jù)綁定到要返回的對象上。

HttpInputMessage

這個類是SpringMVC內(nèi)部對一次Http請求報文的抽象,在HttpMessageConverter的read()方法中,有一個HttpInputMessage的形參,它正是SpringMVC的消息轉(zhuǎn)換器所作用的受體“請求消息”的內(nèi)部抽象,消息轉(zhuǎn)換器從“請求消息”中按照規(guī)則提取消息,轉(zhuǎn)換為方法形參中聲明的對象。

package org.springframework.http;

import java.io.IOException;
import java.io.InputStream;

public interface HttpInputMessage extends HttpMessage {

  InputStream getBody() throws IOException;

}

HttpOutputMessage

在HttpMessageConverter的write()方法中,有一個HttpOutputMessage的形參,它正是SpringMVC的消息轉(zhuǎn)換器所作用的受體“響應(yīng)消息”的內(nèi)部抽象,消息轉(zhuǎn)換器將“響應(yīng)消息”按照一定的規(guī)則寫到響應(yīng)報文中。

package org.springframework.http;

import java.io.IOException;
import java.io.OutputStream;

public interface HttpOutputMessage extends HttpMessage {

  OutputStream getBody() throws IOException;

}

HttpMessageConverter

/*
 * Copyright 2002-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.http.converter;

import java.io.IOException;
import java.util.List;

import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;


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;

}

HttpMessageConverter 接口提供了5個方法:

  1. canRead :判斷該轉(zhuǎn)換器是否能將請求內(nèi)容轉(zhuǎn)換成Java對象
  2. canWrite :判斷該轉(zhuǎn)換器是否可以將Java對象轉(zhuǎn)換成返回內(nèi)容
  3. getSupportedMediaTypes :獲得該轉(zhuǎn)換器支持的MediaType類型
  4. read :讀取請求內(nèi)容并轉(zhuǎn)換成Java對象
  5. write :將Java對象轉(zhuǎn)換后寫入返回內(nèi)容

其中 read 和 write 方法的參數(shù)分別有有 HttpInputMessage 和 HttpOutputMessage 對象,這兩個對象分別代表著一次Http通訊中的請求和響應(yīng)部分,可以通過 getBody 方法獲得對應(yīng)的輸入流和輸出流。

當(dāng)前Spring中已經(jīng)默認(rèn)提供了相當(dāng)多的轉(zhuǎn)換器,分別有:

名稱 作用 讀支持MediaType 寫支持MediaType
ByteArrayHttpMessageConverter 數(shù)據(jù)與字節(jié)數(shù)組的相互轉(zhuǎn)換 / application/octet-stream
StringHttpMessageConverter 數(shù)據(jù)與String類型的相互轉(zhuǎn)換 text/* text/plain
FormHttpMessageConverter 表單與MultiValueMap<string, string=””>的相互轉(zhuǎn)換 application/x-www-form-urlencoded application/x-www-form-urlencoded
SourceHttpMessageConverter 數(shù)據(jù)與javax.xml.transform.Source的相互轉(zhuǎn)換 text/xml和application/xml text/xml和application/xml
MarshallingHttpMessageConverter 使用SpringMarshaller/Unmarshaller轉(zhuǎn)換XML數(shù)據(jù) text/xml和application/xml text/xml和application/xml
MappingJackson2HttpMessageConverter 使用Jackson的ObjectMapper轉(zhuǎn)換Json數(shù)據(jù) application/json application/json
MappingJackson2XmlHttpMessageConverter 使用Jackson的XmlMapper轉(zhuǎn)換XML數(shù)據(jù) application/xml application/xml
BufferedImageHttpMessageConverter 數(shù)據(jù)與java.awt.image.BufferedImage的相互轉(zhuǎn)換 Java I/O API支持的所有類型 Java I/O API支持的所有類型

HttpMessageConverter匹配過程:

@RequestBody注解時: 根據(jù)Request對象header部分的Content-Type類型,逐一匹配合適的HttpMessageConverter來讀取數(shù)據(jù)。

private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType) throws Exception { 

  MediaType contentType = inputMessage.getHeaders().getContentType(); 
  if (contentType == null) { 
    StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType())); 
    String paramName = methodParam.getParameterName(); 
    if (paramName != null) { 
      builder.append(' '); 
      builder.append(paramName); 
    } 
    throw new HttpMediaTypeNotSupportedException("Cannot extract parameter (" + builder.toString() + "): no Content-Type found"); 
  } 

  List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); 
  if (this.messageConverters != null) { 
    for (HttpMessageConverter<?> messageConverter : this.messageConverters) { 
      allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); 
      if (messageConverter.canRead(paramType, contentType)) { 
        if (logger.isDebugEnabled()) { 
          logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType + "\" using [" + messageConverter + "]"); 
        } 
        return messageConverter.read(paramType, inputMessage); 
      } 
    } 
  } 
  throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); 
}

@ResponseBody注解時:根據(jù)Request對象header部分的Accept屬性(逗號分隔),逐一按accept中的類型,去遍歷找到能處理的HttpMessageConverter。

private void writeWithMessageConverters(Object returnValue, HttpInputMessage inputMessage, HttpOutputMessage outputMessage) 
        throws IOException, HttpMediaTypeNotAcceptableException { 
  List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept(); 
  if (acceptedMediaTypes.isEmpty()) { 
    acceptedMediaTypes = Collections.singletonList(MediaType.ALL); 
  } 
  MediaType.sortByQualityValue(acceptedMediaTypes); 
  Class<?> returnValueType = returnValue.getClass(); 
  List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); 
  if (getMessageConverters() != null) { 
    for (MediaType acceptedMediaType : acceptedMediaTypes) { 
      for (HttpMessageConverter messageConverter : getMessageConverters()) { 
        if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { 
          messageConverter.write(returnValue, acceptedMediaType, outputMessage); 
          if (logger.isDebugEnabled()) { 
            MediaType contentType = outputMessage.getHeaders().getContentType(); 
            if (contentType == null) { 
              contentType = acceptedMediaType; 
            } 
            logger.debug("Written [" + returnValue + "] as \"" + contentType + 
                "\" using [" + messageConverter + "]"); 
          } 
          this.responseArgumentUsed = true; 
          return; 
        } 
      } 
    } 
    for (HttpMessageConverter messageConverter : messageConverters) { 
      allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); 
    } 
  } 
  throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes); 
}

自定義一個JSON轉(zhuǎn)換器

class CustomJsonHttpMessageConverter implements HttpMessageConverter {

  //Jackson的Json映射類
  private ObjectMapper mapper = new ObjectMapper();

  //該轉(zhuǎn)換器的支持類型:application/json
  private List supportedMediaTypes = Arrays.asList(MediaType.APPLICATION_JSON);

  /**
   * 判斷轉(zhuǎn)換器是否可以將輸入內(nèi)容轉(zhuǎn)換成Java類型
   * @param clazz   需要轉(zhuǎn)換的Java類型
   * @param mediaType 該請求的MediaType
   * @return
   */
  @Override
  public boolean canRead(Class clazz, MediaType mediaType) {
    if (mediaType == null) {
      return true;
    }
    for (MediaType supportedMediaType : getSupportedMediaTypes()) {
      if (supportedMediaType.includes(mediaType)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 判斷轉(zhuǎn)換器是否可以將Java類型轉(zhuǎn)換成指定輸出內(nèi)容
   * @param clazz   需要轉(zhuǎn)換的Java類型
   * @param mediaType 該請求的MediaType
   * @return
   */
  @Override
  public boolean canWrite(Class clazz, MediaType mediaType) {
    if (mediaType == null || MediaType.ALL.equals(mediaType)) {
      return true;
    }
    for (MediaType supportedMediaType : getSupportedMediaTypes()) {
      if (supportedMediaType.includes(mediaType)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 獲得該轉(zhuǎn)換器支持的MediaType
   * @return
   */
  @Override
  public List getSupportedMediaTypes() {
    return supportedMediaTypes;
  }

  /**
   * 讀取請求內(nèi)容,將其中的Json轉(zhuǎn)換成Java對象
   * @param clazz     需要轉(zhuǎn)換的Java類型
   * @param inputMessage 請求對象
   * @return
   * @throws IOException
   * @throws HttpMessageNotReadableException
   */
  @Override
  public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
    return mapper.readValue(inputMessage.getBody(), clazz);
  }

  /**
   * 將Java對象轉(zhuǎn)換成Json返回內(nèi)容
   * @param o       需要轉(zhuǎn)換的對象
   * @param contentType  返回類型
   * @param outputMessage 回執(zhí)對象
   * @throws IOException
   * @throws HttpMessageNotWritableException
   */
  @Override
  public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
    mapper.writeValue(outputMessage.getBody(), o);
  }
}

自定義MappingJackson2HttpMessage

從 MappingJackson2HttpMessageConverter 的父類 AbstractHttpMessageConverter 中的 write 方法可以看出,該方法通過 writeInternal 方法向返回結(jié)果的輸出流中寫入數(shù)據(jù),所以只需要重寫該方法即可:

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
  return new MappingJackson2HttpMessageConverter() {
    //重寫writeInternal方法,在返回內(nèi)容前首先進行加密
    @Override
    protected void writeInternal(Object object,
                   HttpOutputMessage outputMessage) throws IOException,
        HttpMessageNotWritableException {
      //使用Jackson的ObjectMapper將Java對象轉(zhuǎn)換成Json String
      ObjectMapper mapper = new ObjectMapper();
      String json = mapper.writeValueAsString(object);
      LOGGER.error(json);
      //加密
      String result = json + "加密了!";
      LOGGER.error(result);
      //輸出
      outputMessage.getBody().write(result.getBytes());
    }
  };
}
 

在這之后還需要將這個自定義的轉(zhuǎn)換器配置到Spring中,這里通過重寫 WebMvcConfigurer 中的 configureMessageConverters 方法添加自定義轉(zhuǎn)換器:

//添加自定義轉(zhuǎn)換器
@Override
public void configureMessageConverters(List<httpmessageconverter<?>> converters) {
  converters.add(mappingJackson2HttpMessageConverter());
  super.configureMessageConverters(converters);
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot應(yīng)用啟動流程源碼解析

    SpringBoot應(yīng)用啟動流程源碼解析

    這篇文章主要介紹了SpringBoot應(yīng)用啟動流程源碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • Shiro在springboot中快速實現(xiàn)方法

    Shiro在springboot中快速實現(xiàn)方法

    Apache Shiro是一個Java的安全(權(quán)限)框架,可以容易的開發(fā)出足夠好的應(yīng)用,既可以在JavaEE中使用,也可以在JavaSE中使用,這篇文章主要介紹了Shiro在springboot中快速實現(xiàn),需要的朋友可以參考下
    2023-02-02
  • java swing標(biāo)準(zhǔn)對話框具體實現(xiàn)

    java swing標(biāo)準(zhǔn)對話框具體實現(xiàn)

    這篇文章介紹了swing標(biāo)準(zhǔn)對話框的具體實現(xiàn)方法,有需要的朋友可以參考一下
    2013-06-06
  • 使用controller傳boolean形式值

    使用controller傳boolean形式值

    這篇文章主要介紹了使用controller傳boolean形式值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java中classpath的基本概念和配置方法詳析

    Java中classpath的基本概念和配置方法詳析

    這篇文章主要介紹了Java中的classpath概念,包括其基本概念、設(shè)置方法以及在Java應(yīng)用中的作用,在IDE中的配置也進行了詳細(xì)說明,并提到了一些通用注意事項,需要的朋友可以參考下
    2025-02-02
  • Java ObjectMapper使用詳解

    Java ObjectMapper使用詳解

    ObjectMapper類是Jackson的主要類,它可以幫助我們快速的進行各個類型和Json類型的相互轉(zhuǎn)換,本文給大家介紹Java ObjectMapper的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • Java中Scanner類使用保姆級教程

    Java中Scanner類使用保姆級教程

    JavaSE在java.util類庫中提供了一個專門用于輸入操作的類Scanner類,可以使用該類創(chuàng)建一個對象,然后利用該對象的相關(guān)方法從鍵盤上讀取數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于Java中Scanner類使用的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • 淺談Java平臺無關(guān)性

    淺談Java平臺無關(guān)性

    這篇文章主要介紹了淺談Java平臺無關(guān)性,對此感興趣的同學(xué),可以多了解一下
    2021-04-04
  • AsyncHttpClient KeepAliveStrategy源碼流程解讀

    AsyncHttpClient KeepAliveStrategy源碼流程解讀

    這篇文章主要為大家介紹了AsyncHttpClient KeepAliveStrategy源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Spring注解@RestControllerAdvice原理解析

    Spring注解@RestControllerAdvice原理解析

    這篇文章主要介紹了Spring注解@RestControllerAdvice原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11

最新評論

收藏| 大竹县| 鱼台县| 张家港市| 清镇市| 临海市| 芦溪县| 天长市| 贺州市| 柘荣县| 化州市| 玉田县| 嘉定区| 郓城县| 陈巴尔虎旗| 陇川县| 玉环县| 宁强县| 乡城县| 调兵山市| 潢川县| 手游| 信丰县| 九江县| 芦溪县| 曲靖市| 阳高县| 蓬溪县| 大连市| 灵武市| 仁化县| 南阳市| 榕江县| 土默特左旗| 丹棱县| 仁化县| 同心县| 石楼县| 赤城县| 油尖旺区| 福州市|