天天看點

【Spring】Spring Framework Reference Documentation中文版8

9. Validation, Data Binding, and Type Conversion

驗證、資料綁定和類型轉換

9.1 Introduction

介紹

JSR-303/JSR-349 Bean Validation

JSR-303/JSR-349的bean驗證

Spring Framework 4.0 supports Bean Validation 1.0 (JSR-303) and Bean Validation 1.1 (JSR-349) in terms of setup support, also adapting it to Spring’s Validator interface.

spring架構4支援bean驗證1.0(JSR303)和bean驗證1.1(JSR349),同時适用于spring的驗證接口。

An application can choose to enable Bean Validation once globally, as described in Section 9.8, “Spring Validation”, and use it exclusively for all validation needs.

應用可以選擇是否開啟全局的bean驗證,在9.8節中描述的“spring驗證”,将其用于所有驗證的需要。

An application can also register additional Spring Validator instances per DataBinder instance, as described in Section 9.8.3, “Configuring a DataBinder”. This may be useful for plugging in validation logic without the use of annotations.

一個應用可以注冊額外的spring驗證執行個體對于每個資料綁定執行個體,在9.8.3節中描述的“配置一個資料綁定”。這對不使用注解而實作驗證邏輯的插件化處理很有用。

There are pros and cons for considering validation as business logic, and Spring offers a design for validation (and data binding) that does not exclude either one of them. Specifically validation should not be tied to the web tier, should be easy to localize and it should be possible to plug in any validator available. Considering the above, Spring has come up with a Validator interface that is both basic and eminently usable in every layer of an application.

将驗證作為業務邏輯,spring提供一個設計用于驗證(和資料綁定)包括全部。明确的驗證不應該和web層綁定,應該易于局部化并且可以在需要驗證時以插件的方式使用。考慮到上面的幾點,spring提供了一個驗證器接口可以用于一個應用的每一層。

Data binding is useful for allowing user input to be dynamically bound to the domain model of an application (or whatever objects you use to process user input). Spring provides the so-called DataBinder to do exactly that. The Validator and the DataBinder make up the validation package, which is primarily used in but not limited to the MVC framework.

資料綁定是有用的允許讀者動态輸入綁定應用的對象模型(或你需要處理使用者輸入的object)。spring提供了這樣的DataBinder用于處理這些。驗證器和資料綁定器組成了驗證的包,主要用于但是不限制于MVC的架構中。

The BeanWrapper is a fundamental concept in the Spring Framework and is used in a lot of places. However, you probably will not have the need to use the BeanWrapper directly. Because this is reference documentation however, we felt that some explanation might be in order. We will explain the BeanWrapper in this chapter since, if you were going to use it at all, you would most likely do so when trying to bind data to objects.

BeanWrapper是spring架構的基本内容用在很多的位置。然而,你不需要直接使用BeanWrapper。因為這是一個參考文檔,然而我們會提供一些解釋。我們将會這一節解釋BeanWrapper,如果你決定使用它,當你試圖将資料綁定到object時會用到。

Spring’s DataBinder and the lower-level BeanWrapper both use PropertyEditors to parse and format property values. The PropertyEditor concept is part of the JavaBeans specification, and is also explained in this chapter. Spring 3 introduces a "core.convert" package that provides a general type conversion facility, as well as a higher-level "format" package for formatting UI field values. These new packages may be used as simpler alternatives to PropertyEditors, and will also be discussed in this chapter.

spring的DataBingder和低級的BeanWrapper都使用了PropertyEditors來解析和格式化屬性值。PropertyEditor是JavaBean定義的一部分,并且在這節中得到解釋。spring3介紹了一個core.conver包用于提供通用的類型轉換方法,在formate包中由于格式化UI屬性值。這些新的包将可以簡單的使用PropertyEditors來替代,并且将會這節中講解。

9.2 Validation using Spring’s Validator interface

使用spring的驗證接口進行驗證

Spring features a Validator interface that you can use to validate objects. The Validator interface works using an Errors object so that while validating, validators can report validation failures to the Errors object.

你可以使用spring的驗證器接口的來驗證object。驗證器接口使用一個Errors的object來工作用于完成驗證,驗證器可以對驗證失敗的object提供驗證報告。

Let’s consider a small data object:

讓我們考慮一個小的object

public class Person {

    private String name;

    private int age;

    // the usual getters and setters...

// 通常的get和set方法

}

We’re going to provide validation behavior for the Person class by implementing the following two methods of the org.springframework.validation.Validator interface:

我們通過實作org.springframework.validation.Validator接口中的兩個方法用于對Person類添加驗證行為。

    supports(Class) - Can this Validator validate instances of the supplied Class?

驗證器驗證的執行個體是否是提供的類的執行個體?

    validate(Object, org.springframework.validation.Errors) - validates the given object and in case of validation errors, registers those with the given Errors object

驗證給定的object是否是由于驗證的error,注冊在給定的Errors的object上

Implementing a Validator is fairly straightforward, especially when you know of the ValidationUtils helper class that the Spring Framework also provides.

直接實作Valiator接口,尤其是當你知道spring架構提供了一個ValidationUtils的工具類時。

public class PersonValidator implements Validator {

    public boolean supports(Class clazz) {

        return Person.class.equals(clazz);

    }

    public void validate(Object obj, Errors e) {

        ValidationUtils.rejectIfEmpty(e, "name", "name.empty");

        Person p = (Person) obj;

        if (p.getAge() < 0) {

            e.rejectValue("age", "negativevalue");

        } else if (p.getAge() > 110) {

            e.rejectValue("age", "too.darn.old");

        }

    }

}

As you can see, the static rejectIfEmpty(..) method on the ValidationUtils class is used to reject the 'name' property if it is null or the empty string. Have a look at the ValidationUtils javadocs to see what functionality it provides besides the example shown previously.

你看到了,ValidationUtils中的靜态rejectIfEmpty方法用于拒絕當如果name屬性是null或者是一個空字元串。可以檢視ValidationUtils的javadocs來檢視之前的例子是如何工作的。

While it is certainly possible to implement a single Validator class to validate each of the nested objects in a rich object, it may be better to encapsulate the validation logic for each nested class of object in its own Validator implementation. A simple example of a 'rich' object would be a Customer that is composed of two String properties (a first and second name) and a complex Address object. Address objects may be used independently of Customer objects, and so a distinct AddressValidator has been implemented. If you want your CustomerValidator to reuse the logic contained within the AddressValidator class without resorting to copy-and-paste, you can dependency-inject or instantiate an AddressValidator within your CustomerValidator, and use it like so:

可以單獨實作一個簡單的Validator類用于驗證每個富object中的内置object,最好将對于内置object的驗證邏輯壓縮到一個自有的Validator實作中。一個富object的簡單例子可以是由兩個字元串屬性組成的Customer(一個姓,一個名)和一個複雜的Address的object。Address的object可以獨立于Customer的object,是以可以實作一個AddressValidator。如果你需要你的CustomerValidator來服用邏輯包括在AddressValidator不需要複制和粘貼,你可以獨立注入或在CustomerValidator中使用AddressValidator,你可以使用如下:

public class CustomerValidator implements Validator {

    private final Validator addressValidator;

    public CustomerValidator(Validator addressValidator) {

        if (addressValidator == null) {

            throw new IllegalArgumentException("The supplied [Validator] is " +

                "required and must not be null.");

        }

        if (!addressValidator.supports(Address.class)) {

            throw new IllegalArgumentException("The supplied [Validator] must " +

                "support the validation of [Address] instances.");

        }

        this.addressValidator = addressValidator;

    }

    public boolean supports(Class clazz) {

        return Customer.class.isAssignableFrom(clazz);

    }

    public void validate(Object target, Errors errors) {

        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");

        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");

        Customer customer = (Customer) target;

        try {

            errors.pushNestedPath("address");

            ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);

        } finally {

            errors.popNestedPath();

        }

    }

}

Validation errors are reported to the Errors object passed to the validator. In case of Spring Web MVC you can use <spring:bind/> tag to inspect the error messages, but of course you can also inspect the errors object yourself. More information about the methods it offers can be found in the javadocs.

Validation錯誤用于報告封裝于驗證器中的錯誤object。在spring的mvc中你可以使用<spring:bing/>标簽來檢查錯誤資訊,但是你也可以自行注入錯誤object。更多有關方法的資訊見給定的javadocs。

9.3 Resolving codes to error messages

拆解錯誤資訊和代碼的對應

