验证
注意:验证 API 未维护,将在 GWT 2.8 之后从 GWT SDK 移至独立项目。
介绍
任何接受输入的应用程序的重要部分是验证该输入以确保其正确且有效。此验证可以通过多种方式完成,包括在每次收到输入时手动插入条件语句,但此过程可能很繁琐且难以维护。
为了简化数据验证,GWT 支持 JSR-303 Bean Validation,它提供了一个框架用于指定定义应用程序中哪些数据有效或允许的“约束”。
例如,通过在您的类上指定以下注释
public class Person implements Serializable {
@NotNull
@Size(min = 4, message = "Name must be at least 4 characters long.")
private String name;
}
您可以确保满足这些条件,并在未满足条件时生成有意义的错误。
在编译时,GWT 验证会为您的所有对象创建一个 Validator,该 Validator 可用于进行客户端验证。如果您使用基于 Java 的服务器,则可以使用相同的约束来进行服务器端数据验证。
设置说明
为了使用 GWT 验证,您必须确保您的系统类路径中包含以下库
- 验证 API(类和源代码)(已包含在 GWT SDK 中)
- validation-api-1.0.0.GA.jar
- Hibernate Validator 4.1.0(类和源代码)
- hibernate-validator-4.1.0.Final.jar
- hibernate-validator-4.1.0.Final-sources.jar
- Simple Logging Facade for Java 和 log4j(Hibernate Validator 需要)
- slf4j-api-1.6.1.jar
- slf4j-log4j12-1.6.1.jar
- log4j-1.2.16.jar
如果您在服务器端验证中使用验证器,请确保也正确配置 Web 应用程序类路径。
GWT 验证入门
设置约束
GWT 验证是通过使用约束注释来注释 bean、getter 和属性来完成的。有关如何定义和使用约束的更多信息,请参见 JSR-303 规范。
public class Person {
@Size(min = 4)
private String name;
创建验证器工厂
验证器工厂是启动验证过程所必需的。要创建验证器工厂,您必须创建一个扩展 AbstractGwtValidatorFactory
并实现 createValidator()
方法的类。此方法应返回将用于执行验证的验证器对象。
幸运的是,您无需自己实现验证器,因为 GWT 可以为您生成一个。要生成验证器,只需定义一个扩展 Validator
并包含 @GwtValidation
注释的接口。此注释要求您列出将在客户端验证的所有类。
public final class SampleValidatorFactory extends AbstractGwtValidatorFactory {
/**
* Validator marker for the Validation Sample project. Only the classes and groups listed
* in the {@link GwtValidation} annotation can be validated.
*/
@GwtValidation(Person.class)
public interface GwtValidator extends Validator {
}
@Override
public AbstractGwtValidator createValidator() {
return GWT.create(GwtValidator.class);
}
}
最后,我们必须告诉 GWT 使用延迟绑定来生成我们的验证器对象,将以下代码段添加到您的 module.gwt.xml
中。
<inherits name="org.hibernate.validator.HibernateValidator" />
<replace-with
class="com.google.gwt.sample.validation.client.SampleValidatorFactory">
<when-type-is class="javax.validation.ValidatorFactory" />
</replace-with>
验证约束
使用标准验证引导程序和默认工厂获取您对象的生成的 Validator
。您可以使用此验证器来验证整个 bean 对象或仅验证 bean 的特定属性。
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Person>> violations = validator.validate(person);
验证组
您也可以将对象上的约束放入“验证组”中,然后仅对特定约束子集执行验证。
除非另有说明,否则所有约束都自动属于 Default
组。创建新组就像创建一个空接口一样简单
/** Validates a minimal set of constraints */
public interface Minimal { }
如果您在客户端代码中使用除 Default
之外的任何验证组,则在验证器工厂的 @GwtValidation
注释中列出它们非常重要。
@GwtValidation(value = Person.class, groups = {Default.class, Minimal.class})
public interface GwtValidator extends Validator {
}
之后,您可以在任何约束的“groups”参数中指定此组
public class Address {
@NotEmpty(groups = Minimal.class)
@Size(max=50)
private String street;
@NotEmpty
private String city;
@NotEmpty(groups = {Minimal.class, Default.class})
private String zipCode;
...
}
从这里,您可以使用包含三个约束的 Default
组验证 Address
对象(“street”上的 @Size
,“city”上的 @NotEmpty
和“zipCode”上的 @NotEmpty
)
Address address = new Address();
validator.validate(address);
或者使用包含“street”上的 @NotEmpty
和“zipCode”上的 @NotEmpty
的 Minimal
组验证
validator.validate(address, Minimal.class);
最佳实践
验证组可用于指定在客户端运行哪些约束以及在服务器上运行哪些约束。您甚至可以创建与 GWT 不兼容的服务器端约束——只需确保从验证器工厂的 @GwtValidation
注释中省略任何仅服务器端的组,以避免编译问题。
@ServerConstraint(groups = ServerGroup.class)
public class Person {
@NotNull(groups = ClientGroup.class)
private String name;
}
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
// validate on the client
Set<ConstraintViolation<Person>> violations = validator.validate(person, Default.class, ClientGroup.class);
if (!violations.isEmpty()) {
// client-side violation(s) occurred
} else {
// client-side validation passed so check server-side
greetingService.serverSideValidate(person, new AsyncCallback<SafeHtml>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof ConstraintViolationException) {
// server-side violation
}
// some other issue
}
@Override
public void onSuccess(SafeHtml result) {
// server-side validations passed
}
}
}
不支持的功能
以下功能在 GWT 验证中不支持
- XML 配置
- 在客户端验证非 GWT 兼容类,例如
Calendar
ConstraintValidatorFactory
。约束验证器是使用GWT.create()
而不是使用它生成的。- 除默认提供程序以外的验证提供程序。始终使用
Validation.buildDefaultValidatorFactory()
或Validation.byDefaultProvider()
,而不是使用Validation.byProvider()
。 - 验证提供程序解析器。由于只有一个提供程序,因此使用提供程序解析器是不必要的。