首页 > 技术文章 > spring官网在线学习文档翻译3

lix-2020 2020-09-29 10:41 原文

3. Validation, Data Binding, and Type Conversion

3.1. Introduction(介绍;引进;采用;入门;传入)

JSR-303/JSR-349 Bean Validation

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.

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

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

  • 就设置支持而言,Spring Framework 4.0支持Bean验证1.0 (JSR-303)和Bean验证1.1 (JSR-349),还将其适应于Spring s验证器接口。应用程序可以选择一次全局启用Bean验证,就像Spring验证中描述的那样,并且只针对所有验证需求使用它。应用程序还可以为每个DataBinder实例注册额外的Spring验证器实例,如配置DataBinder中所述。这对于插入验证逻辑而不使用注释可能很有用。

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.

-[ 数据绑定对于允许将用户输入动态绑定到应用程序的域模型(或用于处理用户输入的任何对象)非常有用。Spring提供了所谓的DataBinder来实现这一点。Validator和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,因为如果您打算使用它,那么您很可能在尝试将数据绑定到对象时使用它。

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的DataBinder和底层BeanWrapper都使用PropertyEditors来解析和格式化属性值。PropertyEditor概念是JavaBeans规范的一部分,在本章中也有解释。Spring 3引入了一个“核心”。提供一般类型转换工具的convert包,以及用于格式化UI字段值的高级“format”包。这些新包可以作为PropertyEditors的更简单的替代品,也将在本章进行讨论。

3.2. Validation using Spring’s Validator interface(使用Spring的Validator接口进行验证)

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提供了一个验证器接口,您可以使用它来验证对象。Validator接口使用一个Errors对象工作,因此在验证时,验证器可以向Errors对象报告验证失败。

Let’s consider a small data object:(让我们考虑一个小的数据对象:)

public class Person {

    private String name;
    private int age;

    // the usual getters and setters...
}

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的以下两个方法来为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

    • validate(Object, org.springframework.validation.Errors)——验证给定的对象,在验证错误的情况下,用给定的errors对象注册这些对象

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

  • 实现验证器相当简单,特别是当您知道Spring框架还提供的ValidationUtils助手类时。
public class PersonValidator implements Validator {

    /**
     * This Validator validates *just* Person instances
     */
    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”属性(如果它是空的或空字符串)。查看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:

  • 虽然可以实现单个验证器类来验证富对象中的每个嵌套对象,但最好将每个嵌套对象类的验证逻辑封装在其自己的验证器实现中。“富”对象的一个简单示例是Customer,它由两个字符串属性(第一个和第二个名称)和一个复杂的Address对象组成。Address对象可以独立于Customer对象使用,因此实现了一个不同的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;
    }

    /**
     * This Validator validates Customer instances, and any subclasses of Customer too
     */
    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.

  • 验证错误被报告给传递给验证器的错误对象。对于Spring Web MVC,您可以使用< Spring:bind/>标记来检查错误消息,当然您也可以自己检查错误对象。关于它提供的方法的更多信息可以在javadocs中找到。

3.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.

  • 我们已经讨论了数据绑定和验证。输出与验证错误对应的消息是我们需要讨论的最后一件事。在上面所示的示例中,我们拒绝了名称和年龄字段。如果我们打算通过使用MessageSource输出错误消息,我们将使用拒绝字段时给出的错误代码(在本例中是'name'和'age')来实现。当您从Errors接口调用(直接或间接使用ValidationUtils类)rejectValue或其他拒绝方法时,底层实现不仅会注册您传入的代码,还会注册许多附加的错误代码。它注册的错误代码由所使用的MessageCodesResolver决定。默认情况下,使用DefaultMessageCodesResolver,例如,它不仅用您提供的代码注册消息,而且还注册包含您传递给reject方法的字段名的消息。所以,如果您使用rejectValue(“age”,“too. dark .old”)拒绝一个字段,除了too.darn。旧代码,Spring也会注册。年龄和。da。old。age。int(第一个包含字段名第二个包含字段的类型);这样做是为了方便开发人员定位错误消息等。

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中在线找到。

3.4. Bean manipulation and the BeanWrapper(Bean操作和Bean包装器)

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。bean包遵循Oracle提供的JavaBeans标准。JavaBean只是一个具有默认无参数构造函数的类,它遵循命名约定(通过示例),其中名为bingoMadness的属性将拥有setter方法setBingoMadness(..)和getter方法getBingoMadness()。有关JavaBeans和规范的更多信息,请参阅Oracle的网站(JavaBeans)。

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来执行该bean上的操作,比如设置和检索属性。

3.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(s)和getPropertyValue(s)方法完成的,这两个方法都带有两个重载的变体。它们在Spring附带的javadocs中都有更详细的描述。需要知道的重要一点是,表示对象的属性有两种约定。举几个例子:
Expression(表达式) Explanation(说明)
name Indicates the property name corresponding to the methods getName() or isName() and setName(..)【指示与方法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[2] Indicates the third element of the indexed property account. Indexed properties can be of type array, list or other naturally ordered collection【指示索引属性帐户的第三个元素。索引属性的类型可以是数组、列表或其他自然排序的集合】
account[COMPANYNAME] Indicates the value of the map entry indexed by the key COMPANYNAME of the Map property account【指示按map属性帐户的键公司名称索引的映射项的值】

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:

  • 下面的代码片段展示了一些如何检索和操作实例化的公司和雇员的一些属性的例子:
BeanWrapper company = new 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 = new 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");

3.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的概念来影响对象和字符串之间的转换。如果你仔细想想,它有时可以很方便地以不同的方式表示属性,而不是对象本身。例如,一个日期可以以一种人类可读的方式表示(为字符串的2007-14-09),而我们仍然能够将人类可读的表单转换回原始的日期(或者更好:转换任何日期输入到人类可读的表单,回到日期对象)。这种行为可以通过注册自定义编辑器(java.beans.PropertyEditor)来实现。在前一章中提到的一个特定的IoC容器中,在一个bean包装器上注册自定义编辑器,或者在一个特定的IoC容器中交替注册定制编辑器,从而使它了解如何将属性转换为所需的类型。在java的javadocs中多读一些关于PropertyEditors的内容。Oracle提供的bean包。

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.
    • 在bean上设置属性是使用PropertyEditors完成的。当提及. lang。当您在XML文件中声明的某个bean的属性值时,Spring将(如果相应属性的setter具有类参数)使用ClassEditor来尝试将该参数解析为一个类对象。
  • 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使工作变得简单。下面列出了它们中的每一个,它们都位于org.springframework.beans中。propertyeditors包。大多数,但不是全部(如下所示),默认情况下是由BeanWrapperImpl注册的。如果属性编辑器以某种方式可配置,当然你仍然可以注册自己的变体来覆盖默认的:
Class Explanation(说明)
ByteArrayPropertyEditor Editor for byte arrays. Strings will simply be converted to their corresponding byte representations. Registered by default by BeanWrapperImpl.【字节数组的编辑器。字符串将被简单地转换为相应的字节表示。默认由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.【布尔属性的可自定义属性编辑器。默认情况下是由BeanWrapperImpl注册的,但是可以通过将其自定义实例注册为自定义编辑器来覆盖】
CustomCollectionEditor Property editor for Collections, converting any source Collection to a given target Collection type.【集合的属性编辑器,将任何源集合转换为给定的目标集合类型。】
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.【util的可定制属性编辑器。日期,支持自定义日期格式。默认未注册。必须是用户注册所需的适当的格式。】
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.【可定制的属性编辑器为任何数字子类,如整数,长,浮点,双。默认情况下由BeanWrapperImpl注册,但是可以通过将其自定义实例注册为自定义编辑器来覆盖。】
FileEditor Capable of resolving Strings to java.io.File objects. Registered by default by BeanWrapperImpl.【能够将字符串解析为java.io。文件对象。默认由BeanWrapperImpl注册。】
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) InputStream,因此InputStream属性可以直接设置为字符串。注意,默认用法不会为您关闭InputStream !默认由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.【能够将字符串解析为Locale对象,反之亦然(字符串格式为[country][variant],这与Locale的toString()方法提供的内容相同)。默认由BeanWrapperImpl注册。】
PatternEditor Capable of resolving Strings to java.util.regex.Pattern objects and vice versa.【能够将字符串解析为java.util.regex。模式对象,反之亦然。】
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.【能够转换字符串(使用在java.util的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【修饰字符串的属性编辑器。允许将空字符串转换为空值。默认未注册;必须是根据需要注册的用户。】.
URLEditor Capable of resolving a String representation of a URL to an actual URL object. Registered by default by BeanWrapperImpl.【能够将URL的字符串表示解析为实际的URL对象。默认由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.bean。PropertyEditorManager设置可能需要的属性编辑器的搜索路径。搜索路径还包括sun.bean。编辑器,其中包括字体、颜色和大多数基本类型等类型的PropertyEditor实现。还要注意的是,如果PropertyEditor类与它们处理的类在同一个包中,并且与类同名,并附加了'Editor',那么标准JavaBeans基础设施将自动发现它们(无需显式地注册它们);例如,可以有如下的类和包结构,这就足以识别FooEditor类并将其用作footype属性的PropertyEditor。
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 JavaBeans机制(在这里详细描述)。下面是一个使用BeanInfo机制显式地用关联类的属性注册一个或多个PropertyEditor实例的示例。
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.

  • 下面是引用的FooBeanInfo类的Java源代码。这将使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容器最终使用标准JavaBeans PropertyEditors将这些字符串转换为属性的复杂类型。Spring预先注册了许多定制的PropertyEditors(例如,将表示为字符串的类名转换为实际的类对象)。此外,Java的标准JavaBeans PropertyEditor查找机制允许类的PropertyEditor被适当地命名,并与它提供支持的类放在同一个包中,从而自动查找。

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.

  • 如果需要注册其他自定义PropertyEditors,有几种可用的机制。最常用的手工方法(通常不方便或不推荐使用)是简单地使用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.

  • 请注意,通过使用称为BeanWrapper的东西来处理属性转换,所有bean工厂和应用程序上下文都会自动使用许多内置的属性编辑器。前一节列出了BeanWrapper注册的标准属性编辑器。此外,ApplicationContexts还覆盖或添加额外数量的编辑器,以适合于特定应用程序上下文类型的方式处理资源查找。

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 PropertyEditor实例用于将表示为字符串的属性值转换为属性的实际复杂类型。CustomEditorConfigurer是一个bean工厂后处理器,可以用来方便地将对其他PropertyEditor实例的支持添加到ApplicationContext中。

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

  • 假设一个用户类为ExoticType,另一个类依赖于ExoticType,需要将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
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将新的PropertyEditor注册到ApplicationContext中,它将能够根据需要使用它:
<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.

  • 向Spring容器注册属性编辑器的另一种机制是创建和使用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
        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与数据绑定控制器(如SimpleFormController)结合使用是非常方便的。下面是一个使用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
}

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注册代码封装在一个类中,然后根据需要在尽可能多的控制器之间共享。