We’ve talked about databinding and validation. Outputting messages corresponding to validation errors is the last thing we need to discuss. In the example we’ve shown above, we rejected the name and the age field. If we’re going to output the error messages by using a MessageSource, we will do so using the error code we’ve given when rejecting the field ('name' and 'age' in this case). When you call (either directly, or indirectly, using for example the ValidationUtils class) rejectValue or one of the other reject methods from the Errors interface, the underlying implementation will not only register the code you’ve passed in, but also a number of additional error codes. What error codes it registers is determined by the MessageCodesResolver that is used. By default, the DefaultMessageCodesResolver is used, which for example not only registers a message with the code you gave, but also messages that include the field name you passed to the reject method. So in case you reject a field using rejectValue("age", "too.darn.old"), apart from the too.darn.old code, Spring will also register too.darn.old.age and too.darn.old.age.int (so the first will include the field name and the second will include the type of the field); this is done as a convenience to aid developers in targeting error messages and suchlike.

我們讨論一下資料綁定和驗證。輸出的資訊和相關的驗證錯誤是我們最後需要讨論的問題。在上面的例子,我們拒絕了name和age屬性。如果我們通過使用MessageSource來輸出錯誤資訊,我們可以使用錯誤碼當我們在決絕屬性時(上面例子中的name和age)。當你調用(無論是直接或間接的使用ValidationUtils類)rejectValue或其他reject方法從Error接口中,其中不隻會傳遞你提供的代碼,也包括一些其他的錯誤代碼。這些被注冊的錯誤代碼由使用的MessageCodesResolver來決定。預設的,會使用DefaultMessageCodesResolver,不隻會注冊一個你給定的錯誤資訊,也包括你傳遞給reject方法的屬性名。是以你可以通過使用rejectValue("age", "too.darn.old")來決絕一個field而區分與too.darn.old代碼,spring 将會注冊too.darn.old.age和too.darn.old.age.int(是以首先包括field名,另一個會包括field的類型),這樣會友善開發者用于定位錯誤資訊。

More information on the MessageCodesResolver and the default strategy can be found online in the javadocs of MessageCodesResolver and DefaultMessageCodesResolver, respectively.

MessageCodesResolver的更多資訊和預設政策可以分别檢視MessageCodesResolver和DefaultMessageCodesResolver的javadocs。

9.4 Bean manipulation and the BeanWrapper

bean操作和BeanWrapper

The org.springframework.beans package adheres to the JavaBeans standard provided by Oracle. A JavaBean is simply a class with a default no-argument constructor, which follows a naming convention where (by way of an example) a property named bingoMadness would have a setter method setBingoMadness(..) and a getter method getBingoMadness(). For more information about JavaBeans and the specification, please refer to Oracle’s website ( javabeans).

org.springframework.beans包和oracle提供的javabean标準綁定。一個javabean就是一個簡單的類,有一個預設的無參構造器,按照一定的參數命名規範,如有個屬性名字為bingoMadness,則有set方法setBingoMadness和get方法getBingoMadness。更多有關javabean和定義的資訊請參考oracle的官網。

One quite important class in the beans package is the BeanWrapper interface and its corresponding implementation ( BeanWrapperImpl). As quoted from the javadocs, the BeanWrapper offers functionality to set and get property values (individually or in bulk), get property descriptors, and to query properties to determine if they are readable or writable. Also, the BeanWrapper offers support for nested properties, enabling the setting of properties on sub-properties to an unlimited depth. Then, the BeanWrapper supports the ability to add standard JavaBeans PropertyChangeListeners and VetoableChangeListeners, without the need for supporting code in the target class. Last but not least, the BeanWrapper provides support for the setting of indexed properties. The BeanWrapper usually isn’t used by application code directly, but by the DataBinder and the BeanFactory.

在bean包中很重要的類是BeanWrapper接口和他的相關實作(BeanWrapperImpl)。引用在javadocs,BeanWrapper提供了設定和擷取屬性值的功能(單個或批量)、獲得屬性描述、查詢屬性來确定是否是可讀或可寫的。BeanWrapper也提供支援對内置的屬性、允許無限制深度的設定屬性的子屬性。BeanWrapper支援添加JavaBeans PropertyChangeListeners和VetoableChangeListeners,不需要目标類的代碼支援。BeanWrapper支援索引屬性的設定。BeanWrapper通常不會再應用代碼中直接使用,但是會在DataBinder和BeanFactory中使用。

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.

BeanWrapper工作方式和名字暗示的一部分:他處理bean的行為,類似于設定和獲得屬性。

9.4.1 Setting and getting basic and nested properties

設定或獲得基本和内置屬性

Setting and getting properties is done using the setPropertyValue(s) and getPropertyValue(s) methods that both come with a couple of overloaded variants. They’re all described in more detail in the javadocs Spring comes with. What’s important to know is that there are a couple of conventions for indicating properties of an object. A couple of examples:

設定和獲得屬性由setPropertyValue和getPropertyValue方法來實作,有幾個重載的方法。較長的描述在javadocs中。重要的知道有一些方法用于聲明object的屬性。例子:

Table 9.1. Examples of properties

屬性的例子

Expression

表達式

Explanation

解釋

name

Indicates the property name corresponding to the methods getName() or isName() and setName(..)

聲明屬性name相關的方法是getName()或isName()或setName()

account.name

Indicates the nested property name of the property account corresponding e.g. to the methods getAccount().setName() or getAccount().getName()

聲明account屬性的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

聲明是account的第三個元素。屬性是數組類型、清單或其他有序的collection

account[COMPANYNAME]

Indicates the value of the map entry indexed by the key COMPANYNAME of the Map property account

聲明map類型的account屬性中key為COMPANYNAME的值

Below you’ll find some examples of working with the BeanWrapper to get and set properties.

下面你會發現一些使用BeanWrapper來獲得或設定屬性的例子

(This next section is not vitally important to you if you’re not planning to work with the BeanWrapper directly. If you’re just using the DataBinder and the BeanFactory and their out-of-the-box implementation, you should skip ahead to the section about PropertyEditors.)

(下面的内容不是很重要如果在你并不想直接使用BeanWrapper的情況下。如果你隻是使用DataBinder和BeanFactory和他們的實作,你可以跳過有關PropertyEditors的内容)

Consider the following two classes:

考慮下面兩個類:

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;

    }

}

The following code snippets show some examples of how to retrieve and manipulate some of the properties of instantiated Companies and Employees:

下面的代碼片段展示了一些例子是如果操縱Company和Employee執行個體的屬性值。

BeanWrapper company = new BeanWrapperImpl(new Company());

// setting the company name..

// 設定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:

// 好,我們建立director并和company綁定

BeanWrapper jim = new BeanWrapperImpl(new Employee());

jim.setPropertyValue("name", "Jim Stravinsky");

company.setPropertyValue("managingDirector", jim.getWrappedInstance());

// retrieving the salary of the managingDirector through the company

// 通過company獲得managingDirector的salary

Float salary = (Float) company.getPropertyValue("managingDirector.salary");

9.4.2 Built-in PropertyEditor implementations

内置的PropertyEditor實作

Spring uses the concept of PropertyEditors to effect the conversion between an Object and a String. If you think about it, it sometimes might be handy to be able to represent properties in a different way than the object itself. For example, a Date can be represented in a human readable way (as the String '2007-14-09'), while we’re still able to convert the human readable form back to the original date (or even better: convert any date entered in a human readable form, back to Date objects). This behavior can be achieved by registering custom editors, of type java.beans.PropertyEditor. Registering custom editors on a BeanWrapper or alternately in a specific IoC container as mentioned in the previous chapter, gives it the knowledge of how to convert properties to the desired type. Read more about PropertyEditors in the javadocs of the java.beans package provided by Oracle.

spring使用PropertyEditors來影響object和字元串的轉換。如果你這樣考慮,有時會比較簡單以不同的方式代表屬性而不是object本身。例如,一個日期可以以易于讀的方式來展示(例如字元串'2007-14-09'),當我們試圖從原始日期類型轉換為易于讀取的形式(或者将任意日期轉化為易于閱讀的形式)。這種行為可以通過注冊自定義的編輯器,類型是java.beans.PropertyEditor來實作。注冊自定義編輯器在BeanWrapper上火替代之前章節中提到的特定的IOC容器,用于實作屬性和目标類型的轉換。詳見PropertyEditors的javadocs。

A couple of examples where property editing is used in Spring:

spring中的一些例子中使用了屬性編輯

    setting properties on beans is done using PropertyEditors. When mentioning java.lang.String as the value of a property of some bean you’re declaring in XML file, Spring will (if the setter of the corresponding property has a Class-parameter) use the ClassEditor to try to resolve the parameter to a Class object.

使用PropertyEditors來設定bean的屬性。如果你在xml檔案中指定某個bean的屬性是java.lang.String類型,spring會(如果相應屬性的set方法有一個Class-parameter)使用ClassEditor來試圖處理一個Class object的參數。

    parsing HTTP request parameters in Spring’s MVC framework is done using all kinds of PropertyEditors that you can manually bind in all subclasses of the CommandController.

解析spring的mvc架構中的http請求參數是通過使用各種的PropertyEditors來實作的,你可以手動綁定所有CommandController的子類。

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. Most, but not all (as indicated below), are registered by default by BeanWrapperImpl. Where the property editor is configurable in some fashion, you can of course still register your own variant to override the default one:

spring有一些内置的PropertyEditors來簡化處理。每個PropertyEditors都列在下面的表中都在org.springframework.beans.propertyeditors包中。大部分不是全部(下面提到的)都是通過BeanWrapperImpl預設被注冊的。當屬性編輯器被設定後,你依然可以注冊自定義的編輯器來覆寫預設值:

Table 9.2. Built-in PropertyEditors

内置的PropertyEditors

Class

Explanation

解釋

ByteArrayPropertyEditor

Editor for byte arrays. Strings will simply be converted to their corresponding byte representations. Registered by default by BeanWrapperImpl.

byte數組的編輯器。字元串會轉化為相應的位元組。預設由BeanWrapperImpl注冊

ClassEditor

Parses Strings representing classes to actual classes and the other way around. When a class is not found, an IllegalArgumentException is thrown. Registered by default by BeanWrapperImpl.

解析字元串指向實際的類和其他。如果類沒有被找到會抛出IllegalArgumentException異常。預設由BeanWrapperImpl注冊

CustomBooleanEditor

Customizable property editor for Boolean properties. Registered by default by BeanWrapperImpl, but, can be overridden by registering custom instance of it as custom editor.

可定制的屬性編輯器用于boolean屬性。預設由BeanWrapperImpl注冊但是可以通過自定義編輯器來覆寫。

CustomCollectionEditor

Property editor for Collections, converting any source Collection to a given target Collection type.

用于Collections的屬性編輯器,将任何元結合轉化為給定的集合類型

CustomDateEditor

Customizable property editor for java.util.Date, supporting a custom DateFormat. NOT registered by default. Must be user registered as needed with appropriate format.

可定制屬性編輯器用于java.util.Data,支援自定義日期格式。預設沒有被注冊。必須根據需要使用适當的格式來手動注冊

CustomNumberEditor

Customizable property editor for any Number subclass like Integer, Long, Float, Double. Registered by default by BeanWrapperImpl, but can be overridden by registering custom instance of it as a custom editor.

可定制屬性編輯器用于Number的子類例如Integer、Long、Float、Double。預設由BeanWrapperImpe注冊但是可以被自定義的屬性編輯器覆寫

FileEditor

Capable of resolving Strings to java.io.File objects. Registered by default by BeanWrapperImpl.

處理java.io.File的object的字元串。預設由BeanWrapperImplementation注冊

InputStreamEditor

One-way property editor, capable of taking a text string and producing (via an intermediate ResourceEditor and Resource) an InputStream, so InputStream properties may be directly set as Strings. Note that the default usage will not close the InputStream for you! Registered by default by BeanWrapperImpl.

單向屬性編輯器,可以獲得文本字元串和産生輸入流(通過ResourceEditor和Resource作為輔助),是以輸入流可以直接設定為字元串。注意預設使用中将不會替你關閉輸入流。預設由BeanWrapperImpl注冊

LocaleEditor

Capable of resolving Strings to Locale objects and vice versa (the String format is [country][variant], which is the same thing the toString() method of Locale provides). Registered by default by BeanWrapperImpl.

處理本地object的字元串,反之亦然(字元串類型是[country][variant]和本地提供的toString方法一樣)。預設由BeanWrapperImpl注冊

PatternEditor

Capable of resolving Strings to java.util.regex.Pattern objects and vice versa.

将字元串轉化為java.util.regex.Pattern,反之亦然

PropertiesEditor

Capable of converting Strings (formatted using the format as defined in the javadocs of the java.util.Properties class) to Properties objects. Registered by default by BeanWrapperImpl.

可以将字元串轉化為Properties,(使用定義在java.util.Properties中javadocs說明的格式進行格式化)。預設由BeanWrapperImpl注冊

StringTrimmerEditor

Property editor that trims Strings. Optionally allows transforming an empty string into a null value. NOT registered by default; must be user registered as needed.

屬性編輯器可選對字元串去空格并允許轉化空字元串和null值。預設沒有被注冊。根據需要手動注冊

URLEditor

Capable of resolving a String representation of a URL to an actual URL object. Registered by default by BeanWrapperImpl.

用于處理字元串來代表URL或實際的URL的object。預設由BeanWrapperImpl注冊。

Spring uses the java.beans.PropertyEditorManager to set the search path for property editors that might be needed. The search path also includes sun.bean.editors, which includes PropertyEditor implementations for types such as Font, Color, and most of the primitive types. Note also that the standard JavaBeans infrastructure will automatically discover PropertyEditor classes (without you having to register them explicitly) if they are in the same package as the class they handle, and have the same name as that class, with 'Editor' appended; for example, one could have the following class and package structure, which would be sufficient for the FooEditor class to be recognized and used as the PropertyEditor for Foo-typed properties.

spring使用java.beans.PropertyEditorManger來設定搜尋路徑用于屬性編輯器根據需要。搜尋路徑也包括sun.bean.editors,包括PropertyEditor的實作為了其他類型,如Font、Color和大部分原始類型。注意編著的JavaBean架構可以自動發現PropertyEditor類(不需要你來手動注冊)如果在相同的包中作為類來處理,或有相同的類名,然後以Editor結尾,例如,可以有如下的類和包結構将足夠對于FooEditor類來識别用于Foo類型屬性的屬性編輯。

com

  chank

    pop

      Foo

      FooEditor // the PropertyEditor for the Foo class

Note that you can also use the standard BeanInfo JavaBeans mechanism here as well (described in not-amazing-detail here). Find below an example of using the BeanInfo mechanism for explicitly registering one or more PropertyEditor instances with the properties of an associated class.

注意你也可以使用标準的BeanInfo JavaBean的政策(。。。)。見下面這個使用BeanInfo政策的例子用于注冊一個或多個屬性編輯器執行個體相對于相關類。

com

  chank

    pop

      Foo

      FooBeanInfo // the BeanInfo for the Foo class

Here is the Java source code for the referenced FooBeanInfo class. This would associate a CustomNumberEditor with the age property of the Foo class.

這是java源代碼參考FooBeanInfo類。下面的例子會将CustomNumberEditor和Foo類的age屬性聯系在一起。

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());

        }

    }

}

Registering additional custom PropertyEditors

注冊額外的自定義屬性編輯器

When setting bean properties as a string value, a Spring IoC container ultimately uses standard JavaBeans PropertyEditors to convert these Strings to the complex type of the property. Spring pre-registers a number of custom PropertyEditors (for example, to convert a classname expressed as a string into a real Class object). Additionally, Java’s standard JavaBeans PropertyEditor lookup mechanism allows a PropertyEditor for a class simply to be named appropriately and placed in the same package as the class it provides support for, to be found automatically.

當設定一個bean的屬性為字元串時,spring的ioc容器會使用基本的JavaBean屬性編輯器來将字元串轉化為複雜的屬性類型。spring會事先注冊一些自定義的屬性編輯器(例如,将一個類名表達為一個字元串設定到實際的class的object中)。此外,java的标磚JavaBeans屬性編輯器的查詢政策允許一個類的屬性編輯器簡單被命名并并在同一個包中定義,以便可以自動被發現。

If there is a need to register other custom PropertyEditors, there are several mechanisms available. The most manual approach, which is not normally convenient or recommended, is to simply use the registerCustomEditor() method of the ConfigurableBeanFactory interface, assuming you have a BeanFactory reference. Another, slightly more convenient, mechanism is to use a special bean factory post-processor called CustomEditorConfigurer. Although bean factory post-processors can be used with BeanFactory implementations, the CustomEditorConfigurer has a nested property setup, so it is strongly recommended that it is used with the ApplicationContext, where it may be deployed in similar fashion to any other bean, and automatically detected and applied.

如果需要注冊其他的自定義屬性編輯器則有一些政策可用。其中最手動的方法不是很友善也不被推薦使用,就是簡單的使用ConfigurableBeanFactory接口的registerCustomEditor方法,假設你有一個BeanFactory的引用。另外,稍微有些友善的政策是使用特定bean工廠後處理器名為CustomEditorConfigurer。盡管bean工廠後處理器可以用于BeanFactory的實作,CustomEditorConfigurer有一個内置屬性的設定,是以強烈推薦可以使用在ApplicationContext中,可以和其他bean一樣以相似的方式部署并可以自動被探測和應用。

Note that all bean factories and application contexts automatically use a number of built-in property editors, through their use of something called a BeanWrapper to handle property conversions. The standard property editors that the BeanWrapper registers are listed in the previous section. Additionally, ApplicationContexts also override or add an additional number of editors to handle resource lookups in a manner appropriate to the specific application context type.

注意所有的bean工廠和應用上下文自動使用一定數量的内置屬性編輯器,盡管他們使用的一些叫BeanWrapper用于處理屬性轉換。BeanWrapper注冊的标準的屬性編輯器在前一節中已經列出。此外應用上下文也可以覆寫和添加額外的編輯器用于處理資源的查找在管理以适應特定的應用上下文類型。

