一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳解自定義SpringMVC的Http信息轉換器的使用

詳解自定義SpringMVC的Http信息轉換器的使用

2021-02-24 13:54等風de帆 Java教程

這篇文章主要介紹了詳解自定義SpringMVC的Http信息轉換器的使用,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

HttpInputMessage

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

?
1
2
3
4
5
6
7
8
9
10
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的消息轉換器所作用的受體“響應消息”的內部抽象,消息轉換器將“響應消息”按照一定的規則寫到響應報文中。

?
1
2
3
4
5
6
7
8
9
10
package org.springframework.http;
 
import java.io.IOException;
import java.io.OutputStream;
 
public interface HttpOutputMessage extends HttpMessage {
 
  OutputStream getBody() throws IOException;
 
}

HttpMessageConverter

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
 * 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 :判斷該轉換器是否能將請求內容轉換成Java對象
  2. canWrite :判斷該轉換器是否可以將Java對象轉換成返回內容
  3. getSupportedMediaTypes :獲得該轉換器支持的MediaType類型
  4. read :讀取請求內容并轉換成Java對象
  5. write :將Java對象轉換后寫入返回內容

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

當前Spring中已經默認提供了相當多的轉換器,分別有:

 

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

 

HttpMessageConverter匹配過程:

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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注解時:根據Request對象header部分的Accept屬性(逗號分隔),逐一按accept中的類型,去遍歷找到能處理的HttpMessageConverter。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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轉換器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class CustomJsonHttpMessageConverter implements HttpMessageConverter {
 
  //Jackson的Json映射類
  private ObjectMapper mapper = new ObjectMapper();
 
  //該轉換器的支持類型:application/json
  private List supportedMediaTypes = Arrays.asList(MediaType.APPLICATION_JSON);
 
  /**
   * 判斷轉換器是否可以將輸入內容轉換成Java類型
   * @param clazz   需要轉換的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;
  }
 
  /**
   * 判斷轉換器是否可以將Java類型轉換成指定輸出內容
   * @param clazz   需要轉換的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;
  }
 
  /**
   * 獲得該轉換器支持的MediaType
   * @return
   */
  @Override
  public List getSupportedMediaTypes() {
    return supportedMediaTypes;
  }
 
  /**
   * 讀取請求內容,將其中的Json轉換成Java對象
   * @param clazz     需要轉換的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對象轉換成Json返回內容
   * @param o       需要轉換的對象
   * @param contentType  返回類型
   * @param outputMessage 回執對象
   * @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 方法向返回結果的輸出流中寫入數據,所以只需要重寫該方法即可:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
  return new MappingJackson2HttpMessageConverter() {
    //重寫writeInternal方法,在返回內容前首先進行加密
    @Override
    protected void writeInternal(Object object,
                   HttpOutputMessage outputMessage) throws IOException,
        HttpMessageNotWritableException {
      //使用Jackson的ObjectMapper將Java對象轉換成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());
    }
  };
}

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

?
1
2
3
4
5
6
//添加自定義轉換器
@Override
public void configureMessageConverters(List<httpmessageconverter<?>> converters) {
  converters.add(mappingJackson2HttpMessageConverter());
  super.configureMessageConverters(converters);
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://blog.csdn.net/L_Sail/article/details/70209845

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 恩爱夫妇交换小说 | juliaann大战黑人| 色噜噜 男人的天堂在线观看 | 亚洲精品综合一区二区 | 日韩一级欧美一级一级国产 | 无码人妻丰满熟妇啪啪网不卡 | 美女张开双腿让男人捅 | 天堂俺去俺来也www久久婷婷 | 996热精品视频在线观看 | 国产精品亚洲片在线观看麻豆 | 成年人在线视频观看 | 视频在线观看高清免费 | 91精品婷婷国产综合久久8 | 天天操丝袜 | 青青青视频免费观看 | 192.168.191 | 男人j桶进女人p桶爽 | 国产一级特黄在线播放 | 日韩v | 视频二区 素人 制服 国产 | 亚洲高清一区二区三区久久 | 美女福利视频一区二区 | 免费理伦片高清在线 | 久久这里只精品国产99re66 | 亚洲精品短视频 | 日本成人黄色片 | 日本伦理动漫在线观看 | 欧洲喷浆乌克兰 | 日本道色综合久久影院 | 亚洲国产99在线精品一区二区 | 国内在线观看 | 日韩精品国产自在欧美 | 激情五月姐姐 | 黄漫免费观看 | 九九精品99久久久香蕉 | 欧美高清在线不卡免费观看 | 国产悠悠视频在线播放 | 隔壁的漂亮邻居hd中文 | 午夜想想爱| 国产一区国产二区国产三区 | 嫩草蜜桃 |