【问题标题】:Manually call Spring Annotation Validation手动调用 Spring Annotation Validation
【发布时间】:2013-10-12 00:07:07
【问题描述】:

我正在使用 Hibernate 和 Spring Annotations 进行大量验证,如下所示:

public class Account {
    @NotEmpty(groups = {Step1.class, Step2.class})
    private String name;

    @NotNull(groups = {Step2.class})
    private Long accountNumber;

    public interface Step1{}
    public interface Step2{}
}

然后在控制器中在参数中调用它:

public String saveAccount(@ModelAttribute @Validated({Account.Step1.class}) Account account, BindingResult result) {
   //some more code and stuff here
   return "";
}

但我想根据控制器方法中的一些逻辑来决定使用的组。有没有办法手动调用验证? result = account.validate(Account.Step1.class) 之类的东西?

我知道创建您自己的 Validator 类,但这是我想避免的,我宁愿只使用类变量本身的注释。

【问题讨论】:

    标签: java spring hibernate validation spring-mvc


    【解决方案1】:

    Spring提供了LocalValidatorFactoryBean,它实现了Spring的SmartValidator接口以及Java Bean ValidationValidator接口。

    // org.springframework.validation.SmartValidator - implemented by LocalValidatorFactoryBean
    @Autowired
    SmartValidator validator;
    
    public String saveAccount(@ModelAttribute Account account, BindingResult result) {
        // ... custom logic
        validator.validate(account, result, Account.Step1.class);
        if (result.hasErrors()) {
            // ... on binding or validation errors
        } else {
            // ... on no errors
        }
        return "";
    }
    

    【讨论】:

    • 您从哪里获得BindingResult 值?
    • 那是Spring MVC注入的。好吧...我在回答中假设我们正在谈论 MVC 处理程序方法,因为 ModelAttribute 在任何其他上下文中都没有意义。
    • 这是一个 ValidatorFactory bean,而不是验证器 FactoryBeanFactoryBean 是 Spring 的东西,ValidatorFactory 是 Java EE bean 验证的东西。
    • @M.Justin 你是对的,我已经从答案中删除了我的旧咆哮。
    【解决方案2】:

    这是来自JSR 303 spec的代码示例

    Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    
    Driver driver = new Driver();
    driver.setAge(16);
    Car porsche = new Car();
    driver.setCar(porsche);
    
    
    Set<ConstraintViolation<Driver>> violations = validator.validate( driver );
    

    所以是的,您可以从验证器工厂获取验证器实例并自己运行验证,然后检查是否存在违规行为。您可以在 javadoc for Validator 中看到,它还将接受一组要验证的组。

    显然这直接使用 JSR-303 验证而不是通过 Spring 验证,但我相信如果在类路径中找到 Spring 验证注解将使用 JSR-303

    【讨论】:

    • 问题是,如果您使用 Spring MVC,您可能需要 BindingResult / Errors 而不是 ConstraintViolations。所以虽然你的答案是正确的,但它并不适合这个问题。
    • 这可能对 Spring Rest Controller 有用。当violations 不为空时,您可以抛出new ConstraintViolationException(violations);。这将与 Spring @Validated 引起的完全相同,并且可以由 @ControllerAdvice 处理。
    • 我是新手,但这似乎不起作用。它给出了一个 HV000183 异常,无法初始化 'javax.el.E​​xpressionFactory'。
    【解决方案3】:

    如果您已正确配置所有内容,则可以这样做:

    @Autowired
    Validator validator;
    

    然后你可以用它来验证你的对象。

    【讨论】:

      【解决方案4】:

      此链接提供了在 Spring 应用程序中使用验证的非常好的示例。 https://reflectoring.io/bean-validation-with-spring-boot/

      我在本文中找到了一个以编程方式运行验证的示例。

      class MyValidatingService {
      
        void validatePerson(Person person) {
          ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
          Validator validator = factory.getValidator();
          Set<ConstraintViolation<Person>> violations = validator.validate(person);
          if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
          }
        } 
      }
      

      它会抛出500 状态,因此建议使用自定义异常处理程序进行处理。

      @ControllerAdvice(annotations = RestController.class)
      public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler {
          @ExceptionHandler(ConstraintViolationException.class)
          public ResponseEntity<CustomErrorResponse> constraintViolationException(HttpServletResponse response, Exception ex) throws IOException {
              CustomErrorResponse errorResponse = new CustomErrorResponse();
              errorResponse.setTimestamp(LocalDateTime.now());
              errorResponse.setStatus(HttpStatus.BAD_REQUEST.value());
              errorResponse.setError(HttpStatus.BAD_REQUEST.getReasonPhrase());
              errorResponse.setMessage(ex.getMessage());
              return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
          }
      }
      

      第二个例子来自https://www.mkyong.com/spring-boot/spring-rest-error-handling-example/

      更新: 不推荐使用验证是持久层: https://twitter.com/odrotbohm/status/1055015506326052865

      【讨论】:

        【解决方案5】:

        除了@digitaljoel 的回答之外,一旦您获得了一组违规行为,您就可以抛出 ConstraintViolationException。

        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
                Set<ConstraintViolation<NotionalProviderPaymentDTO>> violations = validator.validate( notionalProviderPaymentDTO );
        
                if(!violations.isEmpty()) {
                    throw new ConstraintViolationException(violations);
                }
        

        您可以创建自己的异常映射器来处理 ConstraintViolationException 并将错误消息发送到客户端。

        【讨论】:

          【解决方案6】:

          还有:

          @Autowired
          @Qualifier("mvcValidator")
          Validator validator;
          
          ...
          violations = validator.validate(account);
          

          【讨论】:

            【解决方案7】:
            import javax.validation.Validator;
            import javax.validation.ConstraintViolation;
            
            public class{
                @Autowired
                private Validator validator;
                   .
                   .
                public void validateEmployee(Employee employee){
            
                    Set<ConstraintViolation<Employee>> violations = validator.validate(employee);
                    if(!violations.isEmpty()) {
                        throw new ConstraintViolationException(violations);
                    }
                }
            }
            

            这里,'Employee' 是一个 pojo 类,'employee' 是它的对象

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-07-17
              • 2016-06-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-03-01
              相关资源
              最近更新 更多