2015-11-12 12 views
12

DTO:Jak dostosować domyślny komunikat o błędzie ze sprawdzania poprawności spring @Valid?

public class User { 

    @NotNull 
    private String name; 

    @NotNull 
    private String password; 

    //.. 
} 

Kontroler:

@RequestMapping(value = "/user", method = RequestMethod.POST) 
public ResponseEntity<String> saveUser(@Valid @RequestBody User user) { 
    //.. 
    return new ResponseEntity<>(HttpStatus.OK); 
} 

Domyślny błąd json:

{"timestamp":1417379464584,"status":400,"error":"Bad Request","exception":"org.springframework.web.bind.MethodArgumentNotValidException","message":"Validation failed for argument at index 0 in method: public org.springframework.http.ResponseEntity<demo.User> demo.UserController.saveUser(demo.User), with 2 error(s): [Field error in object 'user' on field 'name': rejected value [null]; codes [NotNull.user.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name]]; default message [may not be null]],"path":"/user"} 

chciałbym mieć mój własny json dla każdego wystąpił błąd. Jak to osiągnąć?

Odpowiedz

5

Można wykonać sprawdzanie poprawności za pomocą obiektów Errors/BindingResult. Dodaj argument Błędy do metody kontrolera i dostosuj komunikat o błędzie po znalezieniu błędów.

Poniżej znajduje się przykładowy przykład, errors.hasErrors() zwraca wartość true, gdy sprawdzanie poprawności nie powiedzie się.

@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

@ksaughs Jaka jest klasa ApiErrors? – user6123723

+0

org.springframework.validation.Errors ze słoika wiosennego kontekstu – kswaughs

+0

@kswaughs, szukałem ApiErrors wszędzie i nie mogłem go nigdzie znaleźć. Uwzględniłem także zależność wiosenno-kontekstową w maven i nie mogłem nic znaleźć. Jedyne wyniki w Internecie dotyczą tej strony stackoverflow, o której wspominasz w swojej odpowiedzi. Czy mógłbyś pomóc? – user238607

14

Jeśli chcesz pełną kontrolę nad komunikatu odpowiedzi na każdy kontroler napisać ControllerAdvice. Na przykład, że przykład przekształcić MethodArgumentNotValidException do niestandardowego obiektu json:

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; 
     } 
    } 
} 
4

wiem, że to jest trochę stare pytanie,

Ale ja po prostu uruchomić w niej i znalazłem kilka bardzo dobrych article który ma również doskonały przykład w github.

Zasadniczo używa @ControllerAdvice, jak sugeruje dokumentacja Spring.

Tak na przykład łapanie 400 błąd zostanie osiągnięty poprzez nadpisanie jedną funkcję:

@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); 
    } 
} 

(klasa ApiError jest prosty obiekt do stanu, wiadomość posiadać błędy)

2

Jednym ze sposobów na to jest dodawanie wiadomości w adnotacjach @NotNull.

DTO:

public class User { 

    @NotNull(message = "User name cannot be empty") 
    private String name; 

    @NotNull(message = "Password cannot be empty") 
    private String password; 

    //.. 
} 

Kontroler:

@RequestMapping(value = "/user", method = RequestMethod.POST) 
public ResponseEntity<String> saveUser(@Valid @RequestBody User user) { 
    //.. 
    return new ResponseEntity<>(HttpStatus.OK); 
} 
// Add one 
@ExceptionHandler(MethodArgumentNotValidException.class) 
public ResponseEntity<List<YourErrorResponse>> handleException(MethodArgumentNotValidException ex) { 
// Loop through FieldErrors in ex.getBindingResult(); 
// return *YourErrorReponse* filled using *fieldErrors* 
} 
Powiązane problemy