2、注册进DataBinder并运行
public static void main(String[] args) { Person person = new Person(); DataBinder binder = new DataBinder(person, "person"); binder.registerCustomEditor(Date.class, new MyDatePropertyEditor()); //binder.registerCustomEditor(Date.class, "end", new MyDatePropertyEditor()); // 设置属性 MutablePropertyValues pvs = new MutablePropertyValues(); pvs.add("name", "fsx"); // 事件类型绑定 pvs.add("start", new Date()); pvs.add("end", "2019-07-20"); // 试用试用标准的事件日期字符串形式~ pvs.add("endTest", "Sat Jul 20 11:00:22 CST 2019"); binder.bind(pvs); System.out.println(person); }运行打印如下:
ParseException.................... Person(name=fsx, age=null, start=Sat Jul 20 11:41:49 CST 2019, end=Sat Jul 20 00:00:00 CST 2019, endTest=null)结果符合预期。不过对此结果我仍旧抛出如下两个问题供小伙伴自行思考:
1、输出了ParseException....................
2、start有值,endTest值却为null了
理解这块最后我想说:通过自定义编辑器,我们可以非常自由、高度定制化的完成自定义类型的封装,可以使得我们的Controller更加容错、更加智能、更加简洁。有兴趣的可以运用此块知识,自行实践~
WebBindingInitializer和WebDataBinderFactory WebBindingInitializerWebBindingInitializer:实现此接口重写initBinder方法注册的属性编辑器是全局的属性编辑器,对所有的Controller都有效。
可以简单粗暴的理解为:WebBindingInitializer为编码方式,@InitBinder为注解方式(当然注解方式还能控制到只对当前Controller有效,实现更细粒度的控制)
观察发现,Spring对这个接口的命名很有意思:它用的Binding正在进行时态~
// @since 2.5 Spring在初始化WebDataBinder时候的回调接口,给调用者自定义~ public interface WebBindingInitializer { // @since 5.0 void initBinder(WebDataBinder binder); // @deprecated as of 5.0 in favor of {@link #initBinder(WebDataBinder)} @Deprecated default void initBinder(WebDataBinder binder, WebRequest request) { initBinder(binder); } }此接口它的内建唯一实现类为:ConfigurableWebBindingInitializer,若你自己想要扩展,建议继承它~
public class ConfigurableWebBindingInitializer implements WebBindingInitializer { private boolean autoGrowNestedPaths = true; private boolean directFieldAccess = false; // 显然这里是false // 下面这些参数,不就是WebDataBinder那些可以配置的属性们吗? @Nullable private MessageCodesResolver messageCodesResolver; @Nullable private BindingErrorProcessor bindingErrorProcessor; @Nullable private Validator validator; @Nullable private ConversionService conversionService; // 此处使用的PropertyEditorRegistrar来管理的,最终都会被注册进PropertyEditorRegistry嘛 @Nullable private PropertyEditorRegistrar[] propertyEditorRegistrars; ... // 省略所有get/set // 它做的事无非就是把配置的值都放进去而已~~ @Override public void initBinder(WebDataBinder binder) { binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths); if (this.directFieldAccess) { binder.initDirectFieldAccess(); } if (this.messageCodesResolver != null) { binder.setMessageCodesResolver(this.messageCodesResolver); } if (this.bindingErrorProcessor != null) { binder.setBindingErrorProcessor(this.bindingErrorProcessor); } // 可以看到对校验器这块 内部还是做了容错的 if (this.validator != null && binder.getTarget() != null && this.validator.supports(binder.getTarget().getClass())) { binder.setValidator(this.validator); } if (this.conversionService != null) { binder.setConversionService(this.conversionService); } if (this.propertyEditorRegistrars != null) { for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) { propertyEditorRegistrar.registerCustomEditors(binder); } } } }此实现类主要是提供了一些可配置项,方便使用。注意:此接口一般不直接使用,而是结合InitBinderDataBinderFactory、WebDataBinderFactory等一起使用~
WebDataBinderFactory顾名思义它就是来创造一个WebDataBinder的工厂。
// @since 3.1 注意:WebDataBinder 可是1.2就有了~ public interface WebDataBinderFactory { // 此处使用的是Spring自己的NativeWebRequest 后面两个参数就不解释了 WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception; }