【问题标题】:Can JSR 303 Bean Validation be used with Spring Data Rest?JSR 303 Bean Validation 可以与 Spring Data Rest 一起使用吗?
【发布时间】:2014-10-02 22:24:12
【问题描述】:

我从文档 http://docs.spring.io/spring-data/rest/docs/2.1.2.RELEASE/reference/html/validation-chapter.html 了解到,我可以声明带有某些前缀的验证器。

我正在使用 JSR 303,因此我的域实体使用验证注释进行注释。

可以 - 如果可以,如何 - 我将 JSR 303 Bean Validation 与 Spring Data Rest 结合使用?

PS:我正在使用 Spring Boot

【问题讨论】:

标签: java spring-boot spring-data-jpa spring-data-rest


【解决方案1】:

这个 (validatingListener.addValidator("beforeCreate", validator);) 并没有真正完全起作用,因为验证只管理实体。

因此,例如,如果您尝试对非实体进行验证,您会收到一个令人讨厌的错误 org.springframework.beans.NotReadablePropertyException: Invalid property '...' of bean class [... the non-entity one ...]: Bean property '....' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

虽然显然更费力,但您可以直接在 Validator 上手动执行验证,例如:

@Component("beforeSaveListingValidator")
public class BeforeSaveListingValidator implements Validator {

    @Autowired
    private LocalValidatorFactoryBean validator;

    @Override
    public void validate(Object object, Errors errors) {
        BindingResult bindingResult = new BeanPropertyBindingResult(object, errors.getObjectName());
        validator.validate(object, bindingResult);
        errors.addAllErrors(bindingResult);

【讨论】:

    【解决方案2】:

    要自定义 spring data-rest 配置,请注册 RepositoryRestConfigurer(或扩展 RepositoryRestConfigurerAdapter)并针对您的特定用例实现或覆盖 configureValidatingRepositoryEventListener 方法。

    public class CustomRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter {
    
        @Autowired
        private Validator validator;
    
        @Override
        public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
            validatingListener.addValidator("beforeCreate", validator);
            validatingListener.addValidator("beforeSave", validator);
        }
    }
    

    【讨论】:

      【解决方案3】:

      这似乎有效:

      @Configuration
      protected static class CustomRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
      
          @Autowired
          private Validator validator;
      
          @Override
          protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
              validatingListener.addValidator("beforeCreate", validator);
              validatingListener.addValidator("beforeSave", validator);
          }
      }
      

      【讨论】:

      • 创建了自动/可配置的改进请求:jira.spring.io/browse/DATAREST-370
      • 另一种方法是在 Spring Data REST 文档中正确记录这一点:jira.spring.io/browse/DATAREST-372
      • 在方法 configureValidatingRepositoryEventListener() 中创建验证器实例的问题是 - 验证器无法访问其他 Spring 托管 bean。最好在应用程序上下文中定义验证器 bean,并在 CustomRepositoryRestMvcConfiguration 中自动装配,如上所示。
      • 也许我参加聚会有点晚了,但是使用事件listeners 并将@Valid 放在参数上怎么样
      • 如果你使用的是Spring Boot,请看这个问题github.com/spring-projects/spring-boot/issues/2392。要保持 Spring Boot 自动配置,您应该扩展 SpringBootRepositoryRestMvcConfiguration
      【解决方案4】:

      //编辑 - 根据对此答案的评论提供更多信息并相应地更改代码。

      相关文档 - http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

      注意事项

      //This is making the handler global for the application
      //If this were on a @Controller bean it would be local to the controller
      @ControllerAdvice
      
      //Specifies to return a 400
      @ResponseStatus(value = HttpStatus.BAD_REQUEST)
      
      //Which exception to handle
      @ExceptionHandler(ConstraintViolationException.class)
      
      //Specifies to make the return value JSON.
      @ResponseBody
      
      //This class if for modeling the error we return.
      //(Could use HashMap<String, Object> also if you feel it's cleaner)
      class ConstraintViolationModel {
      

      这是一个 Spring 的异常处理程序,应该可以在 Spring Boot 中正常工作。

      import java.util.ArrayList;
      import java.util.List;
      
      import javax.servlet.http.HttpServletRequest;
      import javax.validation.ConstraintViolation;
      import javax.validation.ConstraintViolationException;
      
      import org.springframework.http.HttpStatus;
      import org.springframework.web.bind.annotation.ControllerAdvice;
      import org.springframework.web.bind.annotation.ExceptionHandler;
      import org.springframework.web.bind.annotation.ResponseBody;
      import org.springframework.web.bind.annotation.ResponseStatus;
      
      @ControllerAdvice
      public class ExceptionHandlingController {
          @ResponseStatus(value = HttpStatus.BAD_REQUEST)
          @ExceptionHandler(ConstraintViolationException.class)
          public @ResponseBody List<ConstraintViolationModel> handleConstraintViolation(
                  HttpServletRequest req, final ConstraintViolationException exception) {
              ArrayList<ConstraintViolationModel> list = new ArrayList<ConstraintViolationModel>();
              for (ConstraintViolation<?> violation : exception
                      .getConstraintViolations()) {
                  list.add(new ConstraintViolationModel(violation.getPropertyPath()
                          .toString(), violation.getMessage(), violation
                          .getInvalidValue()));
              }
              return list;
          }
      
          private static class ConstraintViolationModel {
              public String field;
              public String message;
              public Object invalidValue;
      
              public ConstraintViolationModel(String field, String message,
                      Object invalidValue) {
                  this.field = field;
                  this.message = message;
                  this.invalidValue = invalidValue;
              }
          }
      }
      

      【讨论】:

      • 是的,您的陈述是正确的,但此验证异常直接来自 JPA,因此是 500。当使用编码验证器时,Spring Data Rest 返回 400 并响应错误。我希望这种行为也带有注释。可能我的q不够清楚。
      • 再次感谢 Zergleb。 Spring Data REST 已经包含了这个功能。另请参阅我自己的答案。
      猜你喜欢
      • 2020-04-26
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2011-12-28
      • 2012-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多