自定义pojo参数映射原理
HttpServlet接口
-
由spring实现FrameworkServlet get/post -> doService
-
衍生到子类DispatcherServlet实现
-
doDispatcher来分配并执行方法,
getHandler(processedRequest)
获取合适的handlerExecutionChain来执行请求 -
找到HandlerAdapter来屏蔽方法名不同带来的差距,最终找到
RequestMappingHandlerAdapter
-
判断是否要执行前置通知preHandler处理方法
-
执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
-
RequestMappingHandlerAdapter的invokeHandlerMethod方法下的invocableMethod.invokeAndHandle(webRequest, mavContainer);
-
开始执行时第一步就是获取参数InvocableHandlerMethod#invokeForRequest方法中getMethodArgumentValues(request, mavContainer, providedArgs);获取请求参数
-
通过初始化时就注入的参数解析器HandlerMethodArgumentResolver来遍历寻找合适的参数解析器解析参数
-
找到ServletModelAttributeMethodProcessor 来处理并放入缓存ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>
该解析器是ModelAttributeMethodProcessor的字类
-
ModelAttributeMethodProcessor#resolveArgument解析参数
-
使用WebDataBinder来绑定参数到指定pojo
HandlerExecutionChain
由Handler对象及Handler拦截器构成的Handler执行链,由HandlerMapping
的getHandler
方法返回获取
HandlerMapping
Interface to be implemented by objects that define a mapping between requests and handler objects.
一个定义请求与处理器对象映射的将被实现的接口
HandlerAdapter
MVC framework SPI, allowing parameterization of the core MVC workflow
支持核心MVC工作流参数化的MVC框架SPI
java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。这有点类似IOC的思想,将装配的控制权移到了程序之外。
ModelAttributeMethodProcessor
Resolve {@code @ModelAttribute} annotated method arguments and handle return values from {@code @ModelAttribute} annotated methods.
处理被@ModelAttribute注解标注的方法看书映射
ServletModelAttributeMethodProcessor
A Servlet-specific {@link ModelAttributeMethodProcessor} that applies data binding through a WebDataBinder of type {@link ServletRequestDataBinder}.
一个通过WebDataBinder来绑定参数的特定处理器与父类相比,并没有在参数上添加相关注解
GenericConversionService
Base {@link ConversionService} implementation suitable for use in most environments.
基础参数转换类
提交时input框的name通过级联属性来触发映射到内部的pojo中例如pet.name
静态资源位置暂定resource/resource优先于resource/static
自定义参数转换格式
WebMvcConfigurer
自定义mvc配置器
addFormatters
Add {@link Converter Converters} and {@link Formatter Formatters} in addition to the ones registered by default.
向容器中添加自定义WebMvcConfigurer 通过重写addFormatters方法来自定义参数转换规则
多参数模板lambda表达式写法:
registry.addConverter((Converter<String, Pet>)(s) ->{
if (!StringUtils.isEmpty(s)){
Pet pet = new Pet();
String[] split = s.split(",");
pet.setName(split[0]);
pet.setAge(Integer.parseInt(split[1]));
return pet;
}
return null;
});
出错
java.lang.IllegalArgumentException: Unable to determine source type and target type for your Converter
lambda表达式实际会被转为一个由static标注的私有方法进而产生合适的类,该方法是声明类的一部分,spring无法检索/访问
所以可通过
Converter<String, Pet> myConverter = source -> {
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;
};
registry.addConverter(myConverter);
这种方法来解决,解决失败。
注入实现类还是直接实现而不是lambda表达式为好
解决
registry.addConverter(new Converter<String, Pet>() {
@Override
public Pet convert(String source) {
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;
}
});
在解析时将自定义converter也注入了