1、环境搭建
1、pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.manster</groupId>
<artifactId>boot-02-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>boot-02-web</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、Student
package com.manster.bean;
import lombok.Data;
/**
* @Author manster
* @Date 2021/4/28
**/
@Data
public class Student {
private String name;
private Integer age;
private Pet pet;
}
package com.manster.bean;
import lombok.Data;
/**
* @Author manster
* @Date 2021/4/26
**/
@Data
public class Pet {
private String name;
private Double weight;
}
3、StudentController
package com.manster.controller;
import com.manster.bean.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @Author manster
* @Date 2021/4/28
**/
@Controller
public class StudentController {
@ResponseBody
@GetMapping("getStu")
public Student student(Student student){
return student;
}
}
4、index.html
<form action="/getStu" method="post">
name:<input name="name" type="text" value="manster"/><br>
age:<input name="age" type="text" value="18"/><br>
pet.name:<input name="pet.name" type="text" value="旺财"/><br>
pet.age:<input name="pet.weight" type="text" value="3"/><br>
<input type="submit" value="提交" />
</form>
2、执行概要
HttpServletBean
没有doService()
、doGet()
、doPost()
public abstract class HttpServletBean extends HttpServlet
FrameworkServlet
有doGet()
、doPost()
等do方法,都去调用processRequest
,processRequest
调用doService
,但doService
没有实现
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
//都调用了processRequest
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
//调用了doService
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doService(request, response);
}
}
DispatcherServlet
实现了doService()
public class DispatcherServlet extends FrameworkServlet {
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
doDispatch(request, response);
}
}
- 所以一切都要从
doDispatch()
说起
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 确定当前请求的处理程序:可以理解为获取controller中的uri和uri对应的方法实例
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 确定当前请求的处理程序适配器。
// 可能有注解或者实现Controller和实现HttpRequest,三种实现。适配器的作用就是判断当前这个controller是什么方式实现的,到时候以哪种方式调用你的controller方法。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 实际调用处理程序:根据请求调用controller中的method,然后返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 处理处理程序选择和处理程序调用的结果,该结果可以是ModelAndView或要解析为ModelAndView的异常
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
- 请求进入
DispatcherServlet
的doDispatch
后,获取HandlerMethod
(Controller中对应的处理方法)。 - 然后根据
HandlerMethod
来确认HandlerApater
- 确认后执行
HandlerAdapter
的handle
方法。这里确认HandlerApater
为RequestMappingHandlerAdapter
- 在执行
HandlerMethod
之前,需要处理参数的绑定HandlerMethodArgumentResolver
。 - 参数绑定完毕,真正执行
HandlerMethod
方法 - 返回值处理
- 视图解析
3、请求映射(HandlerMethod)
找到请求对应的Controller的method
1.启动服务器,在页面中提交请求
2.调用DispatcherServlet
的 doDispatch()
3.获取原生的 request,得到请求分发路径/getStu
和所有参数
//DispatcherServlet doDispatch()
HttpServletRequest processedRequest = request;
//确定当前请求的处理程序:可以理解为获取controller中的uri和uri对应的方法实例
mappedHandler = getHandler(processedRequest);
4.首先进行路径下的映射匹配(在服务启动期间就已经把所有的映射加载进来了)
RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。
5.这时就会进行路径映射匹配
- SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 /能访问到index.html;
- SpringBoot自动配置了默认 的 RequestMappingHandlerMapping
- 请求进来,挨个尝试所有的
HandlerMapping
看是否有请求信息。- 如果有就找这个请求对应的
Handler(Controller)
- 如果没有就找下一个
HandlerMapping
- 如果有就找这个请求对应的
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
4、参数解析(MethodParameter)
将请求中的参数绑定
通过以上,我们就已经可以匹配到请求相对应的 HandleMethod
,下一步就是进行对参数的解析了
HandlerMapping
中找到能处理请求的Handler
- 为当前
Handler
找一个适配器HandlerAdapter
(RequestMappingHandlerAdapter)- 适配器的作用就是判断当前这个controller是什么方式实现的,到时候以哪种方式调用你的controller方法。
- Controller实现有:注解、实现Controller、实现HttpRequest
- 适配器的作用就是判断当前这个controller是什么方式实现的,到时候以哪种方式调用你的controller方法。
- 适配器执行目标方法并确定方法参数的每一个值
//DispatcherServlet doDispatch()
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
1、寻找适配器 HandlerAdapter
遍历所有适配器进行匹配
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
找到了我们所请求的 HandlerMethod
的适配器
2、确定目标方法每一个参数的值
进入到了目标方法中(执行controller中的逻辑)
//DispatcherServlet doDispatch()
// Actually invoke the handler.实际执行handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
进入 handle()
//AbstractHandlerMethodAdapter handle()
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
进入 handleInternal()
//RequestMappingHandlerAdapter handleInternal()
//方法真正执行的地方
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
进入 invokeHandlerMethod()
//RequestMappingHandlerAdapter invokeHandlerMethod()
//执行handler方法
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//mavContainer中添加了所有的view数据和model数据
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
进入 ServletInvocableHandlerMethod
一是解析请求参数,二是调用Controller中的请求方法
//ServletInvocableHandlerMethod invokeAndHandle()
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
}
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获得当前所有参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
进行参数匹配赋值,使用 匹配到的参数解析器 xxxArgumentResolver
调用 resolveArgument()
进行解析
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取所有执行的方法的参数信息
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
//如果之前有预先设置值的话,则取预先设置好的值
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//所有的参数解析器是否支持当前参数解析
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//解析出参数值
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled...
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
这里需要说的是 argumentResolvers
这个对象是 HandlerMethodArgumentResolverComposite
这个类。所有参数的解析都是委托这个类来完成的,这个类会调用真正的请求参数的解析的类
1.参数解析器HandlerMethodArgumentResolver
确定将要执行的目标方法的每一个参数的值是什么;
SpringMVC目标方法能写多少种参数类型。取决于参数解析器。
public boolean supportsParameter(MethodParameter parameter) {
return getArgumentResolver(parameter) != null;
}
2.遍历判断
挨个判断所有参数解析器哪个支持解析这个参数
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//先看之前有没有解析过这个方法参数,如果解析过,则从缓存中取
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
//循环所有的参数解析类,匹配真正参数解析的类
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
//放到缓存中
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
找到 ServletModelAttributeMethodProcessor
. 自定义类型是这个 Processor 进行解析的
3.解析判断
debug时直接到了 ModelAttributeMethodProcessor
中
public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor
ModelAttributeMethodProcessor
对参数解析器是否可以解析当前参数,是怎样进行判断的
public boolean supportsParameter(MethodParameter parameter) {
//判断有没有ModelAttribute注解,或者注解不是必须的且是简单属性
//而我们的Student对象显示是要返回true的
return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
(this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
}
查看 isSimpleProperty
public static boolean isSimpleProperty(Class<?> type) {
Assert.notNull(type, "'type' must not be null");
//判断是否为简单类型,或数组且是简单类型
//这里返回false
return isSimpleValueType(type) || type.isArray() && isSimpleValueType(type.getComponentType());
}
查看 isSimpleValueType
怎样判断是否为简单类型
public static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
//显然都不是
4.找到参数对应的解析器
ServletModelAttributeMethodProcessor
, 回到 `HandlerMethodArgumentResolverComposite
中执行resolveArgument()
@Override
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
String name = ModelFactory.getNameForParameter(parameter);
//判断是否有ModelAttribute注解
ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null) {
mavContainer.setBinding(name, ann.binding());
}
Object attribute = null;
BindingResult bindingResult = null;
//判断之前是否缓存了该类型
if (mavContainer.containsAttribute(name)) {
attribute = mavContainer.getModel().get(name);
}
else {
// Create attribute instance
//创建一个实例
try {
//创建了一个空的Student对象
attribute = createAttribute(name, parameter, binderFactory, webRequest);
}
catch (BindException ex) {
if (isBindExceptionRequired(parameter)) {
// No BindingResult parameter -> fail with BindException
throw ex;
}
// Otherwise, expose null/empty value and associated BindingResult
if (parameter.getParameterType() == Optional.class) {
attribute = Optional.empty();
}
bindingResult = ex.getBindingResult();
}
}
if (bindingResult == null) {
// Bean property binding and validation;
// Bean属性绑定和验证
// skipped in case of binding failure on construction.
// 如果在构造发生绑定失败,则跳过
// web数据绑定器,将请求参数的值绑定到指定的JavaBean(attribute)里面
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
//绑定请求参数(利用反射)
bindRequestParameters(binder, webRequest);
}
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
// Value type adaptation, also covering java.util.Optional
if (!parameter.getParameterType().isInstance(attribute)) {
attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
bindingResult = binder.getBindingResult();
}
// Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = bindingResult.getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return attribute;
}
binder中有conversionService,其中包括很多converters,用来进行参数类型转换(到这里,我们的参数一直都是String类型)
WebDataBinder
利用它里面的 Converters
将请求数据转成指定的数据类型。再次封装到JavaBean中
GenericConversionService
:在设置每一个值的时候,找它里面的所有 converter
哪个可以将这个数据类型(request带来参数的字符串)转换到指定的类型(JavaBean — Integer)
bindRequestParameters(binder, webRequest);
执行结果
5.自定义converter
@FunctionalInterface
public interface Converter<S, T>
未来我们可以给WebDataBinder里面放自己的Converter;
private static final class StringToNumber<T extends Number> implements Converter<String, T>
自定义 Converter
@Configuration
public class WebConfig {
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, Pet>() {
@Override
public Pet convert(String source) {
// 旺财,3
if(!StringUtils.isEmpty(source)){
Pet pet = new Pet();
String[] split = source.split(",");
pet.setName(split[0]);
pet.setAge(Integer.parseInt(split[1]));
return pet;
}
return null;
}
});
}
};
}
}
5、数据响应
1、得到返回值
RequestMappingHandlerAdapter
invokeHandlerMethod()
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
//返回值解析器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
将返回值解析器封装到 invocableMethod
中
invocableMethod.invokeAndHandle(webRequest, mavContainer);
进入 invokeAndHandle()
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//执行完成后得到返回值,得到了我们返回的Student对象
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
//对象是否为空
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
//有没有什么失败原因
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
//处理返回值
try {
//获取返回值和返回值类型进行返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
HandlerMethod 执行完成后得到的返回值
2、得到方法返回值类型
getReturnValueType(returnValue)
3、得到返回值类型解析器
//获取返回值和返回值类型进行返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
查看 handleReturnValue()
执行过程
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 根据返回值和返回类型找到返回值处理器
// 这里返回的是 RequestResponseBodyMethodProcessor 处理器, 处理标了 @ResponseBody 注解的方法的返回值
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 支持就调用该方法进行处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
// 判断是不是异步的
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// 遍历所有返回值解析器
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
// 判断是否支持这种类型返回值
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
4、处理返回值
通过上述步骤我们得到了返回值类型解析器 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);
}
writeWithMessageConverters()
先进行赋值
body = value;
valueType = getReturnValueType(body, returnType);
targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
然后进行与浏览器进行内容协商
浏览器发送请求时就会告知服务器自己能接受什么内容 以谷歌浏览器为例(q为权重) 浏览器发起请求 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 服务器响应 Content-Type: application/json
最后匹配得到了我们协商好的媒体类型,并以这种方式响应数据
5、总体流程
- 1、返回值处理器判断是否支持这种类型返回值 supportsReturnType
- 2、返回值处理器调用 handleReturnValue 进行处理
- 3、RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。
- 1、利用 MessageConverters 进行处理 将数据写为json
- 1、内容协商(浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型)
- 2、服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据,
- 3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?
- 1、得到MappingJackson2HttpMessageConverter可以将对象写为json
- 2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
- 1、利用 MessageConverters 进行处理 将数据写为json