Spring @RepositoryRestController中的验证

Spring @RepositoryRestController中的验证,spring,validation,spring-data,spring-restcontroller,spring-rest,Spring,Validation,Spring Data,Spring Restcontroller,Spring Rest,我想用javax注释验证我的@RepositoryRestController中的DTO@Valid。 但是,@RepositoryRestController当前不支持@Valid,您可以在该票据中看到: 如果我使用@RestController我的@Valid可以正常工作,但是我的@RepositoryRestResource将不再工作。我需要在我的@RestController中为每个功能(findOne()、findAll()等)手动编写一个方法。目前,我可以将@RepositoryRe

我想用javax注释验证我的
@RepositoryRestController
中的DTO
@Valid
。 但是,
@RepositoryRestController
当前不支持
@Valid
,您可以在该票据中看到:

如果我使用
@RestController
我的
@Valid
可以正常工作,但是我的
@RepositoryRestResource
将不再工作。我需要在我的
@RestController
中为每个功能(findOne()、findAll()等)手动编写一个方法。目前,我可以将
@RepositoryRestResource
与findAll()等方法的投影一起使用

如何在
@RepositoryRestController
中验证DTO

存储库:

@RepositoryRestResource(excerptProjection = ChipProjection.class)
public interface ChipRepository extends JpaRepository<Chip, Long> {

}
控制器:

@RepositoryRestController
public class ChipRestController {
    @Autowired
    ChipService chipService;

    @RequestMapping(value = "/chips", method = RequestMethod.POST)
    public @ResponseBody ChipHelper saveChip(@Valid @RequestBody ChipHelper chip, BindingResult result){
        List<FieldError> errors = result.getFieldErrors();
        //errors is always empty, @Valid not working
        chipService.save(chip);
        return chip;
    }
}

在这种情况下似乎没有好的解决方案,并且默认情况下,
@Valid
注释不受中所述任何方式的支持。因此,为了支持
@RepositoryRestController
方法上的
@Valid
注释,我创建了以下
@ControllerAdvice
类:

package com.tivoli.api.application.advice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

import javax.validation.Valid;
import javax.validation.ValidationException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

/**
 * Workaround class for making JSR-303 annotation validation work for controller method parameters.
 * Check the issue <a href="https://jira.spring.io/browse/DATAREST-593">DATAREST-593</a>
 */
@ControllerAdvice
public class RequestBodyValidationProcessor extends RequestBodyAdviceAdapter {

    private final Validator validator;

    public RequestBodyValidationProcessor(@Autowired final Validator validator) {
        this.validator = validator;
    }

