使用@Valid @RequestBody 的用意在于抛出notvalid的异常

来源:互联网 发布:用数据库统计访问次数 编辑:程序博客网 时间:2024/05/18 15:05

Different ways of validating @RequestBody in Spring MVC 3.2 with @Valid annotation

In spring MVC the @RequestBody annotation indicates a method parameter should be bound to a body of the request. @RequestBody parameter can treated as any other parameter in a@RequestMapping method and therefore it can also be validated by a standard validation mechanism. In this post I will show 2 ways of validating the @RequestBody parameter in your Spring MVC application.

In my sample application I want to create a new Task with not blank name and description. In order to do it I create an API endpoint that supports POST method and accepts Task as JSON.

Tip: To bootstrap the application I used: spring-mvc-quickstart-archetype .

Let's start with the task:

[java] view plain copy
  1. public class Task {  
  2.   
  3.     @NotBlank(message = "Task name must not be blank!")  
  4.     private String name;  
  5.   
  6.     @NotBlank(message = "Task description must not be blank!")  
  7.     private String description;  
  8.   
  9.     public Task() {  
  10.     }  
  11.   
  12.     public Task(String name, String description) {  
  13.         this.name = name;  
  14.         this.description = description;  
  15.     }  
  16.   
  17.     public String getName() {  
  18.         return name;  
  19.     }  
  20.   
  21.     public void setName(String name) {  
  22.         this.name = name;  
  23.     }  
  24.   
  25.     public String getDescription() {  
  26.         return description;  
  27.     }  
  28.   
  29.     public void setDescription(String description) {  
  30.         this.description = description;  
  31.     }  
  32.   
  33. }  
To handle the task we need a @Controller:
[java] view plain copy
  1. @Controller  
  2. @RequestMapping(value = "task")  
  3. public class TaskController {  
  4.   
  5.     @RequestMapping(value = "", method = RequestMethod.POST)  
  6.     @ResponseBody  
  7.     public Task post(Task task) {  
  8.         // create a task     
  9.     }  
  10. }  
The next thing we need to do is the validation. So let's do it.

Validation with @ExceptionHandler

As of Spring 3.1 the @RequestBody method argument can be annotated with @Valid or @Validated annotation to invoke automatic validation. In such a case Spring automatically performs the validation and in case of error MethodArgumentNotValidException is thrown. Optional @ExceptionHandler method may be easily created to add custom behavior for handling this type of exception. MethodArgumentNotValidException holds both the parameter that failed the validation and the result of validation. Now, we can easily extract error messages and return it in an error object as JSON.

[java] view plain copy
  1. @Controller  
  2. @RequestMapping(value = "task")  
  3. public class TaskController {  
  4.   
  5.     @RequestMapping(value = "", method = RequestMethod.POST)  
  6.     @ResponseBody  
  7.     public Task post(@Valid @RequestBody Task task) {         
  8.         // in case of a validation error, MethodArgumentNotValidException will be thrown.  
  9.     }  
  10.   
  11.     @ExceptionHandler  
  12.     @ResponseBody  
  13.     @ResponseStatus(value = HttpStatus.BAD_REQUEST)  
  14.     public Error handleException(MethodArgumentNotValidException exception) {  
  15.         return new ApiErrors(exception.getBindingResult());  
  16.     }  
  17.   
  18. }  

Exception handler method does not need to be located in the same controller class. It can be a global handler for all you API calls.

Validation with Errors/BindingResult object

As of Spring 3.2 @RequestBody method argument may be followed by Errors object, hence allowing handling of validation errors in the same @RequestMapping. Let's look at the code:

[java] view plain copy
  1. @Controller  
  2. @RequestMapping(value = "task")  
  3. public class TaskController {  
  4.   
  5.     @RequestMapping(value = "", method = RequestMethod.POST)  
  6.     @ResponseBody  
  7.     public ResponseEntity post(@Valid @RequestBody Task task, Errors errors) {  
  8.         if (errors.hasErrors()) {  
  9.             return new ResponseEntity(new ApiErrors(errors), HttpStatus.BAD_REQUEST);  
  10.         }  
  11.         return new ResponseEntity(task.save(), HttpStatus.CREATED);  
  12.     }  
  13. }  

Both approaches produce the same result in the above example. Which is better? I don't know yet. And do you?

原创粉丝点击