简体   繁体   中英

How to handle @Valid violations in the RequestMapping?

I have the following Rest Controller in Java/Spring. The validation of constraints are checked. However, these are completed before it reaches the body of my 'bar' method. How can I handle a violation case? Can I customize the 400 response bodies?

@RestController
@RequestMapping("foo")
public class FooController {

    @RequestMapping(value = "bar", method = RequestMethod.POST)
    public ResponseEntity<Void> bar(@RequestBody @Valid Foo foo) {
        //body part
        return ResponseEntity.status(HttpStatus.OK).build();
    }

}

You should use controllerAdvice, here is an exemple (in kotlin) :

@ControllerAdvice
open class ExceptionAdvice {

    @ExceptionHandler(MethodArgumentNotValidException::class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    open fun methodArgumentNotValidExceptionHandler(request: HttpServletRequest, e: MethodArgumentNotValidException): ErrorDto {

        val errors = HashMap<String, String>()

        for (violation in e.bindingResult.allErrors) {
            if (violation is FieldError) {
                errors.put(violation.field, violation.defaultMessage)
            }
        }

        return ErrorDto(errors)
    }

    @ExceptionHandler(BindException::class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    open fun bindExceptionHandler(request: HttpServletRequest, e: BindException): ErrorDto {

        val errors = HashMap<String, String>()

        for (violation in e.bindingResult.allErrors) {
            if (violation is FieldError) {
                errors.put(violation.field, violation.defaultMessage)
            }
        }

        return ErrorDto(errors)
    }
}

It allows to handle exception thrown by your controllers, including validation exceptions.

You can add BindingResult as parameter at the end into method signature.

@RequestMapping(value = "bar", method = RequestMethod.POST)
public ResponseEntity<Void> bar(@RequestBody @Valid Foo foo, BindingResult bindingResult) 
{
    if (bindingResult.hasErrors()) {
        //do something if errors occured
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
    } 

    //body part
    return ResponseEntity.status(HttpStatus.OK).build();
}

Annotate Foo object properly with hibernate annotations and it will work automatically. For example, few validations may be

@NotEmpty(message = "first name must not be empty")
private String firstName;

@NotEmpty(message = "last name must not be empty")
private String lastName;

@NotEmpty(message = "email must not be empty")
@Email(message = "email should be a valid email")
private String email;

To handle other errors, write @ControllerAdvice

@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler
{
    @ExceptionHandler(RecordNotFoundException.class)
    public final ResponseEntity<Object> handleUserNotFoundException(RecordNotFoundException ex, WebRequest request) {
        List<String> details = new ArrayList<>();
        details.add(ex.getLocalizedMessage());
        ErrorResponse error = new ErrorResponse("Record Not Found", details);
        return new ResponseEntity(error, HttpStatus.NOT_FOUND);
    }
}

And add @Valid annotation like this while accepting request body.

@PostMapping(value = "/employees")
public ResponseEntity<EmployeeVO> addEmployee (@Valid @RequestBody EmployeeVO employee)
{
    EmployeeDB.addEmployee(employee);
    return new ResponseEntity<EmployeeVO>(employee, HttpStatus.OK);
}

Read more this blog about rest validation in detail.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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