第 4 章 属性编辑器,数据绑定,校验与BeanWeapper(Bean封装)
4.1. 简介
是否需要对业务逻辑进行验证是一个常见的问题。 有关这一点存在两种截然想法的回答,Spring提出的验证模式(和数据绑定)对两者都不排斥。 验证应该是可以定制化的并且能够依附于任何的验证框架而不应该被强制绑定在Web层。 基于以上原因,Spring提供了一个Validator接口,这个接口可以被应用于应用程序的任何一个层面 (表示层或者逻辑层等 译者注)
数据绑定可以使用户输入与应用程序的域模型进行动态绑定(或者用于处理用户输入对象)。 针对这一点Spring提供了所谓的DataBinder(数据绑定)。 DataBinder和Validator组成了验证包(validation),它主要被用于MVC结构, 除此之外也可以被用于其他的地方。
BeanWrapper是Spring架构的一个基本组件,它在很多地方都是很有用的。 然而,你可能很少直接使用BeanWrapper。 由于这是一篇参考文档,所以我们觉得对此稍作解释还是有必要的。 因为今后你也许进行对象与数据之间的绑定操作,到时就会用到BeanWrapper 了。
Srping大量的使用了PropertyEditors(属性编辑)。 它属于JavaBeans规范的一部分。就像我们上面提到的BeanWrapper一样, PropertyEditors和BeanWrapper以及DataBinder三者之间有着密切的联系。
4.2. 使用DataBinder进行数据绑定
DataBinder构建于BeanWrapper之上。[2].
4.3. Bean处理与BeanWrapper
org.springframework.beans包遵循Sun发布的JavaBeans标准。 一个JavaBean是一个简单的包含无参数构造函数的类,并且包含seter和getter属性方法。 例如prop属性对应setProp(...)方法和getProp()方法. 如果需要了解JavaBeans的详细信息可以访问Sun的网站(java.sun.com/products/javabeans).
这个包中一个非常重要的概念就是BeanWrapper 接口以及它的实现(BeanWrapperImpl)。 根据JavaDoc中的说明,BeanWrapper提供了设置和获得属性值的功能(单个的或者是批量的), 可以获得属性描述、查询只读或者可写属性。而且,BeanWrapper还支持嵌套属性, 可以不限制嵌套深度的进行子属性的设置。所以,BeanWrapper支持标准JavaBeans的PropertyChangeListeners 和VetoableChangeListeners。除此之外,BeanWrapper还提供了设置索引属性的支持。 一般情况下不在应用程序中直接使用BeanWrapper而是使用DataBinder和BeanFactory。 从BeanWrapper的名字就可以看出:它封装了一个bean的行为,比如设置和取出属性值。
The way the BeanWrapper works is partly indicated by its name: it wraps a bean to perform actions on that bean, like setting and retrieving properties.
4.3.1. 设置和提取属性以及嵌套属性
设置和提取属性可以通过使用重载的setPropertyValue(s)和getPropertyValue(s) 方法来完成。 在Srping的JavaDoc中对它们有详细的描述。有关这两个方法的一些约定习惯如下所列:
表 4.1. 属性示例
语法解释name
指出与 getName() 或 isName() 和 setName()相关的name信息
account.name
提供嵌套属性的name,比如 getAccount().setName() 或getAccount().getName()方法
account[2]
Indicates the third element of the indexed property account. Indexed properties can be of type array, list or other naturally ordered collection
在下面的例子中你将看到一些使用BeanWrapper设置属性的例子。
注意:如果你不打算直接使用BeanWrapper这部分不是很重要。 如果你仅仅使用DataBinder 和BeanFactory或者他们的扩展实现, 你可以跳过这部分直接阅读PropertyEditors的部分。
考虑下面的两个类:
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 float salary;
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
}
下面的代码显示了如何接收和设置上面两个类的属性 : Companies and Employees
Company c = new Company();
BeanWrapper bwComp = BeanWrapperImpl(c);
// setting the company name...
bwComp.setPropertyValue("name", "Some Company Inc.");
// ... can also be done like this:
PropertyValue v = new PropertyValue("name", "Some Company Inc.");
bwComp.setPropertyValue(v);
// ok, let's create the director and tie it to the company:
Employee jim = new Employee();
BeanWrapper bwJim = BeanWrapperImpl(jim);
bwJim.setPropertyValue("name", "Jim Stravinsky");
bwComp.setPropertyValue("managingDirector", jim);
// retrieving the salary of the managingDirector through the company
Float salary = (Float)bwComp.getPropertyValue("managingDirector.salary");
4.3.2. 内建的(PropertyEditors)和类型转换
Spring大量的使用了PropertyEditors。有时候它比对象自身描述属性更加容易。 比如,当我们转换一个日期类型(date)时,可以把它描述成一个用户更容易理解的样子。 这一过程可以通过注册一个自定义编辑器来实现。 java.beans.PropertyEditor.注册一个自定义编辑器告诉BeanWrapper我们将要把属性转换为哪种类型。 你可以从Sun的JavaDoc中 java.beans包了解有关java.beans.PropertyEditor的细节。
下面是几个在Spring中设置属性的例子
使用PropertyEditors设置Bean属性。 当你使用在XML文件中声明的java.lang.String作为bean的属性时, Spring将使用ClassEditor来尝试获得类对象的参数
在Spring MVC架构中传输HTTP请求参数,将使用各种PropertyEditors, 因此你可以绑定各种CommandController的子类。 Spring提供了很多内建的属性编辑器来让这些操作变得简单。 所有这些都列在下面的表格中,你也可以从org.springframework.beans.propertyeditors包中找到它们:
Spring has a number of built-in PropertyEditors to make life easy. Each of those is listed below and they are all located in the org.springframework.beans.propertyeditors package:
表 4.2. Built-in PropertyEditors
ClassExplanationClassEditor
Parses Strings representing classes to actual classes and the other way around. When a class is not found, an IllegalArgumentException is thrown
FileEditor
Capable of resolving Strings to File-objects
LocaleEditor
Capable of resolving Strings to Locale-objects and vice versa (the String format is [language]_[country]_[variant], which is the same thing the toString() method of Locale provides
PropertiesEditor
Capable of converting Strings (formatted using the format as defined in the Javadoc for the java.lang.Properties class) to Properties-objects
StringArrayPropertyEditor
Capable of resolving a comma-delimited list of String to a String-array and vice versa
URLEditor
Capable of resolving a String representation of a URL to an actual URL-object
Spring使用java.beans.PropertyEditorManager来为属性编辑器设置搜索路径, 这一点时必须的。搜索路径同时包括了sun.bean.editors,这个类包含了前面提到的PropertyEditors ,颜色以及所有原始类型。
4.3.3. 其他特性
除了前面提到的特性,下面还有一些有价值的特性。
? 确定可读能力和可写能力:使用isReadable() 和 isWritable()方法你可以确定一个属性是否为可读或者可写。
? 获得属性描述(PropertyDescriptors):使用getPropertyDescriptor(String) 和 getPropertyDescriptors()方法可以获得属性的描述(java.beans.PropertyDescriptor),有时候这会派上用场。