3.5. Spring Type Conversion(类型转换)

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.

  • Spring 3引入了一个核心。提供一般类型转换系统的转换包。系统定义了一个SPI来实现类型转换逻辑,以及一个API来在运行时执行类型转换。在Spring容器中,此系统可以用作PropertyEditors的替代方案,将外部化bean属性值字符串转换为所需的属性类型。还可以在应用程序中需要类型转换的任何地方使用公共API。

3.5.1. Converter SPI(转换器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中提供了几个转换器实现。支持包作为方便。这些包括从字符串到数字和其他常见类型的转换器。考虑StringToInteger作为一个典型的转换器实现的例子:
package org.springframework.core.convert.support;

final class StringToInteger implements Converter<String, Integer> {

    public Integer convert(String source) {
        return Integer.valueOf(source);
    }
}

3.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:

  • 当您需要为整个类层次结构集中转换逻辑时,例如从String转换到java.lang时。Enum对象,实现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), 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());
        }
    }
}

3.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支持在多个源和目标类型之间进行转换。此外,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(对象、类型描述符、类型描述符)来实现转换逻辑。源类型描述符提供对保存被转换值的源字段的访问。目标类型描述符提供对将在其中设置转换值的目标字段的访问。

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将内省声明目标集合类型的字段,以解析集合的元素类型。这允许在目标字段上设置集合之前,将源数组中的每个元素转换为集合元素类型。
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 ConditionalConverter {

    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}

