Spring数据绑定之 WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...---02

x33g5p2x  于2022-07-22 转载在 Spring  
字(16.3k)|赞(0)|评价(0)|浏览(796)

Spring数据绑定之DataBinder篇—01

WebDataBinder

上一篇我们对DataBinder的源码进行了详细的分析,下面我们对DataBinder的实现子类来做一下具体分析:

通过继承树可以看出,DataBinder的首席大弟子是WebDataBinder,以Web打头,我们大概就可以猜到,该类是用在Web请求参数到具体JavaBean属性的绑定工作中的。

单从WebDataBinder来说,它对父类进行了增强,提供的增强能力如下:

  • 支持对属性名以_打头的默认值处理(自动挡,能够自动处理所有的Bool、Collection、Map等)
  • 支持对属性名以!打头的默认值处理(手动档,需要手动给某个属性赋默认值,自己控制的灵活性很高)
  • 提供方法,支持把MultipartFile绑定到JavaBean的属性上~

下面我们就来看看这些增强功能的具体实现吧:

WebDataBinder中提供了两个标记符合,当请求参数中存在这两个标记符合时,会进行特殊处理:

  1. //如果请求参数中有以_开头的,那么会取请求参数对应类型的默认值
  2. public static final String DEFAULT_FIELD_MARKER_PREFIX = "_";
  3. //如果请求参数中有以!开头的,那么会去请求参数对应值作为默认值
  4. public static final String DEFAULT_FIELD_DEFAULT_PREFIX = "!";
  5. @Nullable
  6. private String fieldMarkerPrefix = DEFAULT_FIELD_MARKER_PREFIX;
  7. @Nullable
  8. private String fieldDefaultPrefix = DEFAULT_FIELD_DEFAULT_PREFIX;

直接讲标记的作用,会是一头雾水,所以下面我们来看看这些标记具体的应用:

  • 首先WebDataBinder对doBind方法进行了重写
  1. @Override
  2. protected void doBind(MutablePropertyValues mpvs) {
  3. checkFieldDefaults(mpvs);
  4. checkFieldMarkers(mpvs);
  5. adaptEmptyArrayIndices(mpvs);
  6. super.doBind(mpvs);
  7. }
  • checkFieldDefaults检查请求参数中是否有!开头的,以!开头的请求参数会作为兜底的默认值存在
  1. protected void checkFieldDefaults(MutablePropertyValues mpvs) {
  2. String fieldDefaultPrefix = getFieldDefaultPrefix();
  3. if (fieldDefaultPrefix != null) {
  4. PropertyValue[] pvArray = mpvs.getPropertyValues();
  5. for (PropertyValue pv : pvArray) {
  6. // 若你给定的PropertyValue的属性名确实是以!打头的 那就做处理如下:
  7. // 如果JavaBean的该属性可写 && mpvs不存在去掉!后的同名属性,那就添加进来表示后续可以使用了(毕竟是默认值,没有精确匹配的高的)
  8. // 然后把带!的给移除掉(因为默认值以已经转正了~~~)
  9. // 其实这里就是说你可以使用!来给个默认值。比如!name表示若找不到name这个属性的时,就取它的值~~~
  10. // 也就是说你request里若有!name保底,也就不怕出现null值啦~
  11. if (pv.getName().startsWith(fieldDefaultPrefix)) {
  12. String field = pv.getName().substring(fieldDefaultPrefix.length());
  13. if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) {
  14. mpvs.add(field, pv.getValue());
  15. }
  16. mpvs.removePropertyValue(pv);
  17. }
  18. }
  19. }
  20. }

