使用@Valid @RequestBody 的用意在於拋出notvalid的異常

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:

public class Task {

    @NotBlank(message = "Task name must not be blank!")
    private String name;

    @NotBlank(message = "Task description must not be blank!")
    private String description;

    public Task() {
    }

    public Task(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}
To handle the task we need a @Controller:
@Controller
@RequestMapping(value = "task")
public class TaskController {

    @RequestMapping(value = "", method = RequestMethod.POST)
    @ResponseBody
    public Task post(Task task) {
        // create a task   
    }
}
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.

@Controller
@RequestMapping(value = "task")
public class TaskController {

    @RequestMapping(value = "", method = RequestMethod.POST)
    @ResponseBody
    public Task post(@Valid @RequestBody Task task) {       
        // in case of a validation error, MethodArgumentNotValidException will be thrown.
    }

    @ExceptionHandler
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Error handleException(MethodArgumentNotValidException exception) {
        return new ApiErrors(exception.getBindingResult());
    }

}

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:

@Controller
@RequestMapping(value = "task")
public class TaskController {

    @RequestMapping(value = "", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity post(@Valid @RequestBody Task task, Errors errors) {
        if (errors.hasErrors()) {
            return new ResponseEntity(new ApiErrors(errors), HttpStatus.BAD_REQUEST);
        }
        return new ResponseEntity(task.save(), HttpStatus.CREATED);
    }
}

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章