Standard JavaBeans PropertyEditor instances are used to convert property values expressed as strings to the actual complex type of the property. CustomEditorConfigurer, a bean factory post-processor, may be used to conveniently add support for additional PropertyEditor instances to an ApplicationContext.

标準的JavaBeans屬性編輯器執行個體可以用于将屬性值表達為字元串用于實際複雜的屬性類型中。bean的工廠後處理器,CustomEditorConfigurer可以友善用于支援應用上下文中的屬性編輯器執行個體。

Consider a user class ExoticType, and another class DependsOnExoticType which needs ExoticType set as a property:

考慮一個使用者類ExoticType和另一個類DependsOnExoticType需要ExoticType作為屬性:

package example;

public class ExoticType {

    private String name;

    public ExoticType(String name) {

        this.name = name;

    }

}

public class DependsOnExoticType {

    private ExoticType type;

    public void setType(ExoticType type) {

        this.type = type;

    }

}

When things are properly set up, we want to be able to assign the type property as a string, which a PropertyEditor will behind the scenes convert into an actual ExoticType instance:

當被正确的設定好,我們希望指定屬性的類型是字元串,PropertyEditor在後面會将其轉化為ExoticType執行個體。

<bean id="sample" class="example.DependsOnExoticType">

    <property name="type" value="aNameForExoticType"/>

</bean>

The PropertyEditor implementation could look similar to this:

PropertyEditor實作看上去是這樣的:

// converts string representation to ExoticType object

// 轉化字元串為ExoticType的object

package example;

public class ExoticTypeEditor extends PropertyEditorSupport {

    public void setAsText(String text) {

        setValue(new ExoticType(text.toUpperCase()));

    }

}

Finally, we use CustomEditorConfigurer to register the new PropertyEditor with the ApplicationContext, which will then be able to use it as needed:

最後,我們使用應用上下文的CustomEditorConfigurer來注冊新的屬性編輯器,可以根據需要來使用:

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">

    <property name="customEditors">

        <map>

            <entry key="example.ExoticType" value="example.ExoticTypeEditor"/>

        </map>

    </property>

</bean>

Using PropertyEditorRegistrars

使用PropertyEditorRegistrars

Another mechanism for registering property editors with the Spring container is to create and use a PropertyEditorRegistrar. This interface is particularly useful when you need to use the same set of property editors in several different situations: write a corresponding registrar and reuse that in each case. PropertyEditorRegistrars work in conjunction with an interface called PropertyEditorRegistry, an interface that is implemented by the Spring BeanWrapper (and DataBinder). PropertyEditorRegistrars are particularly convenient when used in conjunction with the CustomEditorConfigurer (introduced here), which exposes a property called setPropertyEditorRegistrars(..): PropertyEditorRegistrars added to a CustomEditorConfigurer in this fashion can easily be shared with DataBinder and Spring MVC Controllers. Furthermore, it avoids the need for synchronization on custom editors: a PropertyEditorRegistrar is expected to create fresh PropertyEditor instances for each bean creation attempt.

spirng容器中其他注冊屬性編輯器的政策是建立和使用PropertyEditorRegistrar。當你需要在不同的環境中使用相同的一些屬性編輯器時還是很有用的接口:建立一個相關的注冊者然後在每個類中重複使用。PropertyEditorRegistrars和PropertyEditorRegistry接口同時使用,一個接口的實作是spring的BeanWrapper(和DataBinder)。PropertyEditorRegistrars當和CustomEditorConfigurer一起使用時是很友善的(在這裡介紹),暴露了一個屬性名為setPropertyEditorRegistrars:PropertyEditorRegistrars和CustomEditorConfigurer結合使用可以簡單的在DataBinder和spring的MVC控制之間共享。進一步說,他避免了自定義編輯器對于同步的使用:PropertyEditorRegistrar試圖對每個bean建立PropertyEditor的執行個體。

Using a PropertyEditorRegistrar is perhaps best illustrated with an example. First off, you need to create your own PropertyEditorRegistrar implementation:

使用PropertyEditorRegistrar或許是最好的方法在這個例子中。首先,你需要建立你自己的PropertyEditorRegistrar實作:

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

// 建立一個新的PropertyEditor執行個體

        registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());

        // you could register as many custom property editors as are required here...

// 你可以注冊許多自定義屬性編輯器根據要求

    }

}

See also the org.springframework.beans.support.ResourceEditorRegistrar for an example PropertyEditorRegistrar implementation. Notice how in its implementation of the registerCustomEditors(..) method it creates new instances of each property editor.

也可參考org.springframework.beans.support.ResourceEditorRegistrar作為一個PropertyEditorRegistrar實作的例子。注意實作中的registerCustomEditors方法建立每個屬性編輯器的新執行個體。

Next we configure a CustomEditorConfigurer and inject an instance of our CustomPropertyEditorRegistrar into it:

下面我們配置一個CustomEditorConfigurer并且注入一個我們自己的CustomPropertyEditorRegistrar執行個體:

<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"/>

Finally, and in a bit of a departure from the focus of this chapter, for those of you using Spring’s MVC web framework, using PropertyEditorRegistrars in conjunction with data-binding Controllers (such as SimpleFormController) can be very convenient. Find below an example of using a PropertyEditorRegistrar in the implementation of an initBinder(..) method:

最後,暫時脫離一下本節,在你使用spring的mvc的web架構時,一起使用PropertyEditorRegistrars和資料綁定控制器會更加友善。下面的例子中使用PropertyEditorRegistrar并實作了initBinder方法:

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

// 其他方法用于注冊User

}

This style of PropertyEditor registration can lead to concise code (the implementation of initBinder(..) is just one line long!), and allows common PropertyEditor registration code to be encapsulated in a class and then shared amongst as many Controllers as needed.

這種使用PropertyEditor注冊的風格可以簡化代碼(initBinder的實作隻是一部分),允許通用的PropertyEditor注冊代碼在一個類中然後根據需要在許多控制器間共享。

9.5 Spring Type Conversion

spring的類型轉換

Spring 3 introduces a core.convert package that provides a general type conversion system. The system defines an SPI to implement type conversion logic, as well as an API to execute type conversions at runtime. Within a Spring container, this system can be used as an alternative to PropertyEditors to convert externalized bean property value strings to required property types. The public API may also be used anywhere in your application where type conversion is needed.

spirng3介紹了core.convert包用于提供通用類型的轉換系統。系統定義了SPI來實作類型轉換邏輯,和API在運作時執行類型轉換一樣。在spring的容器中,這個系統可以用于PropertyEditors來轉化屬性字元串到需要的屬性類型。公共API也可以在你應用中使用當需要類型轉換時。

9.5.1 Converter SPI

The SPI to implement type conversion logic is simple and strongly typed:

SPI用于類型轉換的邏輯時簡單的而且是強類型的:

package org.springframework.core.convert.converter;

public interface Converter<S, T> {

    T convert(S source);

}

To create your own converter, simply implement the interface above. Parameterize S as the type you are converting from, and T as the type you are converting to. Such a converter can also be applied transparently if a collection or array of S needs to be converted to an array or collection of T, provided that a delegating array/collection converter has been registered as well (which DefaultConversionService does by default).

建立你自己的轉化器需要實作上面的接口。參數S是你需要轉換的類型,并且T是轉換後的類型。這個轉化器也可以應用在集合或數組上用于從S轉換為T,提供了一個數組和集合轉化器也被注冊(預設是DefaultConversionService)。

For each call to convert(S), the source argument is guaranteed to be NOT null. Your Converter may throw any unchecked exception if conversion fails; specifically, an IllegalArgumentException should be thrown to report an invalid source value. Take care to ensure that your Converter implementation is thread-safe.

對于每次調用轉化,源參數不可以是null。如果轉換失敗該方法可以抛出任何非檢查異常:特殊的,一個IllegalArgumentException應該被抛出來反映一個錯誤的原資料值。保證你的轉換實作是線程安全的。

Several converter implementations are provided in the core.convert.support package as a convenience. These include converters from Strings to Numbers and other common types. Consider StringToInteger as an example for a typical Converter implementation:

一些轉換器的實作在core.convert.support包中被提供作為友善。包括将字元串轉化為數字和其他常用的類型轉換。考慮StringToInteger作為一個列子描述典型的轉換器實作:

package org.springframework.core.convert.support;

final class StringToInteger implements Converter<String, Integer> {

    public Integer convert(String source) {

        return Integer.valueOf(source);

    }

}

9.5.2 ConverterFactory

轉換工廠

When you need to centralize the conversion logic for an entire class hierarchy, for example, when converting from String to java.lang.Enum objects, implement ConverterFactory:

當你需要集中轉換邏輯用于這個類的層級,例如,當将字元串轉換為java.lang.Enum的object時,可以實作ConverterFactory。

package org.springframework.core.convert.converter;

public interface ConverterFactory<S, R> {