例如: 请求参数为 name=dhy&!name=xpy,那么name最终取值为dhy, 如果只有!name=xpy,那么最终我们Controller拿到的name=xpy

  • checkFieldMarkers检查请求参数中是否有_开头的,以_开头的请求参数的值,会给出相应类型的默认值
  1. // 处理_的步骤
  2. // 若传入的字段以_打头
  3. // JavaBean的这个属性可写 && mpvs木有去掉_后的属性名字
  4. // getEmptyValue(field, fieldType)就是根据Type类型给定默认值。
  5. // 比如Boolean类型默认给false,数组给空数组[],集合给空集合,Map给空map 可以参考此类:CollectionFactory
  6. // 当然,这一切都是建立在你传的属性值是以_打头的基础上的,Spring才会默认帮你处理这些默认值
  7. protected void checkFieldMarkers(MutablePropertyValues mpvs) {
  8. String fieldMarkerPrefix = getFieldMarkerPrefix();
  9. if (fieldMarkerPrefix != null) {
  10. PropertyValue[] pvArray = mpvs.getPropertyValues();
  11. for (PropertyValue pv : pvArray) {
  12. if (pv.getName().startsWith(fieldMarkerPrefix)) {
  13. String field = pv.getName().substring(fieldMarkerPrefix.length());
  14. if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) {
  15. Class<?> fieldType = getPropertyAccessor().getPropertyType(field);
  16. mpvs.add(field, getEmptyValue(field, fieldType));
  17. }
  18. mpvs.removePropertyValue(pv);
  19. }
  20. }
  21. }
  22. }

例如: 请求参数为 name=dhy&_name=xpy,那么name最终取值为dhy, 如果只有_name=xpy,那么最终我们Controller拿到的name=null,因为String类型的默认值就是null

  • bindMultipart方法用于将multipartFiles绑定到Java Bean上去
  1. protected void bindMultipart(Map<String, List<MultipartFile>> multipartFiles, MutablePropertyValues mpvs) {
  2. multipartFiles.forEach((key, values) -> {
  3. if (values.size() == 1) {
  4. MultipartFile value = values.get(0);
  5. if (isBindEmptyMultipartFiles() || !value.isEmpty()) {
  6. mpvs.add(key, value);
  7. }
  8. }
  9. else {
  10. mpvs.add(key, values);
  11. }
  12. });
  13. }

实例演示

  1. @Test
  2. public void testWebDataBinder02() throws BindException {
  3. People people = new People();
  4. WebDataBinder webDataBinder = new WebDataBinder(people);
  5. MutablePropertyValues mpvs = new MutablePropertyValues();
  6. mpvs.add("!name","大忽悠");
  7. mpvs.add("_age",20);
  8. webDataBinder.bind(mpvs);
  9. webDataBinder.close();
  10. System.out.println(people);
  11. }

大家也可以自行去尝试一下,WebDataBinder提供的!和_标记,其实是考虑到如果对应属性不存在的情况下,我们可以给出一个默认值替代。

ServletRequestDataBinder

ServletRequestDataBinder名字中的ServletRequest已经暴露了该类的使用场景,它就是遵循了Servlet规范的request参数绑定类。

上面的WebDataBinder本质只是做了一些增强,并没有涉及到Web request请求参数的绑定,相当于并没有和Servlet规范联系到一起,而ServletRequestDataBinder就和servlet规范联系到了一块。

ServletRequestDataBinder的源码也比较简单,就不拆开讲了,直接看吧:

  1. public class ServletRequestDataBinder extends WebDataBinder {
  2. ... // 沿用父类构造
  3. // 注意这个可不是父类的方法,是本类增强的~~~~意思就是kv都从request里来~~当然内部还是适配成了一个MutablePropertyValues
  4. public void bind(ServletRequest request) {
  5. // 内部最核心方法是它:WebUtils.getParametersStartingWith() 把request参数转换成一个Map
  6. // request.getParameterNames()
  7. MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
  8. MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
  9. // 调用父类的bindMultipart方法,把MultipartFile都放进MutablePropertyValues里去~~~
  10. if (multipartRequest != null) {
  11. bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
  12. }
  13. // 这个方法是本类流出来的一个扩展点~~~子类可以复写此方法自己往里继续添加
  14. // 比如ExtendedServletRequestDataBinder它就复写了这个方法,进行了增强(下面会说) 支持到了uriTemplateVariables的绑定
  15. addBindValues(mpvs, request);
  16. doBind(mpvs);
  17. }
  18. // 这个方法和父类的close方法类似,很少直接调用
  19. public void closeNoCatch() throws ServletRequestBindingException {
  20. if (getBindingResult().hasErrors()) {
  21. throw new ServletRequestBindingException("Errors binding onto object '" + getBindingResult().getObjectName() + "'", new BindException(getBindingResult()));
  22. }
  23. }
  24. protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
  25. }
  26. }

