Spring 数据 REST:自定义方法验证
Spring Data REST: custom methods validation
我正在尝试使用带有 @RepositoryRestResource
注释的 Spring Data REST
存储库以及自定义方法实现。
有2种情况:
1) 我有一个用 @RepositoryRestResource
注释的 REST 存储库,它映射到 /users
端点。另外,我有 @RestController
映射到同一个端点。 这导致 @RepositoryRestResource
中的方法(应该公开)不可见,并在其上获得 405 结果。 然而,使用 @Valid
注释的方法验证正在进行中@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
存储库与自定义控制器方法和注释验证一起使用。
似乎在这种情况下没有好的解决方案,而且 @Valid
注释在任何方面都默认不支持,请参阅 DATAREST-593。这就是为什么,为了支持 @RepositoryRestController
方法上的 @Valid
注释,我创建了以下 @ControllerAdvice
class:
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();
}
}
您也可以将其添加到您的@RepositoryRestController 中:
@Inject
private LocalValidatorFactoryBean validator;
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(validator);
}
我正在尝试使用带有 @RepositoryRestResource
注释的 Spring Data REST
存储库以及自定义方法实现。
有2种情况:
1) 我有一个用 @RepositoryRestResource
注释的 REST 存储库,它映射到 /users
端点。另外,我有 @RestController
映射到同一个端点。 这导致 @RepositoryRestResource
中的方法(应该公开)不可见,并在其上获得 405 结果。 然而,使用 @Valid
注释的方法验证正在进行中@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
存储库与自定义控制器方法和注释验证一起使用。
似乎在这种情况下没有好的解决方案,而且 @Valid
注释在任何方面都默认不支持,请参阅 DATAREST-593。这就是为什么,为了支持 @RepositoryRestController
方法上的 @Valid
注释,我创建了以下 @ControllerAdvice
class:
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();
}
}
您也可以将其添加到您的@RepositoryRestController 中:
@Inject
private LocalValidatorFactoryBean validator;
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(validator);
}