public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}

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只有在目标实体类型声明一个静态查找器方法时才能匹配,例如findAccount(Long)。您可以在匹配(类型描述符、类型描述符)的实现中执行这样的查找器方法检查。

3.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。转换器通常在这个facade接口后执行:
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.

  • 在core.convert中提供了健壮的ConversionService实现。支持包。GenericConversionService是适合在大多数环境中使用的通用实现。ConversionServiceFactory为创建通用的ConversionService配置提供了一个方便的工厂。

3.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是一种无状态对象,设计用于在应用程序启动时实例化,然后在多个线程之间共享。在Spring应用程序中,您通常为每个Spring容器(或ApplicationContext)配置一个ConversionService实例。该ConversionService将被Spring拾取,然后在需要由框架执行类型转换时使用。您还可以将这个ConversionService注入到任何bean中并直接调用它。
If no ConversionService is registered with Spring, the original PropertyEditor-based system is used.
  • 如果没有向Spring注册ConversionService,则使用原始的基于propertyeditor的系统。

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可以在字符串、数字、枚举、集合、映射和其他常见类型之间进行转换。若要使用自己的自定义转换器补充或覆盖默认转换器,请设置转换器属性。属性值可以实现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 Conversion and Formatting in the Spring MVC chapter.

  • 在Spring MVC应用程序中使用ConversionService也很常见。请参阅Spring MVC一章中的转换和格式化。

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

  • 在某些情况下,您可能希望在转换期间应用格式。有关使用FormattingConversionServiceFactoryBean的详细信息,请参阅FormatterRegistry SPI。

