Spring 6【数据绑定时类型转换、装饰器设计模式、DataBinder源码分析BeanWrapper、Errors、BindingResult】(十二)-全面详解(学习总结---从入门到深化)

 

目录

3.数据绑定时类型转换

4.装饰器设计模式

5.DataBinder源码分析BeanWrapper、Errors、BindingResult


3.数据绑定时类型转换

类型转换都是发生在数据绑定时。并且在DataBinder上可以看到实现两个接口

public class DataBinder implements PropertyEditorRegistry, TypeConverter

 其中PropertyEditorRegistry作用注册已有类型转换器。根据Bean属性类型从这些类型转换器中选择需 要使用的。虽然DataBinder是PropertyEditorRegistry的实现类,但是PropertyEditorRegistry使用最多 的实现类是PropertyEditorRegistrySupport。

TypeConverter表示类可以进行类型转换服务,底层是基于BeanWrapper实现的(装饰器设计模式)。

在使用TypeConverter时,如果是简单类型,可以直接使用 SimpleTypeConverter,SimpleTypeConverter即实现了PropertyEditorRegistry,又实现了 TypeConverter。使用也很简单

@Test
void testSimpleTypeConverter(){
     SimpleTypeConverter simpleTypeConverter = new SimpleTypeConverter();
     Integer result = simpleTypeConverter.convertIfNecessary("123",Integer.class);
     System.out.println(result);
}

在DataBinder中进行简单数据类型转换,默认使用getSimpleTypeConverter进行转换的。

@Test
void test123(){
     DataBinder dataBinder = new DataBinder("","integer");
     Integer result = dataBinder.convertIfNecessary("123", Integer.class);
     System.out.println(result);
}

4.装饰器设计模式

4.1 装饰器设计模式介绍

装饰器设计模式,又称装饰者设计模式。英文多见:Wrapper、Decorator。

装饰器设计模式属于继承的一种替代模式,使用装饰模式可以动态扩展实现功能。

其本质:“使用关联代替继承”,毕竟继承这种关系属于一种强关系,是Java之父自己承认:“java中自己认 为最后悔的功能是继承”

4.2 装饰器模式角色图

设定需求:

在学校有专业:Java、前端专业。每个专业有自己的学习内容。现赶上学校20周年校庆,学校对专业下 达命令,各个专业根据自己的实力对学生分配对象。 针对这个需求,可以直接修改原有代码,在父类添加公共方法,子类去重写具体怎么分配对象。但是这样不符合开闭原则(对修改关闭,对扩展开放)

也可以直接对Java专业和前端专业新建子类。但是这种方式随着项目功能变多,子类数量也会特别多。

 

使用装饰器模式,主要就是添加一个新的角色。装饰者,让装饰者也实现专业接口,并在装饰者里面放 置原来父接口的关联对象。 按照下图修改后主要分为四个角色:

1、组件(Component) : 专业接口(Subject),提出出公共方法的接口。

2、组件实现(Concrete Component):需要被装饰的实现类。例如:Java专业和前端专业。

3、抽象装饰(Decorator): 定义需要装饰的方法。

4、SubjectWrapper 具体装饰(Concrete Decorator):实现装饰的方法。 SubjectWrapperImpl 

 

4.3 装饰器模式代码实现 

新建专业接口

// 专业接口
public interface Subject {
   // 专业内容方法
   void subject();
}

新建java专业实现类

// java专业
public class JavaSubject implements Subject{
     @Override
     public void subject() {
         System.out.println("java专业");
    }
}

前端专业实现类

public class FrontendSubject implements Subject {
    @Override
    public void subject() {
          System.out.println("前端专业");
    }
}

新建专业包装接口,提出需要包装的方法

public interface SubjectWrapper extends Subject {
     void friend();
}

创建包装的具体实现

public class SubjectWrapperImpl implements SubjectWrapper{
     private Subject subject;
     public SubjectWrapperImpl(Subject subject) {
           this.subject = subject;
      }
    
     @Override
     public void subject() {
            subject.subject();
            friend();// 调用包装方法
      }

     @Override
     public void friend() {
         System.out.println("分配女朋友");
     }
}

测试类测试效果

public class TestWrapper {
   public static void main(String[] args) {
      JavaSubject javaSubject = new JavaSubject();
      SubjectWrapperImpl subjectWrapper = new SubjectWrapperImpl(javaSubject);
      subjectWrapper.subject();
    }
}

4.4 装饰器模式优缺点

优点:

动态扩充,不需要修改原有代码,不需要过度使用继承

缺点:

多重装饰比较复杂。

5.DataBinder源码分析BeanWrapper、Errors、BindingResult

BeanWrapper 是 基于装饰器设计模式实现的。实现了PropertyEditorRegistry接口和TypeConverter接 口。

在DataBinder数据绑定时,Bean的属性绑定过程就是使用BeanWrapper实现的。

BeanWrapper只有一个实现类BeanWrapperImpl,这个类还是PropertyEditorSupport子类,所以具备 类型转换的能力。

在使用DataBinder的convertIfNecessary()方法时,底层通过getTypeConverter()获取到类型转换器对 象。 

@Override
@Nullable
public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException {
        return getTypeConverter().convertIfNecessary(value, requiredType);
}

getTypeConverter()方法中类型转换器是通过getInternaleBindingResult()获取到的。

protected TypeConverter getTypeConverter() {
     if (getTarget() != null) {
           return getInternalBindingResult().getPropertyAccessor();
      }
      else {
          return getSimpleTypeConverter();
     }
}

getInternaleBindingResult()方法返回结果类型为AbstractPropertyBindingResult,通过断电可以看出来 实际返回结果子类BeanPropertyBindingResult。

