SpringMVC默认的返回值处理器有:
0 = {ModelAndViewMethodReturnValueHandler@8543}
1 = {ModelMethodProcessor@8546}
2 = {ViewMethodReturnValueHandler@8547}
3 = {ResponseBodyEmitterReturnValueHandler@8548}
4 = {StreamingResponseBodyReturnValueHandler@8549}
5 = {HttpEntityMethodProcessor@8550}
6 = {HttpHeadersReturnValueHandler@8551}
7 = {CallableMethodReturnValueHandler@8552}
8 = {DeferredResultMethodReturnValueHandler@8553}
9 = {AsyncTaskMethodReturnValueHandler@8554}
10 = {ServletModelAttributeMethodProcessor@8162}
11 = {RequestResponseBodyMethodProcessor@8555}
12 = {ViewNameMethodReturnValueHandler@8556}
14 = {MapMethodProcessor@8557}
14 = {ServletModelAttributeMethodProcessor@8558}
我们最常用的就是 Controller + 返回值"String"
和 Controller + 返回值+ @ResponseBody
,现在分析一下,这两种情况是如何处理的。
Controller + 返回值”String”
@Controller
public class TestController {
@GetMapping("index")
public String toPage() {
return "index";
}
}
GET http://localhost:8080/index
会由 ViewNameMethodReturnValueHandler
去处理,将返回值放到ModeAndView的viewName中。这样视图解析器就会去找相应的视图。
Controller + 返回值+ @ResponseBody
RestController + 返回值
= Controller + 返回值+ @ResponseBody
GET http://localhost:8080/index
会由 RequestResponseBodyMethodProcessor
去处理,看下这个解析器的源码
@Override
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);
}
做2件事情:
- 设置setRequestHandled(true) 告诉视图解析器,已经处理过了,不需要渲染
- 找到合适的MessageConverter,然后将值直接写出。
RequestResponseBodyMethodProcessor
在处理的过程中,客户端可以使用注解@ControllerAdvice在write之前对值进行处理
@ControllerAdvice
public class MyAdvice implements ResponseBodyAdvice {
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
System.out.println("ResponseBodyAdvice: 执行 " + o);
return o;
}}
自定义HandlerMethodReturnValueHandler
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
handlers.add(new HandlerMethodReturnValueHandler() {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return Integer.class == returnType.getParameterType();
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
Integer value = (Integer) returnValue;
mavContainer.addAttribute("intValue", value);
if (value > 10) {
mavContainer.setViewName("big");
} else {
mavContainer.setViewName("small");
}
}
});
}
}
自定义的HandlerMethodReturnValueHandler,做了2件事。
- 将值放入Model中
- 如果大于10跳转big.html,否则跳转small.html
@GetMapping("int/{intValue}")
public int toIntPage(@PathVariable Integer intValue) {
return intValue;
}
GET http://localhost:8080/int/11
big.html
<body>
big.html
<h1 th:text="${intValue}"></h1>
</body>