    @Override
    public boolean supports(final MethodParameter methodParameter, final Type targetType, final Class<? extends
            HttpMessageConverter<?>> converterType) {
        final Annotation[] parameterAnnotations = methodParameter.getParameterAnnotations();
        for (final Annotation annotation : parameterAnnotations) {
            if (annotation.annotationType().equals(Valid.class)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public Object afterBodyRead(final Object body, final HttpInputMessage inputMessage, final MethodParameter
            parameter, final Type targetType, final Class<? extends HttpMessageConverter<?>> converterType) {
        final Object obj = super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
        final BindingResult bindingResult = new BeanPropertyBindingResult(obj, obj.getClass().getCanonicalName());
        validator.validate(obj, bindingResult);
        if (bindingResult.hasErrors()) {
            throw new ValidationException(createErrorMessage(bindingResult));
        }

        return obj;
    }

    private String createErrorMessage(final BindingResult bindingResult) {
        final StringBuilder stringBuilder = new StringBuilder("Invalid parameters specified.");
        if (bindingResult.getFieldErrors() != null && !bindingResult.getFieldErrors().isEmpty()) {
            stringBuilder.append(" Fields:");
            bindingResult.getFieldErrors().forEach(fieldError -> stringBuilder
                    .append(" [ ")
                    .append(fieldError.getField())
                    .append(" : ")
                    .append(fieldError.getRejectedValue())
                    .append(" ] "));
        } else if (bindingResult.getAllErrors() != null && !bindingResult.getAllErrors().isEmpty()) {
            final ObjectError objectError = bindingResult.getAllErrors().get(0); // get the first error
            stringBuilder.append(" Message: ")
                    .append(objectError.getDefaultMessage());
        }

        return stringBuilder.toString();
    }
}
package com.tivoli.api.application.advice;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.core.MethodParameter;
导入org.springframework.http.HttpInputMessage;
导入org.springframework.http.converter.HttpMessageConverter;
导入org.springframework.validation.BeanPropertyBindingResult;
导入org.springframework.validation.BindingResult;
导入org.springframework.validation.ObjectError;
导入org.springframework.validation.Validator;
导入org.springframework.web.bind.annotation.ControllerAdvice;
导入org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
导入javax.validation.Valid;
导入javax.validation.ValidationException;
导入java.lang.annotation.annotation;
导入java.lang.reflect.Type;
/**
*使JSR-303注释验证适用于控制器方法参数的解决方案类。
*检查问题
*/
@控制器建议
公共类RequestBodyValidationProcessor扩展了RequestBodyAdviceAdapter{
私人最终验证器;
public RequestBodyValidationProcessor(@Autowired final Validator Validator){
this.validator=验证程序;
}
@凌驾
公共布尔支持(final MethodParameter MethodParameter、final类型targetType、final类>converterType){
最终注释[]parameterAnnotations=methodParameter.getParameterAnnotations();
对于(最终注释:参数注释){
if(annotation.annotationType().equals(Valid.class)){
返回true;
}
}
返回false;
}
@凌驾
公共对象afterBodyRead(最终对象体、最终HttpInputMessage inputMessage、最终方法参数
参数,最终类型targetType,最终类>转换器类型){
final Object obj=super.afterBodyRead(body,inputMessage,参数,targetType,converterType);
final BindingResult BindingResult=新的BeanPropertyBindingResult(obj,obj.getClass().getCanonicalName());
validator.validate(obj,bindingResult);
if(bindingResult.hasErrors()){
抛出新的ValidationException(createErrorMessage(bindingResult));
}
返回obj;
}
私有字符串createErrorMessage(最终BindingResult BindingResult){
最终StringBuilder StringBuilder=新StringBuilder(“指定的参数无效”);
if(bindingResult.getFieldErrors()!=null&!bindingResult.getFieldErrors().isEmpty()){
追加(“字段:”);
bindingResult.getFieldErrors().forEach(fieldError->stringBuilder
.附加(“[”)
.append(fieldError.getField())
.附加(“:”)
.append(fieldError.getRejectedValue())
。附加(“]”);
}else if(bindingResult.getAllErrors()!=null&&!bindingResult.getAllErrors().isEmpty()){
final ObjectError ObjectError=bindingResult.getAllErrors().get(0);//获取第一个错误
附加(“消息:”)
.append(objectError.getDefaultMessage());
}
返回stringBuilder.toString();
}
}
这个答案:对我有用:

只需将此添加到您的
@RepositoryRestController

@Inject
private LocalValidatorFactoryBean validator;

@InitBinder
protected void initBinder(WebDataBinder binder) {
    binder.addValidators(validator);
}

有效注释成功了吗?Hy,Yuriy。你的解决方案很有效,我认为这是我现在能找到的最好的解决办法。三年过去了,不幸的是,这个问题仍然是现实的。我建议使用带有“basePackageClasses”设置的
@ControllerAdvice
,该建议仅适用于特定控制器(例如
@Controllers
&
@restcollers
)请注意,返回到UI的错误消息将不同于SpringDataREST默认提供的错误消息。我认为这是非常重要的。
package com.tivoli.api.application.advice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

import javax.validation.Valid;
import javax.validation.ValidationException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

/**
 * Workaround class for making JSR-303 annotation validation work for controller method parameters.
 * Check the issue <a href="https://jira.spring.io/browse/DATAREST-593">DATAREST-593</a>
 */
@ControllerAdvice
public class RequestBodyValidationProcessor extends RequestBodyAdviceAdapter {

    private final Validator validator;

    public RequestBodyValidationProcessor(@Autowired final Validator validator) {
        this.validator = validator;
    }

    @Override
    public boolean supports(final MethodParameter methodParameter, final Type targetType, final Class<? extends
            HttpMessageConverter<?>> converterType) {
        final Annotation[] parameterAnnotations = methodParameter.getParameterAnnotations();
        for (final Annotation annotation : parameterAnnotations) {
            if (annotation.annotationType().equals(Valid.class)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public Object afterBodyRead(final Object body, final HttpInputMessage inputMessage, final MethodParameter
            parameter, final Type targetType, final Class<? extends HttpMessageConverter<?>> converterType) {
        final Object obj = super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
        final BindingResult bindingResult = new BeanPropertyBindingResult(obj, obj.getClass().getCanonicalName());
        validator.validate(obj, bindingResult);
        if (bindingResult.hasErrors()) {
            throw new ValidationException(createErrorMessage(bindingResult));
        }

        return obj;
    }

    private String createErrorMessage(final BindingResult bindingResult) {
        final StringBuilder stringBuilder = new StringBuilder("Invalid parameters specified.");
        if (bindingResult.getFieldErrors() != null && !bindingResult.getFieldErrors().isEmpty()) {
            stringBuilder.append(" Fields:");
            bindingResult.getFieldErrors().forEach(fieldError -> stringBuilder
                    .append(" [ ")
                    .append(fieldError.getField())
                    .append(" : ")
                    .append(fieldError.getRejectedValue())
                    .append(" ] "));
        } else if (bindingResult.getAllErrors() != null && !bindingResult.getAllErrors().isEmpty()) {
            final ObjectError objectError = bindingResult.getAllErrors().get(0); // get the first error
            stringBuilder.append(" Message: ")
                    .append(objectError.getDefaultMessage());
        }

        return stringBuilder.toString();
    }
}
@Inject
private LocalValidatorFactoryBean validator;

@InitBinder
protected void initBinder(WebDataBinder binder) {
    binder.addValidators(validator);
}