SpringBoot - Web数据响应
研究SpringBoot进行Web开发时如何处理响应。
1. 数据响应类型
数据响应分为两大类:响应页面,响应数据。
响应页面在我们开发单体应用经常用到,处理器直接返回视图名。
响应页面的原理会在接下来的视图解析章节讲解。
做前后端分离开发场景大多数还是响应数据,常用响应数据类型:
- JSON数据格式
- XML格式
- xls,xlsx表格
- 图片,音视频等媒体格式
- 自定义协议数据等
本章节我们以处理器响应JSON数据来研究数据响应原理。
学习SpringMVC时我们知道,响应JSON需要两步:
- 导入
jackson
依赖; - 在处理器方法上使用
@ResponseBody
注解。
SpringBoot在web场景的启动器spring-boot-starter-web中已经为我们配置了jackson,
所以使用web场景启动器开发时只需使用@ResponseBody
注解即可。
2. ReturnValueHandler原理
2.1 上节遗留的细节
上节研究SpringBoot请求参数处理的时候,我们了解到了参数解析器ArgumentResolver
:
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
// RequestMappingHandlerAdapter.java Line:850~904
// 真正使用处理器适配器执行目标处理器的方法
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
try {
// ... 省略其他代码
// 给执行方法设置参数解析器
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 给执行方法设置返回值解析器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// ... 省略其他代码
// 调用处理器方法并处理请求
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// ... 省略其他代码
}
finally {
webRequest.requestCompleted();
}
}
同时还有一个组件ReturnValueHandler
。
2.2 返回值处理器概述
返回值处理器(ReturnValueHandler):SpringMVC使用返回值处理器处理处理器的返回值,
根据返回值的内容响应对应的信息。
返回值处理器和参数解析器相似,本质都是一个接口HandlerMethodReturnValueHandler
。
这个接口也有两个方法:
- boolean supportsReturnType:判断此返回值处理器是否支持当前返回值类型;
- void handleReturnValue:处理当前返回值的方法。
SpringMVC提供了15种返回值处理器实现类(Spring 2.4.5,严格顺序):
名称 | 作用 |
---|---|
ModelAndViewMethodReturnValueHandler | 处理ModelAndView类型及其子类的返回值 |
ModelMethodProcessor | 处理Model类型及其子类的返回值 |
ViewMethodReturnValueHandler | 处理返回值为View类型及其子类的返回值 |
ResponseBodyEmitterReturnValueHandler | 处理ResponseBodyEmitter类型及其子类,包括使用ResponseEntity包装的类的返回值,在Spring 5.0中还支持响应式适配类型 |
StreamingResponseBodyReturnValueHandler | 处理StreamingResponseBody类型及其子类或ResponseEntity<StreamingResponseBody>类型的返回值 |
HttpEntityMethodProcessor | 处理HttpEntity类型及其子类但不包括RequestEntity类型的返回值 |
HttpHeadersReturnValueHandler | 处理HttpHeaders类型及其子类的返回值 |
CallableMethodReturnValueHandler | 处理Callable类型及其子类的返回值 |
DeferredResultMethodReturnValueHandler | 处理DeferredResult类型及其子类、ListenableFuture类型及其子类和CompletionStage类型及其子类的返回值 |
AsyncTaskMethodReturnValueHandler | 处理WebAsyncTask类型及其子类的返回值 |
ServletModelAttributeMethodProcessorannotationNotRequired = false |
处理被@ModelAttribute注解的方法的返回值 |
RequestResponseBodyMethodProcessor | 处理带有@ResponseBody注解的返回值 |
ViewNameMethodReturnValueHandler | 处理视图名返回值(void或者String) |
MapMethodProcessor | 处理Map类型及其子类的返回值 |
ServletModelAttributeMethodProcessorannotationNotRequired = true |
处理没有被@ModelAttribute注解标注且类型为简单类型的返回值 |
这些处理器也是各有各的返回值支持类型,各有各的处理方法。
2.3 返回值处理器原理(源码)
供调试的处理器方法:
@RequestMapping("/user")
@ResponseBody
public User getUser() {
return new User("张三", 21, true);
}
调试来到ServletInvocableHandlerMethod
类的invokeAndHandle
方法:
// org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle
// ServletInvocableHandlerMethod.java Line:103~133
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 执行目标处理器,并获取返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 设置响应状态
setResponseStatus(webRequest);
// 如果没有返回值
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);