需要说明一点:虽然此处有key是user.name,但是User对象可是不会封装到此值的(因为request.getParameter('user')没这个key嘛~)。如何解决???需要绑定前缀,原理可参考这里
其它应用场景上面例举的场景是此注解最为常用的场景,大家务必掌握。它还有一些奇淫技巧的使用,心有余力的小伙伴不妨也可以消化消化:
若你一次提交需要提交两个"模型"数据,并且它们有重名的属性。形如下面例子:
@Controller @RequestMapping public class HelloController { @Getter @Setter @ToString public static class User { private String id; private String name; } @Getter @Setter @ToString public static class Addr { private String id; private String name; } @InitBinder("user") public void initBinderUser(WebDataBinder binder) { binder.setFieldDefaultPrefix("user."); } @InitBinder("addr") public void initBinderAddr(WebDataBinder binder) { binder.setFieldDefaultPrefix("addr."); } @ResponseBody @GetMapping("/test/initbinder") public String testInitBinder(@ModelAttribute("user") User user, @ModelAttribute("addr") Addr addr) { return user + ":" + addr; } }请求:/test/initbinder?user.id=1&user.name=demoUser&addr.id=10&addr.name=北京市海淀区,结果为:HelloController.User(id=1, name=demoUser):HelloController.Addr(id=10, name=北京市海淀区)
至于加了前缀为何能绑定上,这里简要说说:
1、ModelAttributeMethodProcessor#resolveArgument里依赖attribute = createAttribute(name, parameter, binderFactory, webRequest)方法完成数据的封装、转换
2、createAttribute先request.getParameter(attributeName)看请求域里是否有值(此处为null),若木有就反射创建一个空实例,回到resolveArgument方法。
3、继续利用WebDataBinder来完成对这个空对象的数据值绑定,这个时候这些FieldDefaultPrefix就起作用了。执行方法是:bindRequestParameters(binder, webRequest),实际上是((WebRequestDataBinder) binder).bind(request);。对于bind方法的原理,就不陌生了~
4、完成Model数据的封装后,再进行@Valid校验...
参考解析类:ModelAttributeMethodProcessor对参数部分的处理
总结本文花大篇幅从原理层面总结了@InitBinder这个注解的使用,虽然此注解在当下的环境中出镜率并不是太高,但我还是期望小伙伴能理解它,特别是我本文举例说明的例子的场景一定能做到运用自如。
最后,此注解的使用的注意事项我把它总结如下,供各位使用过程中参考:
@InitBinder标注的方法执行是多次的,一次请求来就执行一次(第一次惩罚)
Controller实例中的所有@InitBinder只对当前所在的Controller有效
@InitBinder的value属性控制的是模型Model里的key,而不是方法名(不写代表对所有的生效)
@InitBinder标注的方法不能有返回值(只能是void或者returnValue=null)
@InitBinder对@RequestBody这种基于消息转换器的请求参数无效
1. 因为@InitBinder它用于初始化DataBinder数据绑定、类型转换等功能,而@RequestBody它的数据解析、转换时消息转换器来完成的,所以即使你自定义了属性编辑器,对它是不生效的(它的WebDataBinder只用于数据校验,不用于数据绑定和数据转换。它的数据绑定转换若是json,一般都是交给了jackson来完成的)
只有AbstractNamedValueMethodArgumentResolver才会调用binder.convertIfNecessary进行数据转换,从而属性编辑器才会生效
== 若对Spring、SpringBoot、MyBatis等源码分析感兴趣,可加我wx:fsx641385712,手动邀请你入群一起飞 ==
== 若对Spring、SpringBoot、MyBatis等源码分析感兴趣,可加我wx:fsx641385712,手动邀请你入群一起飞 ==