¶入参解析器
¶NameValue参数
改解析器用来处理NameValue注解,即含有name
,flag
,defaultValue
- 代码逻辑
1 | //el表达基础条件 |
- 简单总结
name
,defaultValue
支持el表达式,并不是所有子类都支持,子类构造提供了bf
才能支持- 子类处理miss|null情况
- 有处理结束调用点
¶RequestHeader
- 代码逻辑
1 | public RequestHeaderMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) { |
- 总结
- 形参只能为非
Map
和Optional<Map>
- 支持el表达式
- 获取请求头属性
- 形参只能为非
¶RequestAttribute
RequestAttributeMethodArgumentResolver
,代码简单略
- 总结
- 形参支持
@RequestAttribute
修饰 - 不支持el
- 获取spring封装的
WebRequest
属性
- 形参支持
¶RequestPara
RequestParamMethodArgumentResolver
,略
- 代码逻辑
1 | public RequestParamMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory, |
- 总结
- 支持el表达式
- 形参条件
@RequestPara
修饰的Map
,但是不能有name属性MultipartFile
或者Part
不带有@RequestPart
注解- useDefaultResolution==true时,可以使用不带
@RequestPara
的simple类型
¶CookieValue
ServletCookieValueMethodArgumentResolver
略
- 总结
- 支持el
- 形参一般为
Cookie
或String
¶MatrixVariable
MatrixVariableMethodArgumentResolver
略
- 总结
- 不支持el
@MatrixVariable
修改的Map
,且含有name属性- 要使用这个配置类,实际上是为了开启
Mapping
中去除矩阵变量的分隔符.
1
2
3
4
5protected void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper=new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
¶SessionAttribute
SessionAttributeMethodArgumentResolver
,略
- 总结
- 不支持el
@SessionAttribute
修饰,获取session属性- 和
@SessionAttributes
区分开
¶ExpressionValue
- 代码逻辑
1 | public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { |
- 总结
- 和ioc过程中@Value使用一致
¶PathVariable
PathVariableMethodArgumentResolver
- 总结
- 形参
@PathVariable
修饰Map
带有name属性String
- 形参
¶ModelAttribute注解
该注解作为形参使用时说明要从MvcContainer
中尝试获取model
,若没有则会进入创建流程
改处理器同时也是一个返回值处理器
,完成了获取model
,创建model
,验证
的功能
- 关系
¶默认实现
- 代码逻辑
1 | public ModelAttributeMethodProcessor(boolean annotationNotRequired) { |
- 总结
- 典型的使用
@ModelAttribute
||或自定义类型- 从请求参数填充属性
- 可以进行
验证
- 典型的使用
¶Servlet实现
- 代码逻辑
1 | public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor { |
- 总结
- 特有的定义从请求中获取
String
- 用户需定义
ConversionService
来完善功能
- 特有的定义从请求中获取
¶MessageConverter处理器
该类解析器在处理入参时使用用了HttpMessageConverter
,用户可以自定义
- 转换器定义
1 | public interface HttpMessageConverter<T> { |
¶抽象逻辑
- 代码逻辑
1 | public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver { |
- 总结
- 由构造器指定转换器列表
- 拥有
RequestAdvice
和ResponseAdvice
调用点 - http请求必须含有请求体
- 这种转换器都是从body获取数据,因此就不是用来处理能够简单获取key-value的数据,可以和
@ModelAttribute
处理器做一下对比
¶RequestPart
- 代码逻辑
RequestPartMethodArgumentResolver 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
66public class RequestPartMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver {
//这里的逻辑和RequestPara是相反的
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.hasParameterAnnotation(RequestPart.class)) {
return true;
}
else {
if (parameter.hasParameterAnnotation(RequestParam.class)) {
return false;
}
return MultipartResolutionDelegate.isMultipartArgument(parameter.nestedIfOptional());
}
}
}
//处理
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest request, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
Assert.state(servletRequest != null, "No HttpServletRequest");
RequestPart requestPart = parameter.getParameterAnnotation(RequestPart.class);
boolean isRequired = ((requestPart == null || requestPart.required()) && !parameter.isOptional());
String name = getPartName(parameter, requestPart);
parameter = parameter.nestedIfOptional();
Object arg = null;
//交由多文件代理处理,这里逻辑和@RequestPara一致
Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
arg = mpArg;
}
else { //若没法处理则交予处理器处理
try {
HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(servletRequest, name);
arg = readWithMessageConverters(inputMessage, parameter, parameter.getNestedGenericParameterType());
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(request, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
}
catch (MissingServletRequestPartException | MultipartException ex) {
if (isRequired) {
throw ex;
}
}
}
if (arg == null && isRequired) {
if (!MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
throw new MultipartException("Current request is not a multipart request");
}
else {
throw new MissingServletRequestPartException(name);
}
}
return adaptArgumentIfNecessary(arg, parameter);
} - 总结
- 带上
@ReuqestPart
和@RequestPara
区分
- 带上
¶RequestResponse
转换器也是回参处理器,常见的json转换,xml转换都是这个完成的
- 代码逻辑
1 | public boolean supportsReturnType(MethodParameter returnType) { |
- 总结
- 形参为
@Requestbody
- 逻辑简单
¶HttpEntity
转换器也是回参处理器- 总结
HttpEntity
和RequestEntity
支持
¶回参处理器
¶模型处理
¶ModelAttribute
- 代码逻辑
ModelAttributeMethodProcessor 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public boolean supportsReturnType(MethodParameter returnType) {
return (returnType.hasMethodAnnotation(ModelAttribute.class) ||
(this.annotationNotRequired && !BeanUtils.isSimpleProperty(returnType.getParameterType())));
}
/**
* Add non-null return values to the {@link ModelAndViewContainer}.
*/
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue != null) {
String name = ModelFactory.getNameForReturnValue(returnValue, returnType);
mavContainer.addAttribute(name, returnValue);
}
}- 总结
- 该Method有@ModelAttribute修饰||或者采用自定义类型生效
- 将该返回值加入
mvcContainer
¶MapMethod
- 代码逻辑
MapMethodProcessor 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public boolean supportsReturnType(MethodParameter returnType) {
return Map.class.isAssignableFrom(returnType.getParameterType());
}
"rawtypes", "unchecked"}) ({
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue instanceof Map){
mavContainer.addAllAttributes((Map) returnValue);
}
else if (returnValue != null) {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}- 总结
- 返回值必须为
Map
子类 - 符合则加入
mvcContainer
- 返回值必须为
¶视图处理
¶ViewNameMethod
- 代码逻辑
ViewNameMethodReturnValueHandler 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public boolean supportsReturnType(MethodParameter returnType) {
Class<?> paramType = returnType.getParameterType();
return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue instanceof CharSequence) {
String viewName = returnValue.toString();
mavContainer.setViewName(viewName);
if (isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null) {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}- 总结
- 返回值必须是
CharSequence
子类||void - 处理方式是给
mvcContainer#viewName
设置
- 返回值必须是
¶ViewMethod
- 代码逻辑
ViewMethodReturnValueHandler 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
27public class ViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
public boolean supportsReturnType(MethodParameter returnType) {
return View.class.isAssignableFrom(returnType.getParameterType());
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue instanceof View) {
View view = (View) returnValue;
mavContainer.setView(view);
if (view instanceof SmartView && ((SmartView) view).isRedirectView()) {
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null) {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
}- 总结
- 返回值要求为
View
对象 - 设置
MvcContainer#View
属性
- 返回值要求为
¶ModelAndViewMethod
- 代码逻辑
ModelAndViewMethodReturnValueHandler 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 class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
public boolean supportsReturnType(MethodParameter returnType) {
return ModelAndView.class.isAssignableFrom(returnType.getParameterType());
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
ModelAndView mav = (ModelAndView) returnValue;
if (mav.isReference()) {
String viewName = mav.getViewName();
mavContainer.setViewName(viewName);
if (viewName != null && isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
else {
View view = mav.getView();
mavContainer.setView(view);
if (view instanceof SmartView && ((SmartView) view).isRedirectView()) {
mavContainer.setRedirectModelScenario(true);
}
}
mavContainer.setStatus(mav.getStatus());
mavContainer.addAllAttributes(mav.getModel());
}
}- 总结
- 形参
ModelAndView
- 支持重定向类型
- 形参
¶ModelAndViewResolver
- 代码逻辑
ModelAndViewResolverMethodReturnValueHandler 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
58public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
private final List<ModelAndViewResolver> mavResolvers;
private final ModelAttributeMethodProcessor modelAttributeProcessor = new ModelAttributeMethodProcessor(true);
/**
* Create a new instance.
*/
public ModelAndViewResolverMethodReturnValueHandler(@Nullable List<ModelAndViewResolver> mavResolvers) {
this.mavResolvers = mavResolvers;
}
/**
* Always returns {@code true}. See class-level note.
*/
public boolean supportsReturnType(MethodParameter returnType) {
return true;
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (this.mavResolvers != null) {
for (ModelAndViewResolver mavResolver : this.mavResolvers) {
Class<?> handlerType = returnType.getContainingClass();
Method method = returnType.getMethod();
Assert.state(method != null, "No handler method");
ExtendedModelMap model = (ExtendedModelMap) mavContainer.getModel();
ModelAndView mav = mavResolver.resolveModelAndView(method, handlerType, returnValue, model, webRequest);
if (mav != ModelAndViewResolver.UNRESOLVED) {
mavContainer.addAllAttributes(mav.getModel());
mavContainer.setViewName(mav.getViewName());
if (!mav.isReference()) {
mavContainer.setView(mav.getView());
}
return;
}
}
}
// No suitable ModelAndViewResolver...
if (this.modelAttributeProcessor.supportsReturnType(returnType)) {
this.modelAttributeProcessor.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
else {
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
}- 总结
- 回参随意的原因是该回参处理在list的末尾,一般不会调用到这里
- 用户来实现
ModelAndViewResolver
¶HttpMessageConverter
这是mvc中较为常用的类型,通过HttpMessageConverter
来处理转换类型¶抽象逻辑
AbstractMessageConverterMethodProcessor 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
//子类一般会重写,来体统inputMessage和outputMessage
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
writeWithMessageConverters(value, returnType, inputMessage, outputMessage);
}
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object body;
Class<?> valueType;
Type targetType;
//[1]确定类型
if (value instanceof CharSequence) {
body = value.toString();
valueType = String.class;
targetType = String.class;
}
else {
body = value;
valueType = getReturnValueType(body, returnType);
targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
}
//[1!]
//[2] 专门用来处理 Accept-Ranges
if (isResourceType(value, returnType)) {
outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&
outputMessage.getServletResponse().getStatus() == 200) {
Resource resource = (Resource) value;
try {
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());
body = HttpRange.toResourceRegions(httpRanges, resource);
valueType = body.getClass();
targetType = RESOURCE_REGION_LIST_TYPE;
}
catch (IllegalArgumentException ex) {
outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());
}
}
}
//[2!]
//[3] 尝试从Response#header获取类型,若没有则通过ContentNegotiationManager解析
MediaType selectedMediaType = null;
MediaType contentType = outputMessage.getHeaders().getContentType();
boolean isContentTypePreset = contentType != null && contentType.isConcrete();
if (isContentTypePreset) {
if (logger.isDebugEnabled()) {
logger.debug("Found 'Content-Type:" + contentType + "' in response");
}
selectedMediaType = contentType;
}
else {
HttpServletRequest request = inputMessage.getServletRequest();
//req#Accept
List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
//@RequestMapping#produce 中获取
List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);
if (body != null && producibleTypes.isEmpty()) {
throw new HttpMessageNotWritableException(
"No converter found for return value of type: " + valueType);
}
List<MediaType> mediaTypesToUse = new ArrayList<>();
for (MediaType requestedType : acceptableTypes) {
for (MediaType producibleType : producibleTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
if (mediaTypesToUse.isEmpty()) {
if (body != null) {
throw new HttpMediaTypeNotAcceptableException(producibleTypes);
}
if (logger.isDebugEnabled()) {
logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);
}
return;
}
//[3!]
//[4]获取最合适的
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
for (MediaType mediaType : mediaTypesToUse) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using '" + selectedMediaType + "', given " +
acceptableTypes + " and supported " + producibleTypes);
}
}
//[4!]
//[5] 调用HttpMessageConverter进行处理,并附带了advice#beforeBodyRead调用
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
if (body != null) {
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn ->
"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
addContentDispositionHeader(inputMessage, outputMessage);
if (genericConverter != null) {
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Nothing to write: null body");
}
}
return; //处理结束
}
}
}
//[5!]
//[6!] 若进行到这里则说明没有匹配任何处理器
if (body != null) {
Set<MediaType> producibleMediaTypes =
(Set<MediaType>) inputMessage.getServletRequest()
.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {
throw new HttpMessageNotWritableException(
"No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");
}
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
//[6]- 总结
- 返回数据类型由
ContentNegotiationManager
和@RequestMapping#produce
提供 - 提供了处理
context-range
的默认方法 - 提供了
context-dispoition
的方法 - 执行转换前会执行
advice#beforeBodyWrite
- 返回数据类型由
¶RequestResponseBody
- 代码逻辑
RequestResponseBodyMethodProcessor 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
public void handleReturnValue(@Nullable 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);
} - 总结
- controller函数上有
@RequestBody
||控制器有@RequestBody
,如@RestController
- 后续不会发生更新
bindingResult
- controller函数上有
¶HttpEntity
- 代码逻辑
HttpEntityMethodProcessor 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
65public boolean supportsReturnType(MethodParameter returnType) {
return (HttpEntity.class.isAssignableFrom(returnType.getParameterType()) &&
!RequestEntity.class.isAssignableFrom(returnType.getParameterType()));
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//[1]设置标志,创建in||out
mavContainer.setRequestHandled(true);
if (returnValue == null) {
return;
}
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
//[1!]
Assert.isInstanceOf(HttpEntity.class, returnValue);
HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue;
//[2]将Entity中的header设置到out中
HttpHeaders outputHeaders = outputMessage.getHeaders();
HttpHeaders entityHeaders = responseEntity.getHeaders();
if (!entityHeaders.isEmpty()) {
entityHeaders.forEach((key, value) -> {
if (HttpHeaders.VARY.equals(key) && outputHeaders.containsKey(HttpHeaders.VARY)) { //此处涉及到了VARY头
List<String> values = getVaryRequestHeadersToAdd(outputHeaders, entityHeaders);
if (!values.isEmpty()) {
outputHeaders.setVary(values);
}
}
else {
outputHeaders.put(key, value);
}
});
}
//[2]
//[3]处理200和3xx请求
if (responseEntity instanceof ResponseEntity) {
int returnStatus = ((ResponseEntity<?>) responseEntity).getStatusCodeValue();
outputMessage.getServletResponse().setStatus(returnStatus);
if (returnStatus == 200) {
if (SAFE_METHODS.contains(inputMessage.getMethod())
&& isResourceNotModified(inputMessage, outputMessage)) { //get或者head请求,并且资源未改变
// Ensure headers are flushed, no body should be written.
outputMessage.flush();
ShallowEtagHeaderFilter.disableContentCaching(inputMessage.getServletRequest());
// Skip call to converters, as they may update the body.
return;
}
}
else if (returnStatus / 100 == 3) { //处理重定向属性
String location = outputHeaders.getFirst("location");
if (location != null) {
saveFlashAttributes(mavContainer, webRequest, location);
}
}
}
//[3!]
//[4]body作为value,调用转换器代码
// Try even with null body. ResponseBodyAdvice could get involved.
writeWithMessageConverters(responseEntity.getBody(), returnType, inputMessage, outputMessage);
// Ensure headers are flushed even if no body was written.
outputMessage.flush();
//[4!]
}- 总结
- 返回值为
HttpEntity
但不也是RequestHttpEntity
- 将
Entity#body
进行类型转换
- 返回值为
¶异步和其他
异步处理暂时不做分析¶HttpHeaders
- 代码逻辑
HttpHeadersReturnValueHandler 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
public boolean supportsReturnType(MethodParameter returnType) {
return HttpHeaders.class.isAssignableFrom(returnType.getParameterType());
}
"resource") (
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
mavContainer.setRequestHandled(true);
Assert.state(returnValue instanceof HttpHeaders, "HttpHeaders expected");
HttpHeaders headers = (HttpHeaders) returnValue;
if (!headers.isEmpty()) {
HttpServletResponse servletResponse = webRequest.getNativeResponse(HttpServletResponse.class);
Assert.state(servletResponse != null, "No HttpServletResponse");
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(servletResponse);
outputMessage.getHeaders().putAll(headers);
outputMessage.getBody(); // flush headers
}
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
[1] 设置标志,创建input|output
mavContainer.setRequestHandled(true);
if (returnValue == null) {
return;
}
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
Assert.isInstanceOf(HttpEntity.class, returnValue);
HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue;
//[1!]
//[2]保证将返回值的header放置到outMessage中,并且此处处理了`VARY`
HttpHeaders outputHeaders = outputMessage.getHeaders();
HttpHeaders entityHeaders = responseEntity.getHeaders();
if (!entityHeaders.isEmpty()) {
entityHeaders.forEach((key, value) -> {
if (HttpHeaders.VARY.equals(key) && outputHeaders.containsKey(HttpHeaders.VARY)) {
List<String> values = getVaryRequestHeadersToAdd(outputHeaders, entityHeaders);
if (!values.isEmpty()) {
outputHeaders.setVary(values);
}
}
else {
outputHeaders.put(key, value);
}
});
}
//[2!]
//[3]
if (responseEntity instanceof ResponseEntity) {
int returnStatus = ((ResponseEntity<?>) responseEntity).getStatusCodeValue();
outputMessage.getServletResponse().setStatus(returnStatus);
if (returnStatus == 200) {//直接写出,不进行转换操作
if (SAFE_METHODS.contains(inputMessage.getMethod())
&& isResourceNotModified(inputMessage, outputMessage)) {
// Ensure headers are flushed, no body should be written.
outputMessage.flush();
ShallowEtagHeaderFilter.disableContentCaching(inputMessage.getServletRequest());
// Skip call to converters, as they may update the body.
return;
}
}
else if (returnStatus / 100 == 3) { //重定向操作
String location = outputHeaders.getFirst("location");
if (location != null) {
saveFlashAttributes(mavContainer, webRequest, location);
}
}
}
/[3!]
//[4]转换并保证header会被正确的返回
// Try even with null body. ResponseBodyAdvice could get involved.
writeWithMessageConverters(responseEntity.getBody(), returnType, inputMessage, outputMessage);
// Ensure headers are flushed even if no body was written.
outputMessage.flush();
//[4!]
}- 总结
- 返回值
HttpHeaders
- 处理设置
RequestHandled=true
- 返回值
- 形参为
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 博客!
评论