    <T extends R> Converter<S, T> getConverter(Class<T> targetType);

}

Parameterize S to be the type you are converting from and R to be the base type defining the range of classes you can convert to. Then implement getConverter(Class<T>), where T is a subclass of R.

參數S是你需要轉換的類型,R是你需要轉換的類型範圍。getConverter實作中T是R的一個子類。

Consider the StringToEnum ConverterFactory as an example:

考慮StringToEnum的ConverterFactory作為一個例子:

package org.springframework.core.convert.support;

final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {

    public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {

        return new StringToEnumConverter(targetType);

    }

    private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {

        private Class<T> enumType;

        public StringToEnumConverter(Class<T> enumType) {

            this.enumType = enumType;

        }

        public T convert(String source) {

            return (T) Enum.valueOf(this.enumType, source.trim());

        }

    }

}

9.5.3 GenericConverter

通用轉換器

When you require a sophisticated Converter implementation, consider the GenericConverter interface. With a more flexible but less strongly typed signature, a GenericConverter supports converting between multiple source and target types. In addition, a GenericConverter makes available source and target field context you can use when implementing your conversion logic. Such context allows a type conversion to be driven by a field annotation, or generic information declared on a field signature.

當你需要一個複雜的轉換器實作,考慮一下GenericConverter接口。更加友善但是沒有強類型辨別,支援多個源碼到目标類型的轉換。此外,GenericConverter使得當你實作你的轉換邏輯時使用源碼和目标域。這樣的上下文允許一個類型轉換通過域注解或定義在域中通用的資訊。

package org.springframework.core.convert.converter;

public interface GenericConverter {

    public Set<ConvertiblePair> getConvertibleTypes();

    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

}

To implement a GenericConverter, have getConvertibleTypes() return the supported source→target type pairs. Then implement convert(Object, TypeDescriptor, TypeDescriptor) to implement your conversion logic. The source TypeDescriptor provides access to the source field holding the value being converted. The target TypeDescriptor provides access to the target field where the converted value will be set.

實作GenericConverter,getConvertibleTypes需要傳回支援源類型到目标類型的對。然後實作convert方法來實作你的轉換邏輯。源TypeDescriptor提供通路被轉換的元域的值。目标TypeDescriptor提供通路轉換後的目标域的值,該值可以被設定。

A good example of a GenericConverter is a converter that converts between a Java Array and a Collection. Such an ArrayToCollectionConverter introspects the field that declares the target Collection type to resolve the Collection’s element type. This allows each element in the source array to be converted to the Collection element type before the Collection is set on the target field.

一個比較好的GenericConverter例子就是Java數組到集合的轉換。這樣的ArrayToCollectionConverter自省定義在目标集合類型的域用于處理集合元素類型。允許每個在源數組的元素被轉換為集合元素類型在結合被設定到目标域之前。

[Note]

注意

Because GenericConverter is a more complex SPI interface, only use it when you need it. Favor Converter or ConverterFactory for basic type conversion needs.

因為GenericConverter是一個比較複雜的SPI接口,當你需要的時候才會使用。傾向Converter或ConverterFactory用于基本類型轉換根據需要。

ConditionalGenericConverter

Sometimes you only want a Converter to execute if a specific condition holds true. For example, you might only want to execute a Converter if a specific annotation is present on the target field. Or you might only want to execute a Converter if a specific method, such as a static valueOf method, is defined on the target class. ConditionalGenericConverter is the union of the GenericConverter and ConditionalConverter interfaces that allows you to define such custom matching criteria:

有時你希望轉換器在特定條件下進行轉換。例如,你或許希望執行轉換如果一個特定注解在目标域上使用時。或許你隻是希望執行轉換如果一個特定的方法例如靜态的valueOf方法被定義在目标類中。ConditionalGenericConverter就是一個GenericConverter和ConditionalConverter的組合接口允許你定義自定義的比對邏輯條件:

public interface ConditionalGenericConverter

        extends GenericConverter, ConditionalConverter {

    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);

}

A good example of a ConditionalGenericConverter is an EntityConverter that converts between an persistent entity identifier and an entity reference. Such a EntityConverter might only match if the target entity type declares a static finder method e.g. findAccount(Long). You would perform such a finder method check in the implementation of matches(TypeDescriptor, TypeDescriptor).

ConditionalGenericConverter的一個好例子是EntityConverter用于轉換一個持久化實體定義為一個實體引用。例如EntityConverter可以隻比對目标實體類型定義一個靜态的finder方法例如findAccount(Long)。你或許可以使finder方法檢測定義在matches(TypeDescriptor, TypeDescriptor)的實作中。

9.5.4 ConversionService API

轉換服務接口

The ConversionService defines a unified API for executing type conversion logic at runtime. Converters are often executed behind this facade interface:

ConversionService定義了一個統一的API用于在運作時執行類型轉換邏輯。Converters經常執行在此接口的後面:

package org.springframework.core.convert;

public interface ConversionService {

    boolean canConvert(Class<?> sourceType, Class<?> targetType);

    <T> T convert(Object source, Class<T> targetType);

    boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);

    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

}

Most ConversionService implementations also implement ConverterRegistry, which provides an SPI for registering converters. Internally, a ConversionService implementation delegates to its registered converters to carry out type conversion logic.

大部分ConversionService實作也實作了ConverterRegistry,用于提供SPI來注冊轉換器。在其内部,ConversionService實作委托了注冊機制給他的注冊轉換器用于處理類型轉換邏輯。

A robust ConversionService implementation is provided in the core.convert.support package. GenericConversionService is the general-purpose implementation suitable for use in most environments. ConversionServiceFactory provides a convenient factory for creating common ConversionService configurations.

一個強健的ConversionService實作在core.convert.support包中被提供。GenericConversionService是一個通用的實作可以用于大部分的情況。ConversionServiceFactory提供了一個友善的工廠用于建立普通的ConversionService配置。

9.5.5 Configuring a ConversionService

配置一個ConversionService

A ConversionService is a stateless object designed to be instantiated at application startup, then shared between multiple threads. In a Spring application, you typically configure a ConversionService instance per Spring container (or ApplicationContext). That ConversionService will be picked up by Spring and then used whenever a type conversion needs to be performed by the framework. You may also inject this ConversionService into any of your beans and invoke it directly.

一個ConversionService是一個無狀态的object設計加載應用啟動時被執行個體化,在多個線程間被共享。

[Note]

注意

If no ConversionService is registered with Spring, the original PropertyEditor-based system is used.

如果spring沒有注冊ConversionService,則原始的基于屬性編輯器的系統将被使用。

To register a default ConversionService with Spring, add the following bean definition with id conversionService:

為了使用spring注冊預設的ConversionService,需要添加id為conversionService的如下bean定義

<bean id="conversionService"

    class="org.springframework.context.support.ConversionServiceFactoryBean"/>

A default ConversionService can convert between strings, numbers, enums, collections, maps, and other common types. To supplement or override the default converters with your own custom converter(s), set the converters property. Property values may implement either of the Converter, ConverterFactory, or GenericConverter interfaces.

一個預設的ConversionService可以在字元串、數組、枚舉、集合、map和其他通用類型間實作轉換。為了補充或覆寫預設的轉化器使用自定義的轉化器,需要設定converters屬性。屬性值是一個實作Converter或ConverterFactory或GenericConverter接口的某個類。

<bean id="conversionService"

        class="org.springframework.context.support.ConversionServiceFactoryBean">

    <property name="converters">

        <set>

            <bean class="example.MyCustomConverter"/>

        </set>

    </property>

</bean>

It is also common to use a ConversionService within a Spring MVC application. See Section 22.16.3, “Conversion and Formatting” in the Spring MVC chapter.

在spring的mvc應用中使用GenericConverter也很常見。見22.16.3節,“轉換和格式化”在spring的mvc章節。

In certain situations you may wish to apply formatting during conversion. See Section 9.6.3, “FormatterRegistry SPI” for details on using FormattingConversionServiceFactoryBean.

在特定的情況你或許希望在轉換中使用格式化。見9.6.3節,“FormatterRegistry SPI”中的詳細内容使用FormattingConversionServiceFactoryBean。

9.5.6 Using a ConversionService programmatically

程式設計使用ConversionService

To work with a ConversionService instance programmatically, simply inject a reference to it like you would for any other bean:

為了程式設計使用ConversionService執行個體,簡單在一個bean中注入一個引用如下:

@Service

public class MyService {

    @Autowired

    public MyService(ConversionService conversionService) {

        this.conversionService = conversionService;

    }

    public void doIt() {

        this.conversionService.convert(...)

    }

}

For most use cases, the convert method specifying the targetType can be used but it will not work with more complex types such as a collection of a parameterized element. If you want to convert a List of Integer to a List of String programmatically, for instance, you need to provide a formal definition of the source and target types.

