Hibernate有很多值得学习的地方,这里我们主要介绍Hibernate ClassValidator实例,包括介绍Spring MVC 控制器使用的 CreditCardValidator等方面。
创建一个Hibernate ClassValidator实例
这个类进行实例化的代价可能会很高,因此最好只对希望进行验证的每个类来进行实例化。一种方法是创建一个实用工具类,对每个模型对象存储一个Hibernate ClassValidator实例,如下所示:
处理验证的实用工具类
- /**
- * Handles validations based on the Hibernate Annotations Validator framework.
- * @author Ted Bergeron
- * @version $Id: AnnotationValidator.java,v 1.5 2006/01/20 17:34:09 ted Exp $
- */
- public class AnnotationValidator {
- private static Log log = LogFactory.getLog(AnnotationValidator.class);
- // It is considered a good practice to execute these lines once and
- // cache the validator instances.
- public static final ClassValidator<Customer> CUSTOMER_VALIDATOR =
- new ClassValidator<Customer>(Customer.class);
- public static final ClassValidator<CreditCard> CREDIT_CARD_VALIDATOR =
- new ClassValidator<CreditCard>(CreditCard.class);
- private static ClassValidator<? extends BaseObject> getValidator(Class<?
- extends BaseObject> clazz) {
- if (Customer.class.equals(clazz)) {
- return CUSTOMER_VALIDATOR;
- }
- else if (CreditCard.class.equals(clazz)) {
- return CREDIT_CARD_VALIDATOR;
- }
- else {
- throw new IllegalArgumentException("Unsupported class was passed.");
- }
- }
- public static InvalidValue[] getInvalidValues(BaseObject modelObject) {
- String nullnullProperty = null;
- return getInvalidValues(modelObject, nullProperty);
- }
- public static InvalidValue[] getInvalidValues(BaseObject modelObject,
- String property) {
- Class<? extends BaseObject>clazz = modelObject.getClass();
- ClassValidator validator = getValidator(clazz);
- InvalidValue[] validationMessages;
- if (property == null) {
- validationMessages = validator.getInvalidValues(modelObject);
- }
- else {
- // only get invalid values for specified property.
- // For example, "city" applies to getCity() method.
- validationMessages = validator.getInvalidValues(modelObject, property);
- }
- return validationMessages;
- }
- }
创建了两个Hibernate ClassValidator,一个用于 Customer,另外一个用于 CreditCard。这两个希望进行验证的类可以调用 getInvalidValues(BaseObject modelObject),会返回 InvalidValue[]。这则会返回一个包含模型对象实例错误的数组。另外,这个方法也可以通过提供一个特定的属性名来调用,这样做会只返回与该域有关的错误。
在使用 Spring MVC 和 Hibernate Validator 时,为信用卡创建一个验证过程变得非常简单,如下所示:
Spring MVC 控制器使用的 CreditCardValidator
- /**
- * Performs validation of a CreditCard in Spring MVC.
- *
- * @author Ted Bergeron
- * @version $Id: CreditCardValidator.java,v 1.2 2006/02/10 21:53:50 ted Exp $
- */
- public class CreditCardValidator implements Validator {
- private CreditCardService creditCardService;
- public void setCreditCardService(CreditCardService service) {
- this.creditCardService = service;
- }
- public boolean supports(Class clazz) {
- return CreditCard.class.isAssignableFrom(clazz);
- }
- public void validate(Object object, Errors errors) {
- CreditCard creditCard = (CreditCard) object;
- InvalidValue[] invalids = AnnotationValidator.getInvalidValues(creditCard);
- // Perform "expensive" validation only if no simple errors found above.
- if (invalids == null || invalids.length == 0) {
- boolean validCard = creditCardService.validateCreditCard(creditCard);
- if (!validCard) {
- errors.reject("error.creditcard.invalid");
- }
- }
- else {
- for (InvalidValue invalidValue : invalids) {
- errors.rejectValue(invalidValue.getPropertyPath(),
- null, invalidValue.getMessage());
- }
- }
- }
- }
validate() 方法只需要将 creditCard 实例传递给这个验证过程,从而返回 InvalidValue 数组。如果发现了一个或多个这种简单错误,那么就可以将 Hibernate 的 InvalidValue 数组转换成 Spring 的 Errors 对象。如果用户已经创建了这个信用卡并且没有出现任何简单错误,就可以将更加彻底的验证委托给服务层进行。这一层可以与商业服务提供者一起对信用卡进行验证。
现在我们已经看到这个简单的模型层注释是如何平衡到控制器、DAO 和 DBMS 层的验证的。在 Hibernate Doclet 和 Commons Validator 中发现的验证逻辑的重合现在都已经统一到模型中了。尽管这是一个非常受欢迎的改进,但是视图层传统上来说一直是最需要进行详细验证的地方。
【编辑推荐】