3.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.

  • 对于大多数用例,可以使用指定targetType的convert方法,但它不能用于更复杂的类型,如参数化元素的集合。例如,如果希望以编程方式将整数列表转换为字符串列表,则需要提供源和目标类型的正式定义。

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自动注册转换器,这适用于大多数环境。这包括集合转换器、标量转换器和基本对象到字符串转换器。可以使用DefaultConversionService类上的静态addDefaultConverters方法向任何ConverterRegistry注册相同的转换器。

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的集合,假设标准的集合处理是适当的。

3.6. Spring Field Formatting(字段格式)

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和强类型转换器SPI,用于实现从一种类型到另一种类型的转换逻辑。Spring容器使用这个系统来绑定bean属性值。此外,Spring表达式语言(SpEL)和DataBinder都使用这个系统来绑定字段值。例如,当SpEL需要将一个短表达式强制为一个长表达式时。setValue(对象bean,对象值)尝试,核心。转换系统执行强制转换。

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或桌面应用程序)的类型转换需求。在这种环境中,您通常将字符串转换为支持客户端回发过程,并将其转换为支持视图呈现过程的字符串。此外,经常需要对字符串值进行本地化。更一般的核心。convert Converter SPI不直接满足这种格式要求。为了直接解决这些问题,Spring 3引入了一个方便的格式化程序SPI,它为客户机环境提供了一个简单而健壮的PropertyEditors替代方案。

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之间转换。日期和java.lang.Long。当您在客户机环境(如web应用程序)中工作并需要解析和打印本地化的字段值时,请使用Formatter SPI。ConversionService为两个spi提供统一的类型转换API。

3.6.1. Formatter SPI(格式化器SPI)

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

  • 格式化程序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:

  • 格式化程序从打印机和解析器构建块接口扩展:
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.

  • 要创建自己的格式化程序,只需实现上面的格式化程序接口。将T参数化为您希望格式化的对象类型,例如,java.util.Date。实现print()操作以打印一个T的实例,以便在客户机区域设置中显示。实现parse()操作,从客户端区域设置返回的格式化表示中解析T实例。如果解析尝试失败,格式化程序应该抛出ParseException或IllegalArgumentException。注意确保格式化程序实现是线程安全的。

Several Formatter implementations are provided in format subpackages as a convenience. The number package provides a NumberStyleFormatter, CurrencyStyleFormatter, and PercentStyleFormatter 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.

  • 为了方便起见,在format子包中提供了几个格式化程序实现。数字包提供了NumberStyleFormatter、CurrencyStyleFormatter和PercentStyleFormatter来格式化java.lang。使用java.text.NumberFormat为对象编号。datetime包提供了一个DateFormatter来格式化java.util。Date对象使用java.text.DateFormat。datetime。joda包基于joda - time库提供了全面的datetime格式化支持。

Consider DateFormatter as an example Formatter implementation:

  • 考虑DateFormatter作为一个示例格式化程序实现:
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做出贡献。