在大部分使用方式中,轉換方法定義了目标類型可以被使用但是但是在一些參數化元素的集合類型這樣複雜的類型可能無法工作。如果你希望程式設計轉換一個Integer的List到一個字元串的List,例如,你需要提供一個格式定義對源類型和目标類型。

Fortunately, TypeDescriptor provides various options to make that straightforward:

幸運的是,TypeDescriptor提供了一些選項用于實作這樣的功能:

DefaultConversionService cs = new DefaultConversionService();

List<Integer> input = ....

cs.convert(input,

    TypeDescriptor.forObject(input), // List<Integer> type descriptor

    TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));

Note that DefaultConversionService registers converters automatically which are appropriate for most environments. This includes collection converters, scalar converters, and also basic Object to String converters. The same converters can be registered with any ConverterRegistry using the static addDefaultConverters method on the DefaultConversionService class.

注意DefaultConversionService自動注冊轉換器可以使用于大部分的情況。這裡包括集合轉換、标量轉換和基本object到字元串轉化。通過ConverterRegistry同樣的轉換可以被注冊使用DefaultConversionService類中的靜态的addDefaultConverters方法。

Converters for value types will be reused for arrays and collections, so there is no need to create a specific converter to convert from a Collection of S to a Collection of T, assuming that standard collection handling is appropriate.

用于值類型的轉換可以重用在數組和集合中,是以不需要建立特定的轉換器用于轉換一個集合S到另一個集合T,假設标準集合處理是合适的。

9.6 Spring Field Formatting

spring的域格式化

As discussed in the previous section, core.convert is a general-purpose type conversion system. It provides a unified ConversionService API as well as a strongly-typed Converter SPI for implementing conversion logic from one type to another. A Spring Container uses this system to bind bean property values. In addition, both the Spring Expression Language (SpEL) and DataBinder use this system to bind field values. For example, when SpEL needs to coerce a Short to a Long to complete an expression.setValue(Object bean, Object value) attempt, the core.convert system performs the coercion.

在前面的幾節中讨論,core.convert是一個通用的類型轉換系統。他提供特定的ConversionService的API和強健的類型轉換器實作用于實作一個類型到另一個類型的轉換。一個spring的容器使用這個系統來綁定bean的屬性值。此外,spring的表達式語言和DataBinder使用這個系統來綁定屬性值。例如,當SpEL需要迫使一個Short類型轉換為Long類型用于試圖完成expression.setValue(Object bean, Object value),那這個系統可以提供的功能。

Now consider the type conversion requirements of a typical client environment such as a web or desktop application. In such environments, you typically convert from String to support the client postback process, as well as back to String to support the view rendering process. In addition, you often need to localize String values. The more general core.convert Converter SPI does not address such formatting requirements directly. To directly address them, Spring 3 introduces a convenient Formatter SPI that provides a simple and robust alternative to PropertyEditors for client environments.

現在考慮典型用戶端環境下的類型轉換例如作為一個web或桌面應用。在這樣的環境下,你通常需要轉換字元串來支援用戶端回傳程式,也包括轉換成為字元串用于支援視圖表現程式。此外,你也需要本地化字元串值。通常的轉化器SPI沒有直接進行直接的格式轉換根據需要。為了實作這個功能,spring3加入了友善的格式化SPI提供簡單強健的的屬性編輯器用于用戶端環境。

In general, use the Converter SPI when you need to implement general-purpose type conversion logic; for example, for converting between a java.util.Date and and java.lang.Long. Use the Formatter SPI when you’re working in a client environment, such as a web application, and need to parse and print localized field values. The ConversionService provides a unified type conversion API for both SPIs.

通常,當你需要事項通用類型轉換時使用轉換器SPI;例如,為了友善将java.util.Date轉換為java.lang.Long。當你在用戶端環境使用格式化SPI,例如作為一個web營養共,你需要格式化和列印本地化的屬性值。ConversionService提供了統一的類型轉換API用于所有的SPI。

9.6.1 Formatter SPI

The Formatter SPI to implement field formatting logic is simple and strongly typed:

Formatter的SPI用于實作域格式化邏輯是簡單而且強類型的:

package org.springframework.format;

public interface Formatter<T> extends Printer<T>, Parser<T> {

}

Where Formatter extends from the Printer and Parser building-block interfaces:

Formatter繼承了Printer和Parser内置的接口:

public interface Printer<T> {

    String print(T fieldValue, Locale locale);

}

import java.text.ParseException;

public interface Parser<T> {

    T parse(String clientValue, Locale locale) throws ParseException;

}

To create your own Formatter, simply implement the Formatter interface above. Parameterize T to be the type of object you wish to format, for example, java.util.Date. Implement the print() operation to print an instance of T for display in the client locale. Implement the parse() operation to parse an instance of T from the formatted representation returned from the client locale. Your Formatter should throw a ParseException or IllegalArgumentException if a parse attempt fails. Take care to ensure your Formatter implementation is thread-safe.

為了建立你自己的Formatter,需要實作上面的Formatter接口。參數T類型是你需要格式化的類型,例如,java.util.Data。實作print方法用于列印T的執行個體在用戶端本地。實作parse方法用于将T執行個體從用戶端本地格式化。你的Formatter應該抛出ParseException或IllegalArgumentException如果格式化嘗試失敗的時候。注意保證你的Formatter是線程安全的。

Several Formatter implementations are provided in format subpackages as a convenience. The number package provides a NumberFormatter, CurrencyFormatter, and PercentFormatter to format java.lang.Number objects using a java.text.NumberFormat. The datetime package provides a DateFormatter to format java.util.Date objects with a java.text.DateFormat. The datetime.joda package provides comprehensive datetime formatting support based on the Joda Time library.

一些Formatter實作提供在format子包中作為友善使用。該Number子包中提供了NumberFormatter、CurrencyFormatter和PercentFormatter用于格式化java.lang.Number通過使用java.text.NumberFormat。datetime子包中提供了DateFormatter用于格式化java.util.Data通過使用java.text.DataFormat。datetime.joda子包中提供了複雜的日期轉化用于支援Joda的時間包。

Consider DateFormatter as an example Formatter implementation:

考慮Formatter的實作DataFormatter作為一個例子:

package org.springframework.format.datetime;

public final class DateFormatter implements Formatter<Date> {

    private String pattern;

    public DateFormatter(String pattern) {

        this.pattern = pattern;

    }

    public String print(Date date, Locale locale) {

        if (date == null) {

            return "";

        }

        return getDateFormat(locale).format(date);

    }

    public Date parse(String formatted, Locale locale) throws ParseException {

        if (formatted.length() == 0) {

            return null;

        }

        return getDateFormat(locale).parse(formatted);

    }

    protected DateFormat getDateFormat(Locale locale) {

        DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale);

        dateFormat.setLenient(false);

        return dateFormat;

    }

}

The Spring team welcomes community-driven Formatter contributions; see jira.spring.io to contribute.

spring小組歡迎社群的格式化貢獻:見jira.spring.io用于貢獻。

9.6.2 Annotation-driven Formatting

基于注解的格式化

As you will see, field formatting can be configured by field type or annotation. To bind an Annotation to a formatter, implement AnnotationFormatterFactory:

你看到域格式化可以通過域類型或注解來配置。為了将注解綁定到formatter上需要實作AnnotationFormatterFactory:

package org.springframework.format;

public interface AnnotationFormatterFactory<A extends Annotation> {

    Set<Class<?>> getFieldTypes();

    Printer<?> getPrinter(A annotation, Class<?> fieldType);

    Parser<?> getParser(A annotation, Class<?> fieldType);

}

Parameterize A to be the field annotationType you wish to associate formatting logic with, for example org.springframework.format.annotation.DateTimeFormat. Have getFieldTypes() return the types of fields the annotation may be used on. Have getPrinter() return a Printer to print the value of an annotated field. Have getParser() return a Parser to parse a clientValue for an annotated field.

參數A用于域注解類型你希望可以和格式化邏輯相關聯,例如org.springframework.format.annotation.DateTimeFormat。getFieldTypes方法可以傳回使用的注解域的類型。getPrinter可以傳回一個Printer用于列印注解域的值。getParser方法可以傳回一個Parser用于格式化用于注解域的clientValue。

The example AnnotationFormatterFactory implementation below binds the @NumberFormat Annotation to a formatter. This annotation allows either a number style or pattern to be specified:

下面實作AnnotationFormatterFactory的類将NumberFormatter注解和格式化器綁定。注解允許number類型或特定的格式:

public final class NumberFormatAnnotationFormatterFactory

        implements AnnotationFormatterFactory<NumberFormat> {

    public Set<Class<?>> getFieldTypes() {

        return new HashSet<Class<?>>(asList(new Class<?>[] {

            Short.class, Integer.class, Long.class, Float.class,

            Double.class, BigDecimal.class, BigInteger.class }));

    }

    public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {

        return configureFormatterFrom(annotation, fieldType);

    }

    public Parser<Number> getParser(NumberFormat annotation, Class<?> fieldType) {

        return configureFormatterFrom(annotation, fieldType);

    }

    private Formatter<Number> configureFormatterFrom(NumberFormat annotation,

            Class<?> fieldType) {

        if (!annotation.pattern().isEmpty()) {

            return new NumberFormatter(annotation.pattern());

        } else {

            Style style = annotation.style();

            if (style == Style.PERCENT) {

                return new PercentFormatter();

            } else if (style == Style.CURRENCY) {

                return new CurrencyFormatter();

            } else {

                return new NumberFormatter();

            }

        }

    }

}