ServletRequestDataBinder完成了从request对象中取出所有请求参数,然后封装为MutablePropertyValues的工作,并且还增加对文件上传请参数封装的支持和子类扩展mvps的回调接口。

实例演示

  1. @Test
  2. public void testServletRequestDataBinder03() throws BindException {
  3. People people = new People();
  4. ServletRequestDataBinder srdb = new ServletRequestDataBinder(people);
  5. //需要添加spring-test依赖支持
  6. MockHttpServletRequest mockReq = new MockHttpServletRequest();
  7. mockReq.addParameter("name","大忽悠");
  8. mockReq.addParameter("age","18");
  9. mockReq.addParameter("mother.name","1");
  10. mockReq.addParameter("mother.age","2");
  11. mockReq.addParameter("father.name","3");
  12. mockReq.addParameter("father.age","4");
  13. mockReq.addParameter("list","1","2","3","4");
  14. mockReq.addParameter("map[1]","1");
  15. mockReq.addParameter("map[2]","2");
  16. srdb.bind(mockReq);
  17. System.out.println(people);
  18. }

注意: 对于map属性的赋值而言,不能写成下面这样:

  1. mockReq.addParameter("map","{'name',1}");

即不能使用JSON字符串进行map的赋值,因为这和AbstractNestablePropertyAccessor底层对集合表达式解析并赋值的过程由密切关系,不清楚的可以去研究一下这部分源码。

如果想要用JSON赋值,需要添加一个前置处理,就是把JSON转换为上面的合法的map赋值格式,即可。

ExtendedServletRequestDataBinder

ExtendedServletRequestDataBinder是对ServletRequestDataBinder的一个增强,它用于把URI template variables参数添加进来用于绑定。它会去从request的HandlerMapping.class.getName() + ".uriTemplateVariables" 这个属性里查找到值出来用于绑定。

比如我们熟悉的@PathVariable它就和这相关:

  • 它负责把参数从url模版中解析出来,然后放在attr上,最后交给ExtendedServletRequestDataBinder进行绑定
    具体是由UriTemplateVariablesHandlerInterceptor负责解析request,然后得到相关的uri模板参数,然后加入request的属性集合中去的

具体是在AbstractUrlHandlerMapping类的lookupHandler方法中,完成了对URI template variables的解析。

Spring MVC各组件近距离接触–上–02

该类的具体源码如下:

  1. // @since 3.1
  2. public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
  3. ... // 沿用父类构造
  4. //本类的唯一方法
  5. @Override
  6. @SuppressWarnings("unchecked")
  7. protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
  8. // 它的值是:HandlerMapping.class.getName() + ".uriTemplateVariables";
  9. String attr = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
  10. // 注意:此处是attr,而不是parameter
  11. Map<String, String> uriVars = (Map<String, String>) request.getAttribute(attr);
  12. if (uriVars != null) {
  13. uriVars.forEach((name, value) -> {
  14. // 若已经存在确切的key了,不会覆盖~~~~
  15. if (mpvs.contains(name)) {
  16. if (logger.isWarnEnabled()) {
  17. logger.warn("Skipping URI variable '" + name + "' because request contains bind value with same name.");
  18. }
  19. } else {
  20. mpvs.addPropertyValue(name, value);
  21. }
  22. });
  23. }
  24. }
  25. }
WebExchangeDataBinder

它是Spring5.0后提供的,对Reactive编程的Mono数据绑定提供支持.

MapDataBinder

它位于org.springframework.data.web是和Spring-Data相关,专门用于处理target是Map<String, Object>类型的目标对象的绑定,它并非一个public类.

WebRequestDataBinder

它是用于处理Spring自己定义的org.springframework.web.context.request.WebRequest的,旨在处理和容器无关的web请求数据绑定.

数据绑定过程中采坑的类型转换

