Spring --- Data Binding

一) BeanWrapper
  BeanWrapper这个类一般不会被Spring的使用者直接调用,而是使用DataBinder和BeanFactory这两个类是间接被调用的。但是知道BeanWrapper的使用方式对于理解Spring的数据绑定机制还是十分用益的。下面我们就来看个BeanWrapper被直接调用的例子:
//首先是两个对象类Company  Employee
public class Company {
  private String name;
  private Employee managingDirector;
  public String getName() {
    return this.name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Employee getManagingDirector() {
    return this.managingDirector;
  }
  public void setManagingDirector(Employee managingDirector) {
    this.managingDirector = managingDirector;
  }
}

public class Employee {
  private String name;
  private float salary;
  public String getName() {
    return this.name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public float getSalary() {
    return salary;
  }
  public void setSalary(float salary) {
    this.salary = salary;
  }
}

BeanWrapper company = BeanWrapperImpl(new Company());
// setting the company name..
company.setPropertyValue("name", "Some Company Inc.");
// ... can also be done like this:
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
company.setPropertyValue(value);
// ok, let's create the director and tie it to the company:
BeanWrapper jim = BeanWrapperImpl(new Employee());
jim.setPropertyValue("name", "Jim Stravinsky");
company.setPropertyValue("managingDirector", jim.getWrappedInstance());
// retrieving the salary of the managingDirector through the company
Float salary = (Float) company.getPropertyValue("managingDirector.salary");

  这便是BeanWrapper的核心作用——数据绑定!

二)PropertyEditor -- 属性编辑器
  Spring的数据绑定非常强大。属性编辑器PropertyEditor的主要功能就是将外部的设置值转换为JVM内部的对应类型,所以属性编辑器其实就是一个类型转换器。它负责String与Object之间的转换。Spring本身已经定义了许多种类的属性编辑器,所以一些常用类型的转换已经不需要我们再关心了。我们关心的应该是如何自定义的PropertyEditor去满足某些特殊类的转换。
  你可以有两种方式定义PropertyEditor,但不管采用哪种Spring都使用java.beans.PropertyEditorManager类来搜寻一个类所对应的属性编辑器。
  1' 第一种当然是默认路径。

  如图,FooEditor便是Foo的属性编辑器了。在同一Package下,Spring默认类名+"Editor" 便是该类的属性编辑器。

  2'当然,第二种你也可以自定义属性编辑器的位置和名称。
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  <property name="customEditors">
    <map>
     <entry key="example.ExoticType" value="example.ExoticTypeEditor"/>
    </map>
  </property>
</bean>

注:如果使用BeanFactory,用户需要手工调用registerCustomEditor(Class requiredType, PropertyEditor propertyEditor)方法注册自定义属性编辑器;如果使用ApplicationContext,则只需要在配置文件通过CustomEditorConfigurer注册就可以了。一般情况下,我们当然使用ApplicationContext。如上面这个例子,我们自定义了一个名叫ExoticTypeEditor的属性编辑器,它专门负责对ExoticType类的转换。具体的代码如下:
// converts string representation to ExoticType object
package example;
public class ExoticTypeEditor extends PropertyEditorSupport {
  public void setAsText(String text) {
    setValue(new ExoticType(text.toUpperCase()));
  }
}
---------------------------------------------------------------
package example;
public class ExoticType {
  private String name;
  public ExoticType(String name) {
    this.name = name;
  }
}

注:一般地,我们要使用PropertyEditor时,并不直接实现此接口,而是通过继承实现此接口的java.beans.PropertyEditorSupport来简化我们的工作,在子类覆盖setAsText方法就可以了,setValue方法一般不直接使用,在setAsText方法中将字符串进行转换并产生目标对象以后,由调setAsText调用setValue来把目标对象注入到编辑器中。当然,你可用覆盖更多的方法来满足你的特殊要求。
  这样当我们遇到如下情况时,我们的自定义属性编辑器便会被触发使用(反射机制):
public class DependsOnExoticType {
  private ExoticType type;
  public void setType(ExoticType type) {
    this.type = type;
  }
}
<bean id="sample" class="example.DependsOnExoticType">
  <property name="type" value="aNameForExoticType"/>
</bean>


  3' 刚说了只有两种定义属性编辑器的方式,这会儿咋又来第三种呢?呵呵,这种方式确实有点..."另类"?但它的作用非常大,它可以满足一个类中用到多个属性编辑器的情况:

    还是首先讲讲命名规则,如图,FooBeanInfo便是Foo类的BeanInfo了。同一Package下,类名+"BeanInfo" 便是该类对应的属性编辑器,与之前不同的是,它说明了该了中需要使用到的一个或多个子属性编辑器。而它的代码实现如下:
public class FooBeanInfo extends SimpleBeanInfo {
  public PropertyDescriptor[] getPropertyDescriptors() {
    try {
      final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);
      PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) {
         public PropertyEditor createPropertyEditor(Object bean) {
           return numberPE;
         };
      };
      return new PropertyDescriptor[] { ageDescriptor };
    }
    catch (IntrospectionException ex) {
      throw new Error(ex.toString());
    }
  }
}

注:BeanInfo接口有一个常用的实现类:SimpleBeanInfo,一般情况下,可以通过扩展SimpleBeanInfo实现自己的功能。

三)PropertyEditorRegistrars
  这个数据绑定接口结合Spring MVC模块一起使用效果非常好。结合一个例子就非常容易明白:
   首先是声明和配置:
package com.foo.editors.spring;
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
  public void registerCustomEditors(PropertyEditorRegistry registry) {
    // it is expected that new PropertyEditor instances are created
    registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());
    // you could register as many custom property editors as are required here...
  }
}

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  <property name="propertyEditorRegistrars">
  <list>
    <ref bean="customPropertyEditorRegistrar"/>
  </list>
  </property>
</bean>
<bean id="customPropertyEditorRegistrar" class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>

  而后是在Spring MVC中使用它:
public final class RegisterUserController extends SimpleFormController {
  private final PropertyEditorRegistrar customPropertyEditorRegistrar;
  public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {
    this.customPropertyEditorRegistrar = propertyEditorRegistrar;
  }
  protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
    this.customPropertyEditorRegistrar.registerCustomEditors(binder);
  }
  // other methods to do with registering a User
}

  这样就实现了http请求参数与对应类的转换。而且代码还可高度重用,非常好的一个设计!

你可能感兴趣的:(java,spring)