前面几篇有关【springboot】请求处理原理各模块的文章结束后,就到了响应处理。
响应处理又可以分为(一)响应页面(二)响应数据。
(一)响应页面常见于一些单体项目中,主要表现为服务器响应我们发出的请求给我们跳转到对应的页面。(二)响应数据主要见于一些前后端分离的项目,前端向后端发送请求,后端向前端发送JSON数据(或者其他类型的数据,如xml、xlsx、图片音频视频、自定义协议数据等)。
后面的文章都会以(一)响应JSON和(二)内容协商两个模块的内容来开展,本文先介绍(一)响应JSON。
在springboot中来实现响应JSON就必须先在我们项目的pom文件中引入对应的starter-web场景:
然后点旁边那个圆圆的O标志,就会进到springboot为我们集中管理版本(复习:springboot的一大特色)的pom文件中(名字是spring-boot-dependencies-版本号.pom),打开如果看到一大片红的报错,不要害怕,只是因为有的包没有导入,跟普通的项目pom文件是一样的,刷新maven就帮你全下载好了。
我的版本是2.7.4的:
可以看到其中2.7.4版本的starter-json依赖是web场景为我们自动引入的json场景。
同理,继续深入可以获得有关版本的更多详细信息:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.13.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.4</version>
<scope>compile</scope>
</dependency>
响应JSON的实现需要有关①jackson.jar(上文已引入)和②@ResponseBody注解。
②只需要在我们的controller类上加@ResponseBody注解。
这里写一个普通的controller(添加普通@Controller注解):
这就可以向前端(页面)返回JSON数据。
开始就这个过程debug。仍然从DispatcherServlet来到这个位置(InvokeAndHandleMethod类):
查看this.returnValueHandlers有哪些值:(可选的处理器handler/processor,预告一下是[11])
还可以查看我们的返回值,的确就是controller方法中声明的数据。
最核心的处理返回值的逻辑在于handleReturnValue方法:
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
} else {
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
进入selectHandler方法,可以看到该方法返回值是HandleMethodReturnValueHandler类型的,即得到适合处理本controller方法的方法返回值处理器。因此可知handleReturnValue方法处理返回值的逻辑跟之前几篇文章讲(一)请求处理——参数处理的逻辑是一样的,需要根据我们的参数or返回值找到合适的参数or返回值处理器(handler),然后有针对的handleXxx方法来处理具体逻辑。
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);
Iterator var4 = this.returnValueHandlers.iterator();
HandlerMethodReturnValueHandler handler;
do {
do {
if (!var4.hasNext()) {
return null;
}
handler = (HandlerMethodReturnValueHandler)var4.next();
} while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));
} while(!handler.supportsReturnType(returnType));
return handler;
}
selectHandler的过程中首先通过isAsyncReturnValue方法判断是不是异步的返回值,然后这里就是找handler的核心了——又是通过迭代来默认的可选handler列表中(设计模式:适配器模式)找合适的handler。
private boolean isAsyncReturnValue(@Nullable Object value, MethodParameter returnType) {
Iterator var3 = this.returnValueHandlers.iterator();
HandlerMethodReturnValueHandler handler;
do {
if (!var3.hasNext()) {
return false;
}
handler = (HandlerMethodReturnValueHandler)var3.next();
} while(!(handler instanceof AsyncHandlerMethodReturnValueHandler) || !((AsyncHandlerMethodReturnValueHandler)handler).isAsyncReturnValue(value, returnType));
return true;
}
这一步判断结束,不是异步的返回值:
于是继续回到selectHandler方法中判断,可以留意到HandleMethodReturnValueHandler类型:
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
或者ctrl+F12可以查看当前类(接口)的继承关系。
不难知道supportsReturnType方法是判断方法是否支持该返回值的,handleMethodValue是在supportsReturnType为true时才进行处理执行返回值的。
这个跟之前请求参数解析的原理一样的。(supportsParmeter的判断)可以查看HandleMethodReturnValueHandler接口的supportsReturnType方法。HandleMethodReturnValueHandler接口有很多实现类,对应的就是不同的方法返回值处理(判断是否支持再决定是否作为handler处理)的实现。
但是同时debug也发现, 这个supportsReturnType来自,在他的上面有一个之前介绍参数解析时分析过的supportsParameter方法,不过是判断对象不一样。但是他们都来自这个方法处理器(for RequestResponseBody--请求响应体)。
不管如何得到的handler是这个类型的:
(也警示我们:处理器不一定是handler结尾的名字,还可以是processor,也是处理器的意思)
最后执行到最终核心处理(②):
@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);
}
下一篇文章就是介绍这个最里层的handleReturnValue是怎么处理请求响应体返回值的。