虽然DataBinder内部提供了对类型转换的支持,但是由于某些情况下,不存在对应的自定义转换器,会导致赋值失败,那么这种情况下,应该怎么处理呢?

  • 大家看一下下面这段逻辑有没有问题
  1. @Test
  2. public void testServletRequestDataBinder04() throws BindException {
  3. People people = new People();
  4. ServletRequestDataBinder srdb = new ServletRequestDataBinder(people);
  5. //需要添加spring-test依赖支持
  6. MockHttpServletRequest mockReq = new MockHttpServletRequest();
  7. mockReq.addParameter("name","大忽悠");
  8. mockReq.addParameter("age","18");
  9. mockReq.addParameter("birthday","2002-1-2");
  10. srdb.bind(mockReq);
  11. //检查是否在数据绑定和数据校验期间发生了异常,如果发生了则在此处抛出异常
  12. srdb.close();
  13. System.out.println(people);
  14. }

显然错误出在了对birthday属性的赋值上,birthday属性是一个Date类型,我们传入的值是"2002-1-2",那为什么会报错呢?

  • 之前讲过,数据绑定默认是通过BeanWrapper完成的

  • BeanWrapper调用setPropertyValue()给属性赋值,传入的value值都会交给convertForProperty()方法根据get方法的返回值类型进行转换~(比如此处为Date类型)

  • 委托给this.typeConverterDelegate.convertIfNecessary进行类型转换(比如此处为string->Date类型)

  • 先this.propertyEditorRegistry.findCustomEditor(requiredType,propertyName);找到一个合适的PropertyEditor(显然此处我们没有自定义Custom处理Date的PropertyEditor,返回null)

  • 回退到使用ConversionService,显然此处我们也没有设置,返回null

  • 回退到使用默认的editor = findDefaultEditor(requiredType)
    PropertyEditorRegistrySupport中提供的默认类型转换器中没有对Date类型、以及Jsr310提供的各种事件、日期类型的转换(当然也包括我们的自定义类型)。

  • 最终的最终,回退到Spring对Array、Collection、Map的默认值处理问题,最终若是String类型,都会调用
    BeanUtils.instantiateClass(strCtor, convertedValue)也就是有参构造进行初始化~~~(请注意这必须是String类型才有的权利)

所以本例中,到最后一步就相当于new Date(“2002-1-2”),因为该字符串是不符合默认的格式规范,所以会抛出异常。

Spring读源码系列番外篇08—BeanWrapper没有那么简单–上

要解决上面这个问题,那么就是需要注册一个可以转换Date的类型转换器进去,有下面几种方法:

  • 可以选择Spring 3.0后推出的Formatter体系中专门用来格式化Date日期的DateFormatter
  1. @Test
  2. public void testServletRequestDataBinder04() throws BindException {
  3. People people = new People();
  4. ServletRequestDataBinder srdb = new ServletRequestDataBinder(people);
  5. //需要添加spring-test依赖支持
  6. MockHttpServletRequest mockReq = new MockHttpServletRequest();
  7. mockReq.addParameter("name","大忽悠");
  8. mockReq.addParameter("age","18");
  9. mockReq.addParameter("birthday","2002-1-2");
  10. srdb.addCustomFormatter(new DateFormatter());
  11. srdb.bind(mockReq);
  12. srdb.close();
  13. System.out.println(people);
  14. }
  • 或者自定义一个PropertyEditor,然后注册进去
  1. public class MyDatePropertyEditor extends PropertyEditorSupport {
  2. private static final String PATTERN = "yyyy-MM-dd";
  3. @Override
  4. public String getAsText() {
  5. Date date = (Date) super.getValue();
  6. return new SimpleDateFormat(PATTERN).format(date);
  7. }
  8. @Override
  9. public void setAsText(String text) throws IllegalArgumentException {
  10. try {
  11. super.setValue(new SimpleDateFormat(PATTERN).parse(text));
  12. } catch (ParseException e) {
  13. System.out.println("ParseException....................");
  14. }
  15. }
  16. }
  1. srdb.registerCustomEditor(Date.class, new MyDatePropertyEditor());

WebBindingInitializer

WebBindingInitializer:实现此接口重写initBinder方法注册的属性编辑器是全局的属性编辑器,对所有的Controller都有效。

可以简单粗暴的理解为:WebBindingInitializer为编码方式,@InitBinder为注解方式(当然注解方式还能控制到只对当前Controller有效,实现更细粒度的控制)

  1. public interface WebBindingInitializer {
  2. void initBinder(WebDataBinder binder);
  3. //spring 5.0之后废弃了该方法
  4. @Deprecated
  5. default void initBinder(WebDataBinder binder, WebRequest request) {
  6. initBinder(binder);
  7. }
  8. }

