1.1 前言

  • RequestResponseBodyMethodProcessor 的作用是处理被@RequestBody注解的参数,和@ResponseBody注解的返回值

  • 查看RequestResponseBodyMethodProcessor继承关系,可以看到它是同时继承了HandlerMethodArgumentResolverHandlerMethodReturnValueHandler,所以就是说它同时具有参数对象解析及结果对象解析的功能,野心很大

2.1 解析

RequestResponseBodyMethodProcessor.java

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/**
* 处理被@RequestBody注解的参数,和@ResponseBody注解的返回值
*
* Resolves method arguments annotated with {@code @RequestBody} and handles return
* values from methods annotated with {@code @ResponseBody} by reading and writing
* to the body of the request or response with an {@link HttpMessageConverter}.
*
* <p>An {@code @RequestBody} method argument is also validated if it is annotated
* with {@code @javax.validation.Valid}. In case of validation failure,
* {@link MethodArgumentNotValidException} is raised and results in an HTTP 400
* response status code if {@link DefaultHandlerExceptionResolver} is configured.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
*/
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {

/**
* Basic constructor with converters only. Suitable for resolving
* {@code @RequestBody}. For handling {@code @ResponseBody} consider also
* providing a {@code ContentNegotiationManager}.
*/
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
super(converters);
}

/**
* Basic constructor with converters and {@code ContentNegotiationManager}.
* Suitable for resolving {@code @RequestBody} and handling
* {@code @ResponseBody} without {@code Request~} or
* {@code ResponseBodyAdvice}.
*/
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
ContentNegotiationManager manager) {

super(converters, manager);
}

/**
* Complete constructor for resolving {@code @RequestBody} method arguments.
* For handling {@code @ResponseBody} consider also providing a
* {@code ContentNegotiationManager}.
* @since 4.2
*/
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
List<Object> requestResponseBodyAdvice) {

super(converters, null, requestResponseBodyAdvice);
}

/**
* Complete constructor for resolving {@code @RequestBody} and handling
* {@code @ResponseBody}.
*/
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
ContentNegotiationManager manager, List<Object> requestResponseBodyAdvice) {

super(converters, manager, requestResponseBodyAdvice);
}

/**
* 检测参数是否使用了@RequestBody注解
*
* @param parameter the method parameter to check
* @return
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}

/**
* 检测返回结果是否使用了@ResponseBody注解
*
* @param returnType the method return type to check
* @return
*/
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}

/**
* 处理被@RequestBody注解的参数
*
* Throws MethodArgumentNotValidException if validation fails.
* @throws HttpMessageNotReadableException if {@link RequestBody#required()}
* is {@code true} and there is no body content or if there is no suitable
* converter to read the content with.
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

parameter = parameter.nestedIfOptional();
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);

WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());

return adaptArgumentIfNecessary(arg, parameter);
}

/**
*
* @param webRequest the current request
* @param parameter the method parameter descriptor (may be {@code null})
* @param paramType the type of the argument value to be created
* @param <T>
* @return
* @throws IOException
* @throws HttpMediaTypeNotSupportedException
* @throws HttpMessageNotReadableException
*/
@Override
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);

Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null) {
if (checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getMethod().toGenericString());
}
}
return arg;
}

/**
* 检查RequestBody注解是否required
* @param parameter
* @return
*/
protected boolean checkRequired(MethodParameter parameter) {
return (parameter.getParameterAnnotation(RequestBody.class).required() && !parameter.isOptional());
}

/**
* 处理@ResponseBody注解的返回值
*
* @param returnValue the value returned from the handler method
* @param returnType the type of the return value. This type must have
* previously been passed to {@link #supportsReturnType} which must
* have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param webRequest the current request
* @throws IOException
* @throws HttpMediaTypeNotAcceptableException
* @throws HttpMessageNotWritableException
*/
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

}

2.1.1 处理被@RequestBody注解的参数解析

  • 参数解析需要关注此类是怎么实现的HandlerMethodArgumentResolver接口的
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
public interface HandlerMethodArgumentResolver {

/**
* 是否支持
*
* Whether the given {@linkplain MethodParameter method parameter} is
* supported by this resolver.
* @param parameter the method parameter to check
* @return {@code true} if this resolver supports the supplied parameter;
* {@code false} otherwise
*/
boolean supportsParameter(MethodParameter parameter);

/**
* 根据request解析方法参数值
*
* Resolves a method parameter into an argument value from a given request.
* A {@link ModelAndViewContainer} provides access to the model for the
* request. A {@link WebDataBinderFactory} provides a way to create
* a {@link WebDataBinder} instance when needed for data binding and
* type conversion purposes.
* @param parameter the method parameter to resolve. This parameter must
* have previously been passed to {@link #supportsParameter} which must
* have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param webRequest the current request
* @param binderFactory a factory for creating {@link WebDataBinder} instances
* @return the resolved argument value, or {@code null}
* @throws Exception in case of errors with the preparation of argument values
*/
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;

}
  • 查看boolean supportsParameter(MethodParameter parameter);方法的实现,实现很简单就是判断是否使用了@RequestBody注解
