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