此接口它的内建唯一实现类为:ConfigurableWebBindingInitializer,若你自己想要扩展,建议继承它:

  1. public class ConfigurableWebBindingInitializer implements WebBindingInitializer {
  2. //默认支持级联属性
  3. private boolean autoGrowNestedPaths = true;
  4. //底层默认使用BeanWrapper
  5. private boolean directFieldAccess = false;
  6. @Nullable
  7. private MessageCodesResolver messageCodesResolver;
  8. @Nullable
  9. private BindingErrorProcessor bindingErrorProcessor;
  10. @Nullable
  11. private Validator validator;
  12. @Nullable
  13. private ConversionService conversionService;
  14. // 此处使用的PropertyEditorRegistrar来管理的,最终都会被注册进PropertyEditorRegistry
  15. @Nullable
  16. private PropertyEditorRegistrar[] propertyEditorRegistrars;
  17. ... // 省略所有get/set
  18. // 它做的事无非就是把配置的值都放进去而已~~
  19. @Override
  20. public void initBinder(WebDataBinder binder) {
  21. binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
  22. if (this.directFieldAccess) {
  23. binder.initDirectFieldAccess();
  24. }
  25. if (this.messageCodesResolver != null) {
  26. binder.setMessageCodesResolver(this.messageCodesResolver);
  27. }
  28. if (this.bindingErrorProcessor != null) {
  29. binder.setBindingErrorProcessor(this.bindingErrorProcessor);
  30. }
  31. // 可以看到对校验器这块 内部还是做了容错的
  32. if (this.validator != null && binder.getTarget() != null && this.validator.supports(binder.getTarget().getClass())) {
  33. binder.setValidator(this.validator);
  34. }
  35. if (this.conversionService != null) {
  36. binder.setConversionService(this.conversionService);
  37. }
  38. if (this.propertyEditorRegistrars != null) {
  39. for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
  40. propertyEditorRegistrar.registerCustomEditors(binder);
  41. }
  42. }
  43. }
  44. }

此实现类主要是提供了一些可配置项,用来覆盖DataBinder的默认配置。

注意:此接口一般不直接使用,而是结合InitBinderDataBinderFactory、WebDataBinderFactory等一起使用~

WebDataBinderFactory

顾名思义它就是来创造一个WebDataBinder的工厂。

  1. // @since 3.1 注意:WebDataBinder 可是1.2就有了~
  2. public interface WebDataBinderFactory {
  3. // 此处使用的是Spring自己的NativeWebRequest 后面两个参数就不解释了
  4. WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception;
  5. }

继承树如下:

DefaultDataBinderFactory

  1. public class DefaultDataBinderFactory implements WebDataBinderFactory {
  2. @Nullable
  3. private final WebBindingInitializer initializer;
  4. // 注意:这是唯一构造函数
  5. public DefaultDataBinderFactory(@Nullable WebBindingInitializer initializer) {
  6. this.initializer = initializer;
  7. }
  8. // 实现接口的方法
  9. @Override
  10. @SuppressWarnings("deprecation")
  11. public final WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception {
  12. WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
  13. // 可见WebDataBinder 创建好后,此处就会回调(只有一个)
  14. if (this.initializer != null) {
  15. //通过WebBindingInitializer的initBinder方法,我们可以覆盖掉dataBinder的默认配置
  16. this.initializer.initBinder(dataBinder, webRequest);
  17. }
  18. // 空方法 子类去实现,比如InitBinderDataBinderFactory实现了词方法
  19. initBinder(dataBinder, webRequest);
  20. return dataBinder;
  21. }
  22. // 子类可以复写,默认实现是WebRequestDataBinder
  23. // 比如子类ServletRequestDataBinderFactory就复写了,使用的new ExtendedServletRequestDataBinder(target, objectName)
  24. protected WebDataBinder createBinderInstance(@Nullable Object target, String objectName, NativeWebRequest webRequest) throws Exception
  25. return new WebRequestDataBinder(target, objectName);
  26. }
  27. //空实现
  28. protected void initBinder(WebDataBinder dataBinder, NativeWebRequest webRequest)
  29. throws Exception {
  30. }
  31. }

