Spring Data REST:自定义方法validation

我正在尝试使用带有@RepositoryRestResource注释和自定义方法实现注释的Spring Data REST存储库。 有2种情况:

1)我有使用@RepositoryRestResource注释的REST存储库,它被映射到/users端点。 另外,我有@RestController ,它被映射到同一个端点。 这导致@RepositoryRestResource中的方法(应该被暴露)不可见并且在它们上获得405结果。 但是,使用@Valid注释的方法validation正在使用@RestController方法。 例如,这工作:

 @ResponseBody @RequestMapping(value = "/users") public ResponseEntity signUp(@RequestBody @Valid final UserSignUpRequest userSignUpRequest) 

2)与REST存储库一起工作的控制器是@RepositoryRestController控制器。 这样,在@RepositoryRestController@RepositoryRestResource中声明的两个方法都可以正常工作。 但是JSR-303 @Valid注释方法停止工作,所以我不能使用@Valid注释 。 这个问题已经描述了DATAREST-593 。

任何想法如何解决两个问题中的至少一个? 主要思想是使用@RepositoryRestResource存储库以及自定义控制器方法和注释validation。

你也可以将它添加到你的@RepositoryRestController:

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

在这种情况下似乎没有好的解决方案,默认情况下不支持@Valid注释,请参阅DATAREST-593 。 这就是为什么,为了支持@Valid方法的@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 DATAREST-593 */ @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> 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> 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(); } }