自定义参数封装过程原理【用实体类接收参数】
当请求提交的参数足够多时,可以使用JavaBean作为接收参数。而具体的是怎样将请求报文中的参数值和控制器中的Bean参数的属性一一对应赋值的。这就是需要探究的
首先来到DispatcherServlet中寻找处理请求的适配器,然后再使用适配器处理请求和参数。
在JavaBean中
@Data
public class TestBean {
private String username;
private String password;
private Food food;
}
在控制器中
@RequestMapping("/testBean")
public TestBean testBean(TestBean testBean){
return testBean;
}
页面中
springboot会自动转换类型和格式,会联级封装,在上面的bean中没写toString,但是控制器使用了@RestController注解,返回的类型在页面就会变成json。想知道为什么就看源码
<form action="/https/blog.csdn.net/testBean" method="post">
username--<input type="text" name="username"/><br>
password--<input type="password" name="password"/><br>
food_name--<input type="text" name="food.name"/><br>
food_price--<input type="text" name="food.price"/><br>
<input type="submit" value="发送请求提交数据">
</form>
原理
首先重启服务器,来到DispatcherServlet中,找到那一行确定请求适配器的,还有执行控制器方法的那一行。首先确定是用哪一个参数解析器解析实体参数的
确定是由 ha = {RequestMappingHandlerAdapter@7233} 这个适配器处理当前请求映射,然后来到真正处理请求的那一行 mv = ha.handle.... 。进入
首先来到AbstractHandlerMethodAdapter-->>handle,然后继续进入来到RequestMappingHandlerAdapter-->>invokeHandlerMethod里面,略过前面的初始化内容,找到这一行
invocableMethod.invokeAndHandle(webRequest, mavContainer);
进入后,找到熟悉的这两行
第一行是处理请求和参数的,执行完了就会执行控制器方法,再执行第二句
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
首先进入第一行,来到InvocableHandlerMethod-->>invokeForRequest里面,从第一行进入来到getMethodArgumentValues方法里面,确定参数的解析器和为控制器参数赋值
找到这两行,第一行确定的是参数的解析器resolver,第二行是获取请求中的值为参数赋值
if (!this.resolvers.supportsParameter(parameter)) {
...
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
首先进入第一行,经过HandlerMethodArgumentResolverComposite-->>supportsParameter方法来到getArgumentResolver方法
在这里确定由哪个参数解析器解析参数
在底层可以发现很多这样的增强for循环,实现解决一些参数赋值解析问题
在循环里面有27个解析器,经过循环最后是由result = {ServletModelAttributeMethodProcessor@7402} 作为参数解析器
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;