1
2
3
4
5
6
7
8
9
10
/**
* 检测参数是否使用了@RequestBody注解
*
* @param parameter the method parameter to check
* @return
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
  • 查看public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) 方法的实现
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
/**
* 处理被@RequestBody注解的参数
*
* Throws MethodArgumentNotValidException if validation fails.
* @throws HttpMessageNotReadableException if {@link RequestBody#required()}
* is {@code true} and there is no body content or if there is no suitable
* converter to read the content with.
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

parameter = parameter.nestedIfOptional();
// 主体逻辑
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);

WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
// 校验参数是否正确 @Valid注解开启
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
return adaptArgumentIfNecessary(arg, parameter);
}
  • 进入Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
// 主体逻辑
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null) {
if (checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getMethod().toGenericString());
}
}
return arg;
}
  • 继续进入Object arg = readWithMessageConverters(inputMessage, parameter, paramType); ,可以看到是遍历 this.messageConverters ,通过canRead方法判断转换器是否支持对参数的转换,然后执行read方法完成转换。
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/**
* Create the method argument value of the expected parameter type by reading
* from the given HttpInputMessage.
* @param <T> the expected type of the argument value to be created
* @param inputMessage the HTTP input message representing the current request
* @param parameter the method parameter descriptor (may be {@code null})
* @param targetType the target type, not necessarily the same as the method
* parameter type, e.g. for {@code HttpEntity<String>}.
* @return the created method argument value
* @throws IOException if the reading from the request fails
* @throws HttpMediaTypeNotSupportedException if no suitable message converter is found
*/
@SuppressWarnings("unchecked")
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

MediaType contentType;
boolean noContentType = false;
try {
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}

Class<?> contextClass = (parameter != null ? parameter.getContainingClass() : null);
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = (parameter != null ?
ResolvableType.forMethodParameter(parameter) : ResolvableType.forType(targetType));
targetClass = (Class<T>) resolvableType.resolve();
}

HttpMethod httpMethod = ((HttpRequest) inputMessage).getMethod();
Object body = NO_VALUE;

try {
inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);

// 遍历 this.messageConverters 选择适合的消息处理器来处理参数
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
if (converter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
// 判断是否适合处理参数
if (genericConverter.canRead(targetType, contextClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
}
if (inputMessage.getBody() != null) {
inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
body = genericConverter.read(targetType, contextClass, inputMessage);
body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
}
else {
body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
}
break;
}
}
else if (targetClass != null) {
if (converter.canRead(targetClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
}
if (inputMessage.getBody() != null) {
inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
}
else {
body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
}
break;
}
}
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
}

if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && inputMessage.getBody() == null)) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}

return body;
}
  • 查看this.messageConverters有哪些呢?见下图
  • 下图是主要MessageConverter的功能介绍

2.1.2 处理被@ResponseBody注解的返回值解析

  • 返回值解析需要关注此类是怎样实现HandlerMethodArgumentResolver接口的方法的
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
public interface HandlerMethodReturnValueHandler {

/**
* 是否支持
*
* Whether the given {@linkplain MethodParameter method return type} is
* supported by this handler.
* @param returnType the method return type to check
* @return {@code true} if this handler supports the supplied return type;
* {@code false} otherwise
*/
boolean supportsReturnType(MethodParameter returnType);

/**
* 处理结果集
*
* Handle the given return value by adding attributes to the model and
* setting a view or setting the
* {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}
* to indicate the response has been handled directly.
* @param returnValue the value returned from the handler method
* @param returnType the type of the return value. This type must have
* previously been passed to {@link #supportsReturnType} which must
* have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param webRequest the current request
* @throws Exception if the return value handling results in an error
*/
void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

}
  • 查看boolean supportsReturnType(MethodParameter returnType);的方法的实现,实现也很简单就是判断是否使用了@ResponseBody注解