3.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:

  • 您将看到,可以根据字段类型或注释配置字段格式。要将注释绑定到格式化程序,请实现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()返回一个打印机来打印一个带注释的字段的值。让getParser()返回一个解析器来解析已注释字段的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实现将@NumberFormat注释绑定到一个格式化程序。这个注释允许指定一个数字样式或模式:
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 NumberStyleFormatter(annotation.pattern());
        } else {
            Style style = annotation.style();
            if (style == Style.PERCENT) {
                return new PercentStyleFormatter();
            } else if (style == Style.CURRENCY) {
                return new CurrencyStyleFormatter();
            } else {
                return new NumberStyleFormatter();
            }
        }
    }
}

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.

  • format中有一个可移植的格式注释API。注释包。使用@NumberFormat格式化java.lang。数量字段。使用@DateTimeFormat格式化java.util。日期、java.util。日历,java.util。Long或Joda-Time字段。

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

  • 下面的示例使用@DateTimeFormat格式化java.util。日期(yyyy-MM-dd
public class MyModel {

    @DateTimeFormat(iso=ISO.DATE)
    private Date date;
}

3.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的实现。可以使用FormattingConversionServiceFactoryBean以编程方式或声明方式将此实现配置为Spring bean。因为这个实现还实现了ConversionService,所以可以直接配置它,以便与Spring的DataBinder和Spring表达式语言(SpEL)一起使用。

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.

  • 如上所示,格式化程序可以通过fieldType或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,只需定义一次这些规则,它们就会在需要格式化时应用。

3.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 or when registering a Printer/Parser pair. The next section provides more information on converter and formatter registration.

  • FormatterRegistrar在为给定格式类别(如日期格式)注册多个相关转换器和格式器时非常有用。在声明性注册不足的情况下,它也很有用。例如,格式化程序需要在与其自己的不同的特定字段类型下建立索引,或者注册打印机/解析器对时。下一节提供关于转换器和格式化程序注册的更多信息。

3.6.5. Configuring Formatting in Spring MVC(在Spring MVC中配置格式)

See Conversion and Formatting in the Spring MVC chapter.

  • 请参阅Spring MVC一章中的转换和格式化。

3.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从字符串转换。短的风格。如果您愿意,可以通过定义自己的全局格式来更改这一点。

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-Time库。

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-Time库:
@Configuration
public class AppConfig {

    @Bean
    public FormattingConversionService conversionService() {

        // Use the DefaultFormattingConversionService but do not register defaults
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);

        // Ensure @NumberFormat is still supported
        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>
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-Time提供了不同的类型来表示日期、时间和日期-时间值。应该使用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 Conversion and Formatting for details.

3.8. Spring Validation(验证)

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.

  • Spring 3对其验证支持进行了一些增强。首先,现在完全支持JSR-303 Bean验证API。其次,当以编程方式使用时,Spring的DataBinder现在可以验证对象并绑定到它们。第三,Spring MVC现在支持声明式验证@Controller输入。

3.8.1. Overview of the JSR-303 Bean Validation API(JSR-303 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.

  • JSR-303标准化了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:

  • JSR-303允许您针对这些属性定义声明性验证约束:
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.

  • 当这个类的实例被JSR-303验证器验证时,这些约束将被强制执行。

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.

  • 有关JSR-303/JSR-349的一般信息,请参阅Bean验证网站。有关默认参考实现的特定功能的信息,请参阅Hibernate Validator文档。要了解如何将Bean验证提供程序设置为Spring Bean,请继续阅读。

3.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的全面支持。这包括方便地支持将JSR-303/JSR-349 Bean验证提供程序引导为Spring Bean。这允许使用javax.validation。ValidatorFactory或javax.validation。在应用程序中需要验证的地方注入验证器。

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验证,以使用其默认的引导机制进行初始化。JSR-303/JSR-349提供程序(如Hibernate Validator)应该出现在类路径中,并将被自动检测到。
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. Validator. Validator。您可以将对这两个接口的引用注入需要调用验证逻辑的bean中。

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

  • 向javax.validation注入一个引用。如果你喜欢直接使用Bean验证API:
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:

  • 向org.springframework.validation注入一个引用。如果你的bean需要Spring验证API:
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 ConstraintValidator 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注释都引用相应的ConstraintValidator实现类。在运行时,当域模型中遇到约束注释时,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配置一个使用Spring创建ConstraintValidator实例的SpringConstraintValidatorFactory。这允许您的自定义constraintvalidator像其他任何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实现可以像任何其他Spring bean一样拥有它的依赖@Autowired。
Spring-driven Method Validation(之方法验证)

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 validation 1.1和Hibernate Validator 4.3支持的方法验证特性,可以通过MethodValidationPostProcessor Bean定义集成到Spring上下文中:
<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 Validator和Bean Validation 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。

3.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.

  • 从Spring 3开始,可以用验证器配置DataBinder实例。一旦配置完毕,验证器可以通过调用binding .validate()来调用。任何验证错误都会自动添加到绑定器的绑定结果中。

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

  • 以编程方式使用DataBinder时,可用于在绑定到目标对象后调用验证逻辑:
Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());

// bind to the target object
binder.bind(propertyValues);

// validate the target object
binder.validate();

// get BindingResult that includes any validation errors
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 [validation-mvc-configuring].

  • 还可以通过DataBinder配置多个验证器实例。addValidators dataBinder.replaceValidators。当将全局配置的Bean验证与在DataBinder实例上本地配置的Spring验证器相结合时,这是非常有用的。看到[validation-mvc-configuring]。

3.8.4. Spring MVC 3 Validation(Spring MVC 3验证)

See Validation in the Spring MVC chapter.(请参阅Spring MVC一章中的验证。)

后续内容戳我^^

推荐阅读