2015-02-24 130 views
11

当从json请求主体创建POJO的字段时,注释的Spring验证有效。但是,当我手动创建相同的对象(使用setter)并想要触发验证时,我不知道如何执行此操作。如何手动触发弹簧验证?

这里是注册类,它具有可以构建对象的Builder内部类。在构建方法中,我想引发spring验证。请滚动到底部并检查Builder.build()和Builder.valiate()方法以查看当前的实现。我使用javax.validation.Validator来触发验证,但如果可能的话,我更愿意使用spring验证。

package com.projcore.dao; 

import com.projcore.util.ToString; 
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 
import org.hibernate.validator.constraints.NotEmpty; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

import javax.validation.ConstraintViolation; 
import javax.validation.Valid; 
import javax.validation.Validation; 
import javax.validation.Validator; 
import javax.validation.constraints.Size; 
import java.util.List; 
import java.util.Set; 

/** 
* The data transfer object that contains the information of a Registration 
* and validation rules for attributes. 
*/ 
@JsonIgnoreProperties(ignoreUnknown = true) 
public final class Registration { 
    private static final Logger LOGGER = LoggerFactory.getLogger(Registration.class); 

    private String id; 

    @NotEmpty 
    @Size(max = 255) 
    private String messageId; 

    @NotEmpty 
    @Size(max = 255) 
    private String version; 

    @Size(max = 255) 
    private String system; 

    public Registration() { 
    } 

    private Registration(Builder builder) { 
     this.id = builder.id; 
     this.messageId = builder.messageId; 
     this.version = builder.version; 
     this.system = builder.system; 
    } 

    public static Builder getBuilder() { 
     return new Builder(); 
    } 

    public String getId() { 
     return id; 
    } 

    public void setId(String id) { 
     this.id = id; 
    } 

    public String getMessageId() { 
     return messageId; 
    } 

    public void setMessageId(String messageId) { 
     this.messageId = messageId; 
    } 

    public String getVersion() { 
     return version; 
    } 

    public void setVersion(String version) { 
     this.version = version; 
    } 

    public String getSystem() { 
     return system; 
    } 

    public void setSystem(String system) { 
     this.system = system; 
    } 

    @Override 
    public String toString() { 
     return ToString.create(this); 
    } 

    /** 
    * Builder pattern makes the object easier to construct in one line. 
    */ 
    public static class Builder { 

     private String id; 

     private String messageId; 

     private String version; 

     private String system; 

     private Builder() {} 

     public Builder id(String id) { 
      this.id = id; 
      return this; 
     } 

     public Builder messageId(String messageId) { 
      this.messageId = messageId; 
      return this; 
     } 


     public Builder version(String version) { 
      this.version = version; 
      return this; 
     } 

     public Builder system(String system) { 
      this.system = system; 
      return this; 
     } 

     public Registration build() { 
      Registration entry = new Registration(this); 

      // *** Would like to trigger spring validation here *** 
      Set violations = validate(entry); 
      if (violations.isEmpty()) 
       return entry; 
      else 
       throw new RuntimeException(violations.toString()); 
     } 

     private Set validate(Registration entry) { 
      Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); 
      Set<ConstraintViolation<Registration>> constraintViolations = validator.validate(entry); 
      return constraintViolations; 
     } 

    } 
} 

验证在这里工作正常:

@RequestMapping(method = RequestMethod.POST) 
@ResponseStatus(HttpStatus.CREATED) 
Registration create(@RequestBody @Valid Registration registration) 

解决方案:

删除Registraion.Builder.validate()。更新Registraion.Builder.build()来:

public Registration build() { 
     Registration entry = new Registration(this); 
     return (Registration) ValidatorUtil.validate(entry); 
    } 

ValidationUtil.java

package projcore.util; 

import com.ericsson.admcore.error.InvalidDataException; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.stereotype.Service; 
import org.springframework.validation.BeanPropertyBindingResult; 
import org.springframework.validation.Errors; 
import org.springframework.validation.beanvalidation.SpringValidatorAdapter; 

import javax.validation.Validation; 
import javax.validation.Validator; 
import java.util.Set; 

public class ValidatorUtil { 
    private static final Logger LOGGER = LoggerFactory.getLogger(ValidatorUtil.class); 
    private static final Validator javaxValidator = Validation.buildDefaultValidatorFactory().getValidator(); 
    private static final SpringValidatorAdapter validator = new SpringValidatorAdapter(javaxValidator); 

    public static Object validate(Object entry) { 
     Errors errors = new BeanPropertyBindingResult(entry, entry.getClass().getName()); 
     validator.validate(entry, errors); 
     if (errors == null || errors.getAllErrors().isEmpty()) 
      return entry; 
     else { 
      LOGGER.error(errors.toString()); 
      throw new InvalidDataException(errors.getAllErrors().toString(), errors); 
     } 
    } 
} 

InvalidDataException.java

package projcore.error; 

import org.springframework.validation.Errors; 

/** 
* This exception is thrown when the dao has invalid data. 
*/ 
public class InvalidDataException extends RuntimeException { 
    private Errors errors; 

    public InvalidDataException(String msg, Errors errors) { 
     super(msg); 
     setErrors(errors); 
    } 

    public Errors getErrors() { 
     return errors; 
    } 

    public void setErrors(Errors errors) { 
     this.errors = errors; 
    } 
} 

回答

14

Spring提供了JSR-303 Bean验证API的全面支持。这包括为将Spring JSR-303实现引导为Spring bean提供方便的支持。这允许在您的应用程序需要验证的地方注入javax.validation.Validator。

使用LocalValidatorFactoryBean配置默认JSR-303作为验证一个Spring bean:

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /> 

的基本配置上面会触发JSR-303使用其默认的引导机制来初始化。 JSR-303提供程序(如Hibernate验证程序)预计会出现在类路径中,并会自动检测到。

5.7.2.1注入验证

LocalValidatorFactoryBean implements both javax.validation.Validator and org.springframework.validation.Validator.您可能注入到这两个接口中的一个参考到需要调用验证逻辑豆。

注入到javax.validation.Validator参考,如果你喜欢与JSR-303的API直接工作:如果你的bean需要春天验证API

// JSR-303 Validator 
import javax.validation.Validator; 

@Service 
public class MyService { 

    @Autowired 
    private Validator validator; 

} 

注入到org.springframework.validation.Validator参考:

// Spring Validator 
import org.springframework.validation.Validator; 

@Service 
public class MyService { 

    @Autowired 
    private Validator validator; 

} 

这里是一个很好的例子 Using JSR 303 with "classic" Spring Validators (enter the SpringValidatorAdapter)

此链接非常有帮助。包装javax.validation.Validator org.springframework.validation.beanvalidation.SpringValidatorAdapter 帮助处理错误一致。你可以将其添加为一个答案,从而 我可以接受它

Spring doc here

+2

我觉得春天启动还提供了验证豆你(不,这是很难做到的自己)。 – 2015-02-24 22:01:52

+1

这是否意味着spring验证器只能用于@Service类来触发验证?我在网上做了足够的阅读,所以看到了这样的例子,但我仍然不明白我在POJO中如何做到这一点,因此,这个问题。我也知道如何触发自定义验证器的验证,但不知道如何在POJO中触发默认验证。如果可能的话,你能否在我所拥有的范围内提供具体的答案。 – 2015-02-25 14:50:10

+1

您可以将Validator注入到任何spring bean。 http://nonrepeatable.blogspot.com/2010/04/using-jsr-303-with-classic-spring.html有一个古老的例子。如果您仍有疑问,请点击此处 – iamiddy 2015-02-25 14:58:24