To trigger formatting, simply annotate fields with @NumberFormat:

為了觸發格式化,簡單聲明@NumberFormat注解在域中:

public class MyModel {

    @NumberFormat(style=Style.CURRENCY)

    private BigDecimal decimal;

}

Format Annotation API

格式化注解API

A portable format annotation API exists in the org.springframework.format.annotation package. Use @NumberFormat to format java.lang.Number fields. Use @DateTimeFormat to format java.util.Date, java.util.Calendar, java.util.Long, or Joda Time fields.

友善的格式化注解API在org.springframework.format.annotation包中提供。使用@NumberFormat用于格式化java.lang.Number域。使用@DateTimeFormat用于格式化java.util.Date、java.util.Calendar、java.util.Long或Joda時間域,

The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date (yyyy-MM-dd):

下面的例子展示了使用@DateTimeFormate來将java.util.Date格式化為ISO日期(yyyy-MM-dd):

public class MyModel {

    @DateTimeFormat(iso=ISO.DATE)

    private Date date;

}

9.6.3 FormatterRegistry SPI

The FormatterRegistry is an SPI for registering formatters and converters. FormattingConversionService is an implementation of FormatterRegistry suitable for most environments. This implementation may be configured programmatically or declaratively as a Spring bean using FormattingConversionServiceFactoryBean. Because this implementation also implements ConversionService, it can be directly configured for use with Spring’s DataBinder and the Spring Expression Language (SpEL).

FormatterRegistry是一個SPI用于注冊格式化器和轉換器。FormattingConversionService是FormatterRegistry的實作用于大部分環境。該實作可以通過程式設計配置或定義為一個spring的bean通過使用FormattingConversionServiceFactoryBean。因為這個實作也實作了ConversionService,可以直接配置用于spring的DataBinder和spring的表達式語言。

Review the FormatterRegistry SPI below:

回憶下面的FormatterRegistry的SPI:

package org.springframework.format;

public interface FormatterRegistry extends ConverterRegistry {

    void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);

    void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);

    void addFormatterForFieldType(Formatter<?> formatter);

    void addFormatterForAnnotation(AnnotationFormatterFactory<?, ?> factory);

}

As shown above, Formatters can be registered by fieldType or annotation.

就像上面展示的,可以通過域類型或注解來注冊格式化器。

The FormatterRegistry SPI allows you to configure Formatting rules centrally, instead of duplicating such configuration across your Controllers. For example, you might want to enforce that all Date fields are formatted a certain way, or fields with a specific annotation are formatted in a certain way. With a shared FormatterRegistry, you define these rules once and they are applied whenever formatting is needed.

FormatterRegistry的SPI允許你配置格式化規則,避免跨控制器的重複配置。例如,你可以強制所有的日期域格式化為一個特定的形式或有特定注解的域格式化為特定的形式。通過共享FormatterRegistry,你可以一次定義這些規則并将它們應用于你需要的位置。

9.6.4 FormatterRegistrar SPI

The FormatterRegistrar is an SPI for registering formatters and converters through the FormatterRegistry:

FormatterRegistrar作為一個SPI用于注冊格式化器和轉換器通過FormatterRegistry:

package org.springframework.format;

public interface FormatterRegistrar {

    void registerFormatters(FormatterRegistry registry);

}

A FormatterRegistrar is useful when registering multiple related converters and formatters for a given formatting category, such as Date formatting. It can also be useful where declarative registration is insufficient. For example when a formatter needs to be indexed under a specific field type different from its own <T> or when registering a Printer/Parser pair. The next section provides more information on converter and formatter registration.

FormatterRegistrar是有用的當注冊多個相關的轉換器和格式化器用于給定的格式化種類,例如日期格式化。在直接注冊不能實作時可以很有用。例如當一個格式化去需要被索引在特定的域類型下不同于T類型或當注冊Printer/Parser對時使用。下一節将展示更多的有關轉換器和格式化器注冊的内容。

9.6.5 Configuring Formatting in Spring MVC

在spring的mvc中配置格式化

See Section 22.16.3, “Conversion and Formatting” in the Spring MVC chapter.

見22.16.3節,“轉換和格式化”在spring的mvc章節。

9.7 Configuring a global date & time format

配置全局的日期和時間格式

By default, date and time fields that are not annotated with @DateTimeFormat are converted from strings using the DateFormat.SHORT style. If you prefer, you can change this by defining your own global format.

預設,日期和時間域沒有使用@DateTimeFormat來修飾可以使用DateFormat.SHORT的風格從字元串來轉化。如果你需要,你可以通過定義你自己的全局格式來改變。

You will need to ensure that Spring does not register default formatters, and instead you should register all formatters manually. Use the org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar or org.springframework.format.datetime.DateFormatterRegistrar class depending on whether you use the Joda Time library.

你将會需要確定spring沒有注冊預設的格式化器,作為代替你需要手動注冊所有的格式化去。使用org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar或org.springframework.format.datetime.DateFormatterRegistrar類根據你是否使用Joda時間庫。

For example, the following Java configuration will register a global ' `yyyyMMdd’ format. This example does not depend on the Joda Time library:

例如,下面的Java配置注冊了一個全局的“yyyyMMdd”格式。這個例子不需要依賴Joda時間庫。

@Configuration

public class AppConfig {

    @Bean

    public FormattingConversionService conversionService() {

        // Use the DefaultFormattingConversionService but do not register defaults

// 使用DefaultFormattingConversionService但是沒有将其注冊為預設

        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);

        // Ensure @NumberFormat is still supported

// 依然支援@NumberFormat

        conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());

        // Register date conversion with a specific global format

// 使用全局的格式化來注冊日期的格式化

        DateFormatterRegistrar registrar = new DateFormatterRegistrar();

        registrar.setFormatter(new DateFormatter("yyyyMMdd"));

        registrar.registerFormatters(conversionService);

        return conversionService;

    }

}

If you prefer XML based configuration you can use a FormattingConversionServiceFactoryBean. Here is the same example, this time using Joda Time:

如果你傾向于基于xml的配置你可以使用FormattingConversionServiceFactoryBean。這裡給一個例子,其中這裡的時間使用了Joda時間庫:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd>

    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">

        <property name="registerDefaultFormatters" value="false" />

        <property name="formatters">

            <set>

                <bean class="org.springframework.format.number.NumberFormatAnnotationFormatterFactory" />

            </set>

        </property>

        <property name="formatterRegistrars">

            <set>

                <bean class="org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar">

                    <property name="dateFormatter">

                        <bean class="org.springframework.format.datetime.joda.DateTimeFormatterFactoryBean">

                            <property name="pattern" value="yyyyMMdd"/>

                        </bean>

                    </property>

                </bean>

            </set>

        </property>

    </bean>

</beans>

[Note]

注意

Joda Time provides separate distinct types to represent date, time and date-time values. The dateFormatter, timeFormatter and dateTimeFormatter properties of the JodaTimeFormatterRegistrar should be used to configure the different formats for each type. The DateTimeFormatterFactoryBean provides a convenient way to create formatters.

Joda時間提供了分割的域來代表日期、時間和日期時間值。JodaTimeFormatterRegistrar類的dateFormatter、timeFormatter和dateTimeFormatter屬性應該被使用用于配置不同的類型的格式。DateTimeFormatterFactoryBean提供了一個友善的方式用于建立格式化器。

If you are using Spring MVC remember to explicitly configure the conversion service that is used. For Java based @Configuration this means extending the WebMvcConfigurationSupport class and overriding the mvcConversionService() method. For XML you should use the 'conversion-service' attribute of the mvc:annotation-driven element. See Section 22.16.3, “Conversion and Formatting” for details.

如果你使用spring的mvc,記住明确配置需要使用的轉換服務。對于@Configuration注解來說這意味着擴充WebMvcConfigurationSupport類和覆寫mvcConversionService方法。對于使用xml,你應當使用mvc:annotation-driven元素的conversion-service屬性。見22.16.3,“轉換和格式化”。

9.8 Spring Validation

spring的驗證

Spring 3 introduces several enhancements to its validation support. First, the JSR-303 Bean Validation API is now fully supported. Second, when used programmatically, Spring’s DataBinder can now validate objects as well as bind to them. Third, Spring MVC now has support for declaratively validating @Controller inputs.