protected AbstractPropertyBindingResult getInternalBindingResult() {
      if (this.bindingResult == null) {
           this.bindingResult = (this.directFieldAccess ? createDirectFieldBindingResult():
           createBeanPropertyBindingResult());
        }
     return this.bindingResult;
}

createBeanPropertyBindingResult()方法

protected AbstractPropertyBindingResult createBeanPropertyBindingResult() {
        BeanPropertyBindingResult result = new  BeanPropertyBindingResult(getTarget(), getObjectName(), isAutoGrowNestedPaths(), getAutoGrowCollectionLimit());
        if (this.conversionService != null) {
               result.initConversion(this.conversionService);
        }
        if (this.messageCodesResolver != null) {
              result.setMessageCodesResolver(this.messageCodesResolver);
        }
      return result;
}

AbstractPropertyBindingResult是Errors接口和BindingResult接口的实现类。 Errors接口里面存储数据绑定和错误信息。也就是是说通过Errors可以获取到属性的信息并且给属性绑 定一个错误信息。 Errors接口里面方法比较多

public interface Errors {
    /**
    * 实际值为点(.)
    */
    String NESTED_PATH_SEPARATOR = PropertyAccessor.NESTED_PROPERTY_SEPARATOR;
    /**
    * 返回绑定对象名字
    */
    String getObjectName();
    /**
     * 设置嵌套路径,当有关联对象时使用
     */
    void setNestedPath(String nestedPath);
    /**
    * 获取嵌套路径字符串类型值
    */
    String getNestedPath();
    /**
    * 把嵌套路径放入栈中
    */
    void pushNestedPath(String subPath);
    /**
    * 移除嵌套路径从栈中
    */
    void popNestedPath() throws IllegalStateException;
    /**
    * 给对象绑定一个全局的错误码(errorCode)
    */
    void reject(String errorCode);
    /**
    * 给对象绑定一个全局的错误码(errorCode)和错误信息(defaultMessage)
    */
    void reject(String errorCode, String defaultMessage);
    /**
    * 给对象绑定一个全局错误码(errorCode)、错误参数(errorArgs),错误信息(defualtMessage)
    */
    void reject(String errorCode, @Nullable Object[] errorArgs, @Nullable String
defaultMessage);
    /**
    * 给属性绑定错误码
    */
    void rejectValue(@Nullable String field, String errorCode);
    /**
    * 给属性绑定错误码和错误信息
    */
    void rejectValue(@Nullable String field, String errorCode, String
defaultMessage);
    /**
    * 给属性绑定错误码和错误参数及错误信息
    */
    void rejectValue(@Nullable String field, String errorCode,
@Nullable Object[] errorArgs, @Nullable String defaultMessage);
    /**
    * 把参数(errors)实例所有内容添加到当前对象中
    */
    void addAllErrors(Errors errors);
    /**
    * 判断是否有错误
    */
    boolean hasErrors();
    /**
    * 返回错误的数量
    */
    int getErrorCount();
    /**
    * 获取到所有的错误对象
    */
    List<ObjectError> getAllErrors();
    /**
    * 是否有全局错误
    */
    boolean hasGlobalErrors();
    /**
    * 获取全局错误信息
    */
    int getGlobalErrorCount();
    /**
    * 获取所有全局错误实例
    */
    List<ObjectError> getGlobalErrors();
    /**
    * 获取全局错误对象
    */
    @Nullable
    ObjectError getGlobalError();
    /**
    * 是否有属性错误
    */
    boolean hasFieldErrors();
    /**
    * 获取属性错误个数
    */
    int getFieldErrorCount();
    /**
    * 获取属性错误集合
    */
    List<FieldError> getFieldErrors();
    /**
    * 获取属性错误对象
    */
    @Nullable
    FieldError getFieldError();
    /**
     * 判断某个属性是否有错误
    */
    boolean hasFieldErrors(String field);
    /**
     * 获取某个属性错误个数
     */
    int getFieldErrorCount(String field);
    /**
    * 获取某个属性错误集合
    */
    List<FieldError> getFieldErrors(String field);
    /**
    * 获取某个属性错误个数
    */
    @Nullable
    FieldError getFieldError(String field);
    /**
    * 获取某个属性的值
    */
    @Nullable
    Object getFieldValue(String field);
    /**
    * 获取某个属性的类型
    */
    @Nullable
    Class<?> getFieldType(String field);
}

而BindingResult是Errors接口的子接口。也就是说里面也存储了错误信息和属性绑定信息。而 BindingResult接口主要是为了和数据校验Validation一起使用的。所以下一章节我们就讲解一下Validation是什么。 我们继续看源码getTypeConverter()方法中获取到BindingResult后,调用getPropertyAccessor()

protected TypeConverter getTypeConverter() {
    if (getTarget() != null) {
         return getInternalBindingResult().getPropertyAccessor();
     }
     else {
        return getSimpleTypeConverter();
    }
}

 getPropertyAccessor()方法最终返回的是BeanWrapper,如果继续跟源码,可以知道 createBeanWrapper()方法实际返回结果为BeanWrapperImpl。这也说明了DataBinder数据绑定时, 类型转换器本质是BeanWrapper的实现类BeanWrapperImpl。使用了装饰者模式。

@Override
public final ConfigurablePropertyAccessor getPropertyAccessor() {
     if (this.beanWrapper == null) {
           this.beanWrapper = createBeanWrapper();
           this.beanWrapper.setExtractOldValueForEditor(true);
           this.beanWrapper.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
           this.beanWrapper.setAutoGrowCollectionLimit(this.autoGrowCollectionLimit);
      }
    return this.beanWrapper;
}

猜你喜欢

转载自blog.csdn.net/m0_58719994/article/details/131990858