按照Spring一贯的设计,本方法实现了模板动作,子类只需要复写对应的动作即可达到效果。

InitBinderDataBinderFactory

它继承自DefaultDataBinderFactory,主要用于处理标注有@InitBinder的方法做初始绑定~
关于@InitBinder注解的原理,后续会出一篇文章专门讲解

  1. // @since 3.1
  2. public class InitBinderDataBinderFactory extends DefaultDataBinderFactory {
  3. // 需要注意的是:`@InitBinder`可以标注N多个方法~ 所以此处是List
  4. //拿到的InvocableHandlerMethod就是Controller类中标注了@InitBinder的方法
  5. private final List<InvocableHandlerMethod> binderMethods;
  6. // 此子类的唯一构造函数
  7. public InitBinderDataBinderFactory(@Nullable List<InvocableHandlerMethod> binderMethods, @Nullable WebBindingInitializer initializer) {
  8. super(initializer);
  9. this.binderMethods = (binderMethods != null ? binderMethods : Collections.emptyList());
  10. }
  11. // 上面知道此方法的调用方法生initializer.initBinder之后
  12. // 所以使用注解它生效的时机是在直接实现接口的后面的~
  13. @Override
  14. public void initBinder(WebDataBinder dataBinder, NativeWebRequest request) throws Exception {
  15. for (InvocableHandlerMethod binderMethod : this.binderMethods) {
  16. // 判断@InitBinder是否对dataBinder持有的target对象生效~~~(根据name来匹配的)
  17. if (isBinderMethodApplicable(binderMethod, dataBinder)) {
  18. // 关于目标方法执行这块---binderMethod只有一个参数为WebDataBinder,并且返回值必须为null
  19. Object returnValue = binderMethod.invokeForRequest(request, null, dataBinder);
  20. // 标注@InitBinder的方法不能有返回值
  21. if (returnValue != null) {
  22. throw new IllegalStateException("@InitBinder methods must not return a value (should be void): " + binderMethod);
  23. }
  24. }
  25. }
  26. }
  27. //@InitBinder有个Value值,它是个数组。它是用来匹配dataBinder.getObjectName()是否匹配的 若匹配上了,现在此注解方法就会生效
  28. // 若value为空,那就对所有生效~~~
  29. protected boolean isBinderMethodApplicable(HandlerMethod initBinderMethod, WebDataBinder dataBinder) {
  30. InitBinder ann = initBinderMethod.getMethodAnnotation(InitBinder.class);
  31. Assert.state(ann != null, "No InitBinder annotation");
  32. String[] names = ann.value();
  33. return (ObjectUtils.isEmpty(names) || ObjectUtils.containsElement(names, dataBinder.getObjectName()));
  34. }
  35. }
ServletRequestDataBinderFactory

它继承自InitBinderDataBinderFactory,作用就更明显了。既能够处理@InitBinder,而且它使用的是更为强大的数据绑定器:ExtendedServletRequestDataBinder

  1. // @since 3.1
  2. public class ServletRequestDataBinderFactory extends InitBinderDataBinderFactory {
  3. public ServletRequestDataBinderFactory(@Nullable List<InvocableHandlerMethod> binderMethods, @Nullable WebBindingInitializer initializer) {
  4. super(binderMethods, initializer);
  5. }
  6. @Override
  7. protected ServletRequestDataBinder createBinderInstance(
  8. @Nullable Object target, String objectName, NativeWebRequest request) throws Exception {
  9. return new ExtendedServletRequestDataBinder(target, objectName);
  10. }
  11. }

此工厂是RequestMappingHandlerAdapter这个适配器默认使用的一个数据绑定器工厂,而RequestMappingHandlerAdapter却又是当下使用得最频繁、功能最强大的一个适配器

小结

WebDataBinder在SpringMVC中使用,它不需要我们自己去创建,我们只需要向它注册参数类型对应的属性编辑器PropertyEditor。PropertyEditor可以将字符串转换成其真正的数据类型,它的void setAsText(String text)方法实现数据转换的过程。

而如果我们想要获取到WebDataBinder来进行属性编辑器的注册或者其他干一些其他事情,可以通过WebBindingInitializer接口或者@InitBinder注解来完成。

相关文章