1
2
3
4
5
6
7
8
9
10
11
/**
* 检测返回结果是否使用了@ResponseBody注解
*
* @param returnType the method return type to check
* @return
*/
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
  • 查看public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)的实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    /**
    * 处理@ResponseBody注解的返回值
    *
    * @param returnValue the value returned from the handler method
    * @param returnType the type of the return value. This type must have
    * previously been passed to {@link #supportsReturnType} which must
    * have returned {@code true}.
    * @param mavContainer the ModelAndViewContainer for the current request
    * @param webRequest the current request
    * @throws IOException
    * @throws HttpMediaTypeNotAcceptableException
    * @throws HttpMessageNotWritableException
    */
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
    throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

    mavContainer.setRequestHandled(true);
    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

    // Try even with null return value. ResponseBodyAdvice could get involved.
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
    }

2.1.3 HttpMessageConverter

  • HttpMessageConverter接口定义了5个方法,用于将HTTP请求报文转换为Java对象,以及将Java对象转换为HTTP响应报文。 对应到SpringMVCController方法,read方法即是读取HTTP请求转换为参数对象,write方法即是将返回值对象转换为HTTP响应报文。

  • 代码:

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
/**
* Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
*/
public interface HttpMessageConverter<T> {

/**
* 当前转换器是否能将HTTP报文转换为对象类型
*
* Indicates whether the given class can be read by this converter.
* @param clazz the class to test for readability
* @param mediaType the media type to read (can be {@code null} if not specified);
* typically the value of a {@code Content-Type} header.
* @return {@code true} if readable; {@code false} otherwise
*/
boolean canRead(Class<?> clazz, MediaType mediaType);

/**
* 当前转换器是否能将对象类型转换为HTTP报文
*
* Indicates whether the given class can be written by this converter.
* @param clazz the class to test for writability
* @param mediaType the media type to write (can be {@code null} if not specified);
* typically the value of an {@code Accept} header.
* @return {@code true} if writable; {@code false} otherwise
*/
boolean canWrite(Class<?> clazz, MediaType mediaType);

/**
* 转换器能支持的HTTP媒体类型
*
* Return the list of {@link MediaType} objects supported by this converter.
* @return the list of supported media types
*/
List<MediaType> getSupportedMediaTypes();

/**
* 转换HTTP报文为特定类型
*
* Read an object of the given type from the given input message, and returns it.
* @param clazz the type of object to return. This type must have previously been passed to the
* {@link #canRead canRead} method of this interface, which must have returned {@code true}.
* @param inputMessage the HTTP input message to read from
* @return the converted object
* @throws IOException in case of I/O errors
* @throws HttpMessageNotReadableException in case of conversion errors
*/
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;

/**
* 将特定类型对象转换为HTTP报文
*
* Write an given object to the given output message.
* @param t the object to write to the output message. The type of this object must have previously been
* passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
* @param contentType the content type to use when writing. May be {@code null} to indicate that the
* default content type of the converter must be used. If not {@code null}, this media type must have
* previously been passed to the {@link #canWrite canWrite} method of this interface, which must have
* returned {@code true}.
* @param outputMessage the message to write to
* @throws IOException in case of I/O errors
* @throws HttpMessageNotWritableException in case of conversion errors
*/
void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;

}
  • Spring MVC定义了两个接口来操作这两个过程,参数解析器和返回值处理器在底层处理时,都是通过HttpMessageConverter进行转换。流程如下:

    • 参数解析器HandlerMethodArgumentResolver
    • 返回值处理器HandlerMethodReturnValueHandler
  • 下图是HttpMessageConverter的工作流程图

  • Spring mvc启动时默认会加载下面的几种HttpMessageConverter,相关代码在org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport中的addDefaultHttpMessageConverters
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
/**
* Adds a set of default HttpMessageConverter instances to the given list.
* Subclasses can call this method from {@link #configureMessageConverters(List)}.
* @param messageConverters the list to add the default message converters to
*/
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
stringConverter.setWriteAcceptCharset(false);

messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(stringConverter);
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new SourceHttpMessageConverter<Source>());
messageConverters.add(new AllEncompassingFormHttpMessageConverter());

if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}

if (jackson2XmlPresent) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(objectMapper));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}

if (jackson2Present) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
}

3.1 总结

  • 我们知道,Http请求和响应报文本质上都是一串字符串,当请求报文来到Java世界,它会被封装成为一个ServletInputStream的输入流,供我们读取报文。响应报文则是通过一个ServletOutputStream的输出流,来输出响应报文,我们得到输入输出流之后需要把它转成我们的Java实体类对象,这个是怎样转换的呢,就是通过我们的HttpMessageConverter消息转换器来实现的

4.1 参考

官方文档: https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html

https://my.oschina.net/lichhao/blog/172562

http://www.chinacion.cn/article/608.html