自定义pojo类与前端请求参数绑定源码解析
1、DispatcherServlet.class
找到能处理请求的Handler
为当前Handler 找一个适配器HandlerAdapter
找到适配器真正执行方法
2、AbstractHandlerMethodAdapter.class
找到执行方法
3、RequestMappingHandlerAdapter.class
真正来执行处理器的方法
SpringMVC目标方法能写多少种参数类型。取决于参数解析器。
参数解析器
返回值处理器
执行目标方法
4、ServletInvocableHandlerMethod.class
确定参数,真正执行目标方法
的地方,有方法的返回值。
5、InvocableHandlerMethod.class
获取当前目标方法所有参数的属性值,然后在65行通过反射
执行目标方法(也就是Controller方法)
挨个判断所有参数解析器哪个支持解析目标方法的参数
6、HandlerMethodArgumentResolverComposite.class
判断是否有满足条件的解析器
如果是自定义类型参数封装POJO会调用ServletModelAttributeMethodProcessor
这个参数处理器
7、InvocableHandlerMethod.class
返回该处理器来到下面的处理环节
8、HandlerMethodArgumentResolverComposite.class
拿到能支持解析的参数解析器,然后调用resolveArgument方法进行解析
9、ModelAttributeMethodProcessor.class
创建实例,不同的解析器会进入到不同的class文件中
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
WebDataBinder :web数据绑定器,利用它里面的 Converters 将请求数据转成指定的数据类型。再次封装到JavaBean中
有124个转换器。从前端传来的数据经过http超文本协议想从文本类型转换为指定的数据类型需要使用到这些转换器
关键一步,把请求里的数据绑定
10、ServletModelAttributeMethodProcessor.class
把原生的数据调过来进行绑定
11、ServletRequestDataBinder.class
获取原生参数所有key-value对
准备进行绑定
12、WebDataBinder.class
13、DataBinder.class
应用属性
设置属性值
14、AbstractPropertyAccessor.class
遍历并且底层利用反射赋值
15、AbstractNestablePropertyAccessor.class
对反射属性和原生数据进行绑定
把原生数据的类型进行转换并绑定
去找转换器
16、TypeConverterDelegate.class
判断能不能进行转换
17、GenericConversionService.class
获取转换器
找它里面的所有converter那个可以将这个数据类型(request带来参数的字符串)转换到指定的类型
18、TypeConverterDelegate.class
判断为true时则进行转换
19、GenericConversionService.class
20、ConversionUtils.class
21、GenericConversionService.class
22、StringToNumberConverterFactory.class
未来我们可以给WebDataBinder里面放自己的Converter; private static final class StringToNumber<T extends Number> implements Converter<String, T>,
23、AbstractNestablePropertyAccessor.class
前端参数值转换完毕开始赋值
自定义Converter
原理:底层用了一个WebDataBinder数据绑定器,它会将请求参数的值绑定到指定JavaBean里面
1、自定义配置文件,把前端传来的值去掉“,”后一一对应绑定到JavaBean里面
@Component
public class MyConfig {
@Bean
public WebMvcConfigurer myWebMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, User>() {
@Override
public User convert(String source) {
if(!StringUtils.isNullOrEmpty(source)){
String[] split = source.split(",");
User user = new User();
user.setUserId(Integer.parseInt(split[0]));
user.setName(split[1]);
user.setBalance(Integer.parseInt(split[2]));
return user;
}
return null;
}
});
}
};
}
}
2、客服端发送post请求提交数据
<form action="/requestBook" method="post">
<input name="bookId" value="1"/><br/>
<input name="bookName" value="三体"/><br/>
<input name="price" value="100"/><br/>
<input name="stock" value="99"/><br/>
<input name="user" value="2,张三,1000"/><br/>
<input type="submit" value="save"/>
</form>
3、服务端接收数据自定义Converter处理并返回
@Controller
public class UserController {
@Autowired
private UserService userService;
@ResponseBody
@RequestMapping(value = "/requestBook", method = RequestMethod.POST)
public Book requestBook(Book book){
return book;
}
@ResponseBody
@RequestMapping(value = "/responseData", method = RequestMethod.GET)
public Book responseData(){
Book book = new Book();
book.setBookId(1);
book.setBookName("三体");
book.setPrice(100);
book.setStock(10);
return book;
}
}
实现结果: