简体   繁体   English

Spring Bean Validation @Valid 处理

[英]Spring Bean Validation @Valid handling

I have created a Spring MVC REST service using Bean Validation 1.2 with the following method:我使用 Bean Validation 1.2 创建了一个 Spring MVC REST 服务,方法如下:

@RequestMapping(value = "/valid")
public String validatedMethod(@Valid ValidObject object) {

}

If object isn't valid, Tomcat informs me that The request sent by the client was syntactically incorrect.如果对象无效,Tomcat 会通知我The request sent by the client was syntactically incorrect. and my validatedMethod is never called.并且我的validatedMethod方法永远不会被调用。

How can I get the message that was defined in the ValidObject bean?如何获取在ValidObject bean 中定义的消息? Should I use some filter or interceptor?我应该使用一些过滤器或拦截器吗?

I know that I can rewrite like below, to get the set of ConstraintViolation s from the injected Validator , but the above seems more neat...我知道我可以像下面这样重写,从注入的Validator获取一组ConstraintViolation ,但上面看起来更整洁......

@RequestMapping(value = "/valid")
public String validatedMethod(ValidObject object) {
    Set<ConstraintViolation<ValidObject>> constraintViolations = validator
            .validate(object);
    if (constraintViolations.isEmpty()) {
        return "valid";
    } else {
        final StringBuilder message = new StringBuilder();
        constraintViolations.forEach((action) -> {
            message.append(action.getPropertyPath());
            message.append(": ");
            message.append(action.getMessage());
        });
        return message.toString();
    }
}

I believe a better way of doing this is using ExceptionHandler .我相信这样做的更好方法是使用ExceptionHandler

In your Controller you can write ExceptionHandler to handle different exceptions.在您的Controller您可以编写ExceptionHandler来处理不同的异常。 Below is the code for the same:下面是相同的代码:

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ValidationFailureResponse validationError(MethodArgumentNotValidException ex) {
    BindingResult result = ex.getBindingResult();
    final List<FieldError> fieldErrors = result.getFieldErrors();

    return new ValidationFailureResponse((FieldError[])(fieldErrors.toArray(new FieldError[fieldErrors.size()])));
}

When you send a bad request to the Controller, the validator throws an exception of type MethodArgumentNotValidException .当您向 Controller 发送错误请求时,验证器会抛出MethodArgumentNotValidException类型的异常。 So the ideal way would be to write an exception handler to specifically handle this exception.所以理想的方法是编写一个异常处理程序来专门处理这个异常。

There you can create a beautiful response to tell the user of things which went wrong.在那里你可以创建一个漂亮的响应来告诉用户出了什么问题。 I advocate this, because you have to write this just once and many Controller methods can use it.我提倡这样做,因为您只需编写一次即可,许多Controller方法都可以使用它。 :) :)

UPDATE更新

When you use the @Valid annotation for a method argument in the Controller , the validator is invoked automatically and it tries to validate the object, if the object is invalid, it throws MethodArgumentNotValidException .当您对Controller的方法参数使用 @Valid 注释时,将自动调用验证器并尝试验证对象,如果对象无效,则抛出MethodArgumentNotValidException

If Spring finds an ExceptionHandler method for this exception it will execute the code inside this method.如果 Spring 找到此异常的ExceptionHandler方法,它将执行此方法中的代码。

You just need to make sure that the method above is present in your Controller.您只需要确保上述方法存在于您的控制器中。

Now there is another case when you have multiple Controller s where you want to validate the method arguments.现在还有另一种情况,当您有多个Controller想要验证方法参数时。 In this case I suggest you to create a ExceptionResolver class and put this method there.在这种情况下,我建议您创建一个ExceptionResolver类并将此方法放在那里。 Make your Controller s extend this class and your job is done.让你的Controller扩展这个类,你的工作就完成了。

Try this尝试这个

@RequestMapping(value = "/valid")
public String validatedMethod(@Valid ValidObject object, BindingResult result) {
    StringBuilder builder = new StringBuilder();
    List<FieldError> errors = result.getFieldErrors();
    for (FieldError error : errors ) {
       builder.append(error.getField() + " : " + error.getDefaultMessage());
    } 
    return builder.toString();
}

The answer by @dharam works. @dharam 的答案有效。 For users at Spring v4.3, Here's a nice implementation which uses a Custom Exception class to handle exception by type.对于 Spring v4.3 的用户,这是一个很好的实现,它使用自定义异常类按类型处理异常。

@RestControllerAdvice
public class CustomExceptionClass extends ResponseEntityExceptionHandler{
   @ExceptionHandler(value = MethodArgumentNotValidException.class)
   public ResponseEntity<Object> handleException(MethodArgumentNotValidException ex, WebRequest req){
   // Build your custom response object and access the exception message using ex.getMessage()
}
}

This method will enable handling all @Valid exceptions across all of your @Controller methods in a consolidated way此方法将启用以统一方式处理所有@Controller方法中的所有@Valid异常

When you use @Valid and doing bad request body Spring handle MethodArgumentNotValidException You must create special class and extend ResponseEntityExceptionHandler and override handleMethodArgumentNotValid Example当您使用 @Valid 并且做不好的请求主体时 Spring 处理 MethodArgumentNotValidException 您必须创建特殊类并扩展 ResponseEntityExceptionHandler 并覆盖 handleMethodArgumentNotValid 示例

@ControllerAdvice public class ControllerExceptionHandler extends ResponseEntityExceptionHandler { @ControllerAdvice 公共类 ControllerExceptionHandler 扩展 ResponseEntityExceptionHandler {

@ExceptionHandler(UserExistException.class)
public ResponseEntity<Object> handleUserExistException(
        UserExistException e, WebRequest request) {

    Map<String, Object> body = new LinkedHashMap<>();
    body.put("timestamp", LocalDateTime.now());
    body.put("status", HttpStatus.BAD_REQUEST.value());
    body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase());
    body.put("message", e.getMessage());
    body.put("path", request.getDescription(false).replace("uri=", ""));


    return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
}

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

    Map<String, Object> body = new LinkedHashMap<>();
    body.put("timestamp", LocalDateTime.now());
    body.put("status", HttpStatus.BAD_REQUEST.value());
    body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase());
    body.put("path", request.getDescription(false).replace("uri=", ""));
    return new ResponseEntity<>(body, headers, status);
}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM