Java Spring数据REST:自定义方法验证
我正在尝试使用Java Spring数据REST:自定义方法验证,java,spring,validation,spring-mvc,spring-data-rest,Java,Spring,Validation,Spring Mvc,Spring Data Rest,我正在尝试使用Spring数据REST存储库,并使用@RepositoryRestResource注释和自定义方法实现。 有两种情况: 1) 我用映射到/users端点的@RepositoryRestResource注释了REST存储库。此外,我还有映射到同一端点的@RestController这导致@RepositoryRestResource中的方法(应该公开)不可见,并获得405个结果。但是@Valid注释的方法验证正在@RestController方法上工作。e、 g.这项工作: @Re
Spring数据REST
存储库,并使用@RepositoryRestResource
注释和自定义方法实现。
有两种情况:
1) 我用映射到/users
端点的@RepositoryRestResource
注释了REST存储库。此外,我还有映射到同一端点的@RestController
这导致@RepositoryRestResource
中的方法(应该公开)不可见,并获得405个结果。但是@Valid
注释的方法验证正在@RestController
方法上工作。e、 g.这项工作:
@ResponseBody
@RequestMapping(value = "/users")
public ResponseEntity signUp(@RequestBody @Valid final UserSignUpRequest userSignUpRequest)
2) 与REST存储库一起工作的控制器是@RepositoryRestController
控制器。这样,在@RepositoryRestController
和@RepositoryRestResource
中声明的两种方法都可以工作。但是,JSR-303方法上的Valid注释停止工作,因此我无法使用@Valid
注释。这个问题已经描述过了
你知道如何至少解决两个问题中的一个吗?其主要思想是将
@RepositoryRestResource
存储库与自定义控制器方法和注释验证一起使用。在这种情况下似乎没有好的解决方案,默认情况下不以任何方式支持@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);
}
谢谢分享。您的解决方案产品的响应与从标准SDR存储库返回的响应非常不同。此外,在您的情况下,返回的是500 http状态,而不是4xx。一些建议?您可以在createErrorMessage方法中自定义响应。对于不同的状态代码,您只需要在相应的异常处理程序中捕获ValidationException。它可以工作,我得到一个400错误,但是响应的json与“标准”SDR存储库的json不同,有没有办法定制它?