之前说到常用的http 入参解析方式有基于request-body解析、基于表单解析。
其中request-body参数解析,直接读取servletRequest.getInputStream(),按照json 或者xml 或者RSS格式解析即可,具体的解析细节根据使用的数据格式工具包实现。
表单解析则不同,更多的依赖javax.servlet 定义的接口方法解析获取数据
exmpale
@InitBinder
public void initBinder(WebDataBinder binder) {
// 可以使用joda, 按需索取
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
Insight
如之前记录,表单解析器是ServletModelAttributeMethodProcessor,具体的解析实现交给父类 ModelAttributeMethodProcessor。
@InitBinder 注解的方法就是此处initBinder()发生调用,通过反射,将自定义Editor注册到当前请求的binder。
然后由 DataBinder 完成参数对象属性的set。
注解方法的调用
// InitBinderDataBinderFactory#initBinder
public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
for (InvocableHandlerMethod binderMethod : this.binderMethods) {
if (isBinderMethodApplicable(binderMethod, binder)) {
// 反射,执行对应的方法,即注册editor 至入参binder
Object returnValue = binderMethod.invokeForRequest(request, null, binder);
if (returnValue != null) {
throw new IllegalStateException("@InitBinder methods should return void: " + binderMethod);
}
}
}
}
protected boolean isBinderMethodApplicable(HandlerMethod initBinderMethod, WebDataBinder binder) {
InitBinder annot = initBinderMethod.getMethodAnnotation(InitBinder.class);
Collection<String> names = Arrays.asList(annot.value());
// 判断是通用Editor 还是指定类型的Editor, 逻辑简单利落
return (names.size() == 0 || names.contains(binder.getObjectName()));
}
从requet获取数据并bind的过程
public void bind(WebRequest request) {
// 从request获取所有参数(Map of the parameters of this request)
MutablePropertyValues mpvs = new MutablePropertyValues(request.getParameterMap());
if (request instanceof NativeWebRequest) {
// Multipart上传文件 处理
MultipartRequest multipartRequest = ((NativeWebRequest) request).getNativeRequest(MultipartRequest.class);
if (multipartRequest != null) {
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
}
}
// 简化为,将String转换为类型,填充对象属性
doBind(mpvs);
}