spring3增加一些特性用于支援驗證。首先,JSR303的bean驗證api是全部支援的。其次,當程式設計使用驗證時,spring的DataBinder可以驗證object并綁定他們。第三,spring的mvc現在支援在@Controller中輸入驗證内容。

9.8.1 Overview of the JSR-303 Bean Validation API

JSR303的bean驗證api的概述

JSR-303 standardizes validation constraint declaration and metadata for the Java platform. Using this API, you annotate domain model properties with declarative validation constraints and the runtime enforces them. There are a number of built-in constraints you can take advantage of. You may also define your own custom constraints.

JSR303标準提供驗證限制定義和中繼資料用于java平台。使用這個api,你使用顯示的驗證限制聲明域模型并且運作時會強制執行他們。有很多内置的驗證限制需要關注。你也可以定義你自己的自定義限制。

To illustrate, consider a simple PersonForm model with two properties:

為了說明,考慮一個有兩個屬性的簡單的PersonForm模型:

public class PersonForm {

    private String name;

    private int age;

}

JSR-303 allows you to define declarative validation constraints against such properties:

JSR303允許你定義顯示的驗證限制在這些屬性中:

public class PersonForm {

    @NotNull

    @Size(max=64)

    private String name;

    @Min(0)

    private int age;

}

When an instance of this class is validated by a JSR-303 Validator, these constraints will be enforced.

當這個執行個體在JSR303驗證器下被驗證,這些限制會被強制執行。

For general information on JSR-303/JSR-349, see the Bean Validation website. For information on the specific capabilities of the default reference implementation, see the Hibernate Validator documentation. To learn how to setup a Bean Validation provider as a Spring bean, keep reading.

在JSR303或JSR349中,參考bean驗證的網站。關于特定的功能對于預設的引用實作,見Hibernate的驗證文檔。為了給spring的bean提供bean驗證,請繼續閱讀。

9.8.2 Configuring a Bean Validation Provider

配置bean驗證提供者

Spring provides full support for the Bean Validation API. This includes convenient support for bootstrapping a JSR-303/JSR-349 Bean Validation provider as a Spring bean. This allows for a javax.validation.ValidatorFactory or javax.validation.Validator to be injected wherever validation is needed in your application.

spring提供全面的支援對于bean驗證的api。包括友善支援JSR303或JSR349的bean提供者用于spring的bean。這允許javax.validation.ValidatorFactory或javax.validation.Validator可以注入你需要在你的應用中使用驗證的位置。

Use the LocalValidatorFactoryBean to configure a default Validator as a Spring bean:

使用LocalValidatorFactoryBean為spring的bean配置預設的驗證器:

<bean id="validator"

    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

The basic configuration above will trigger Bean Validation to initialize using its default bootstrap mechanism. A JSR-303/JSR-349 provider, such as Hibernate Validator, is expected to be present in the classpath and will be detected automatically.

上面的配置将會在初始化時激活bean的驗證,使用預設的啟動政策。JSR303或JSR349的提供,例如Hibernate的驗證器,被期望出現在classpath中并且會自動被探測。

Injecting a Validator

注入一個驗證器

LocalValidatorFactoryBean implements both javax.validation.ValidatorFactory and javax.validation.Validator, as well as Spring’s org.springframework.validation.Validator. You may inject a reference to either of these interfaces into beans that need to invoke validation logic.

LocalValidatorFactoryBean實作了javax.validation.ValidatorFactory和javax.validation.Validator接口,也包括Spring的org.springframework.validation.Validator。你可以注入任何一個上面三個接口的引用到你的bean中如果你需要調用驗證邏輯。

Inject a reference to javax.validation.Validator if you prefer to work with the Bean Validation API directly:

如果你希望直接使用bean驗證api可以注入javax.validation.Validator的引用:

import javax.validation.Validator;

@Service

public class MyService {

    @Autowired

    private Validator validator;

Inject a reference to org.springframework.validation.Validator if your bean requires the Spring Validation API:

如果你需要spring的驗證api則注入org.springframework.validation.Validator的引用:

import org.springframework.validation.Validator;

@Service

public class MyService {

    @Autowired

    private Validator validator;

}

Configuring Custom Constraints

配置自定義的限制

Each Bean Validation constraint consists of two parts. First, a @Constraint annotation that declares the constraint and its configurable properties. Second, an implementation of the javax.validation.ConstraintValidator interface that implements the constraint’s behavior. To associate a declaration with an implementation, each @Constraint annotation references a corresponding ValidationConstraint implementation class. At runtime, a ConstraintValidatorFactory instantiates the referenced implementation when the constraint annotation is encountered in your domain model.

每個bean的驗證限制包括兩個部分。第一,@Constraint注解聲明了限制和他的可配置屬性。第二,實作javax.validation.ConstraintValidator接口用于實作限制的行為。為了關聯實作的定義,每個@Constraint注解引用一個相關的ValidationConstraint實作類。在運作時,一個ConstraintValidatorFactory執行個體化相關的實作當限制注解定義你的域模型中。

By default, the LocalValidatorFactoryBean configures a SpringConstraintValidatorFactory that uses Spring to create ConstraintValidator instances. This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean.

預設的,LocalValidatorFactoryBean配置了SpringConstraintValidatorFactory用于spring來建立ConstraintValidator執行個體。允許你自定義ConstraintValidators來獨立注入類似于其他spring的bean。

Shown below is an example of a custom @Constraint declaration, followed by an associated ConstraintValidator implementation that uses Spring for dependency injection:

下面是一個@Constraint聲明的例子,使用spring的依賴注入來管理ConstraintValidator的實作:

@Target({ElementType.METHOD, ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME)

@Constraint(validatedBy=MyConstraintValidator.class)

public @interface MyConstraint {

}

import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

    @Autowired;

    private Foo aDependency;

    ...

}

As you can see, a ConstraintValidator implementation may have its dependencies @Autowired like any other Spring bean.

可見,ConstraintValidator實作可以有獨立的@Autowired類似于其他的spring的bean。

Spring-driven Method Validation

基于spring的方法驗證

The method validation feature supported by Bean Validation 1.1, and as a custom extension also by Hibernate Validator 4.3, can be integrated into a Spring context through a MethodValidationPostProcessor bean definition:

方法驗證特性通過bean驗證1.1來支援,Hibernate驗證4.3的自定義擴充也可以注入spring的上下文通過一個MethodValidationPostProcessor的bean定義。

<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>

In order to be eligible for Spring-driven method validation, all target classes need to be annotated with Spring’s @Validated annotation, optionally declaring the validation groups to use. Check out the MethodValidationPostProcessor javadocs for setup details with Hibernate Validator and Bean Validation 1.1 providers.

為了适用于基于spring的方法驗證,所有的目标的類需要使用spring的@Validated注解,可選的使用驗證組。檢視MethodValidationPostProcessor的javadocs用于了解Hibernate驗證器和bean驗證1.1的詳情。

Additional Configuration Options

額外的配置選項

The default LocalValidatorFactoryBean configuration should prove sufficient for most cases. There are a number of configuration options for various Bean Validation constructs, from message interpolation to traversal resolution. See the LocalValidatorFactoryBean javadocs for more information on these options.

預設的LocalValidatorFactoryBean配置應當适合大多數場景。需要很多配置選項用于多種bean的驗證限制,從資訊采集到解決方案。詳細見LocalValidatorFactoryBean的javadocs。

9.8.3 Configuring a DataBinder

配置DataBinder

Since Spring 3, a DataBinder instance can be configured with a Validator. Once configured, the Validator may be invoked by calling binder.validate(). Any validation Errors are automatically added to the binder’s BindingResult.

自從spring3,DataBinder執行個體可以使用驗證器來配置。一次配置,驗證器可以通過調用binder.validate來使用。任何驗證錯誤可以自動加入binder的BindingResult中。

When working with the DataBinder programmatically, this can be used to invoke validation logic after binding to a target object:

當程式設計使用DataBinder,可以在目标object上調用驗證邏輯:

Foo target = new Foo();

DataBinder binder = new DataBinder(target);

binder.setValidator(new FooValidator());

// bind to the target object

// 綁定到目标object

binder.bind(propertyValues);

// validate the target object

// 驗證目标object

binder.validate();

// get BindingResult that includes any validation errors

// 獲得BindingResult裡面包含所有驗證錯誤

BindingResult results = binder.getBindingResult();

A DataBinder can also be configured with multiple Validator instances via dataBinder.addValidators and dataBinder.replaceValidators. This is useful when combining globally configured Bean Validation with a Spring Validator configured locally on a DataBinder instance. See ???.

DataBinder可以使用多個驗證器執行個體來配置,通過使用dataBinder.addValidators和dataBinder.replaceValidators。當組合全局配置的bean驗證通過使用spring的驗證器在本地的DataBinder執行個體上使用。見……

9.8.4 Spring MVC 3 Validation

spring的mvc3的驗證

See Section 22.16.4, “Validation” in the Spring MVC chapter.

将22.16.4,spirng的mvc章節中的驗證。