Java JSR303bean验证可以与SpringDataREST一起使用吗?

Java JSR303bean验证可以与SpringDataREST一起使用吗?,java,spring-boot,spring-data-jpa,spring-data-rest,Java,Spring Boot,Spring Data Jpa,Spring Data Rest,我从文档中了解到,我可以使用某些前缀声明验证器 我使用的是JSR303,因此我的域实体使用验证注释进行注释 我可以——如果可以,如何——将JSR303bean验证与SpringDataREST一起使用吗 PS:我正在使用Spring Boot//编辑-根据此答案的注释提供更多信息,并相应地更改代码 有关文件- 注释 //这使处理程序成为应用程序的全局处理程序 //如果这是在@controllerbean上,那么它将是控制器的本地 @控制器建议 //指定返回一个值 @ResponseStatus(

我从文档中了解到,我可以使用某些前缀声明验证器

我使用的是JSR303,因此我的域实体使用验证注释进行注释

我可以——如果可以,如何——将JSR303bean验证与SpringDataREST一起使用吗


PS:我正在使用Spring Boot

//编辑-根据此答案的注释提供更多信息,并相应地更改代码

有关文件-

注释

//这使处理程序成为应用程序的全局处理程序
//如果这是在@controllerbean上,那么它将是控制器的本地
@控制器建议
//指定返回一个值
@ResponseStatus(值=HttpStatus.BAD_请求)
//要处理哪个异常
@ExceptionHandler(ConstraintViolationException.class)
//指定使返回值为JSON。
@应答器
//该类用于建模我们返回的错误。
//(如果您觉得HashMap更干净,也可以使用它)
类约束ViolationModel{
这是一个Spring的异常处理程序,应该可以在Spring引导中正常工作

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;
        }
    }
}
import java.util.ArrayList;
导入java.util.List;
导入javax.servlet.http.HttpServletRequest;
导入javax.validation.ConstraintViolation;
导入javax.validation.ConstraintViolationException;
导入org.springframework.http.HttpStatus;
导入org.springframework.web.bind.annotation.ControllerAdvice;
导入org.springframework.web.bind.annotation.ExceptionHandler;
导入org.springframework.web.bind.annotation.ResponseBody;
导入org.springframework.web.bind.annotation.ResponseStatus;
@控制器建议
公共类例外处理控制器{
@ResponseStatus(值=HttpStatus.BAD_请求)
@ExceptionHandler(ConstraintViolationException.class)
public@ResponseBody列表handleConstraintViolation(
HttpServletRequest请求,最终约束ViolationException(异常){
ArrayList=新建ArrayList();
对于(约束冲突:异常
.getConstraintViolations()){
添加(新的ConstraintViolationModel(violation.getPropertyPath())
.toString(),违例。getMessage(),违例
.getInvalidValue());
}
退货清单;
}
私有静态类ConstraintViolationModel{
公共字符串字段;
公共字符串消息;
公共客体无效价值;
public ConstraintViolationModel(字符串字段、字符串消息、,
对象无效值){
this.field=字段;
this.message=消息;
this.invalidValue=invalidValue;
}
}
}
这似乎有效:

@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);
    }
}

要自定义spring数据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);
    }
}
这(
validatingListener.addValidator(“beforeCreate”,validator);
)并不能完全工作,因为验证只管理实体

因此,例如,如果您尝试对非实体进行验证,您会得到一个严重错误,即
org.springframework.beans.NotReadablePropertyException:bean类[…非实体的…]的无效属性“…”:Bean属性“..”不可读或具有无效的getter方法:getter的返回类型是否与setter的参数类型匹配?

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

@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);

是的,您的陈述是正确的,但此验证异常直接来自JPA,因此是500。当使用编码验证程序时,Spring Data Rest返回400,并有错误响应。我希望此行为也与注释一起出现。可能我的q不够清楚。再次感谢Zergleb。Spring Data Rest已包含此.Se的功能e也是我自己的答案。创建了自动/可配置的改进请求:另一种方法是在Spring数据REST文档中正确记录这一点:在方法configureValidatingRepositoryEventListener()中创建验证器实例的问题is-validator无法访问其他spring管理的bean。最好在应用程序上下文中定义validator bean,并在CustomRepositoryRestMVCCConfiguration中定义autowire,如上图所示。也许我来晚了一点,但如何使用事件并将@Valid放在参数上?如果使用spring Boot,请查看此问题。要保持Spring Boot自动配置,您应该扩展SpringBootRepositoryRestMvcConfiguration的可能重复项
@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);