How do I customize default error message from spring @Valid validation?

前端 未结 10 776
孤街浪徒
孤街浪徒 2020-12-22 23:04

DTO:

public class User {

    @NotNull
    private String name;

    @NotNull
    private String password;

    //..
}

Controller:

相关标签:
10条回答
  • 2020-12-22 23:46

    I know this is kind of old question,

    But I just run into it and I found some pretty good article which has also a perfect example in github.

    Basically it uses @ControllerAdvice as Spring documentation suggests.

    So for example catching 400 error will be achieved by overriding one function:

    @ControllerAdvice
    public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
    
        @Override
        protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
            logger.info(ex.getClass().getName());
            //
            final List<String> errors = new ArrayList<String>();
            for (final FieldError error : ex.getBindingResult().getFieldErrors()) {
                errors.add(error.getField() + ": " + error.getDefaultMessage());
            }
            for (final ObjectError error : ex.getBindingResult().getGlobalErrors()) {
                errors.add(error.getObjectName() + ": " + error.getDefaultMessage());
            }
            final ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
            return handleExceptionInternal(ex, apiError, headers, apiError.getStatus(), request);
        }
    }
    

    (ApiError class is a simple object to hold status, message, errors)

    0 讨论(0)
  • 2020-12-22 23:58

    If you want full control over the response message in every controller write a ControllerAdvice. For example, that example transform MethodArgumentNotValidException into a custom json object:

    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.ResponseStatus;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import static org.springframework.http.HttpStatus.BAD_REQUEST;
    
    /**
     * Kudos http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/
     *
     */
    @Order(Ordered.HIGHEST_PRECEDENCE)
    @ControllerAdvice
    public class MethodArgumentNotValidExceptionHandler {
    
        @ResponseStatus(BAD_REQUEST)
        @ResponseBody
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public Error methodArgumentNotValidException(MethodArgumentNotValidException ex) {
            BindingResult result = ex.getBindingResult();
            List<org.springframework.validation.FieldError> fieldErrors = result.getFieldErrors();
            return processFieldErrors(fieldErrors);
        }
    
        private Error processFieldErrors(List<org.springframework.validation.FieldError> fieldErrors) {
            Error error = new Error(BAD_REQUEST.value(), "validation error");
            for (org.springframework.validation.FieldError fieldError: fieldErrors) {
                error.addFieldError(fieldError.getField(), fieldError.getDefaultMessage());
            }
            return error;
        }
    
        static class Error {
            private final int status;
            private final String message;
            private List<FieldError> fieldErrors = new ArrayList<>();
    
            Error(int status, String message) {
                this.status = status;
                this.message = message;
            }
    
            public int getStatus() {
                return status;
            }
    
            public String getMessage() {
                return message;
            }
    
            public void addFieldError(String path, String message) {
                FieldError error = new FieldError(path, message);
                fieldErrors.add(error);
            }
    
            public List<FieldError> getFieldErrors() {
                return fieldErrors;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-22 23:59

    You can perform validation with Errors/BindingResult object. Add Errors argument to your controller method and customize the error message when errors found.

    Below is the sample example, errors.hasErrors() returns true when validation is failed.

    @RequestMapping(value = "/user", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<String> saveUser(@Valid @RequestBody User user, Errors errors) {
        if (errors.hasErrors()) {
            return new ResponseEntity(new ApiErrors(errors), HttpStatus.BAD_REQUEST);
        }
        return new ResponseEntity<>(HttpStatus.OK);
    }
    
    0 讨论(0)
  • 2020-12-22 23:59
    @ControllerAdvice
    @RestController
    public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
    
            @Override
            protected ResponseEntity<Object> handleMethodArgumentNotValid(
                    MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
    
               // ex.getBindingResult(): extract the bind result for default message. 
                  String errorResult = ex.getBindingResult().toString();
                 CustomizedExceptionHandlerResponse exceptionResponse = new CustomizedExceptionHandlerResponse(
                        errorResult, new Date(), request.getDescription(false));
    
                return new ResponseEntity<>(exceptionResponse, HttpStatus.BAD_REQUEST);
            }
    
    
    }
    
    class CustomizedExceptionHandlerResponse {
    
       private String message;
       private String status;
       private Date timestamp;
    
       // constuctor, setters, getters...
    }
    
    0 讨论(0)
提交回复
热议问题