2016-08-26 4 views
3

данного следующую DTO и контроллерКак я ошибка проверки напечатанная на отказе

public class PasswordCredentials implements AuthenticationProvider { 

    @NotNull 
    @NotEmpty 
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) 
    private String user; 

    @NotNull 
    @NotEmpty 
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) 
    private CharSequence pass; 


    public void setPass(final CharSequence pass) { 
     this.pass = pass; 
    } 

    public void setUser(final String user) { 
     this.user = user; 
    } 

    @Override 
    public Authentication toAuthentication() { 
     return new UsernamePasswordAuthenticationToken(user, pass); 
    } 
} 

@RestController 
@RequestMapping(path = "authentication") 
class AuthenticationController { 
    private final AuthenticationManager am; 

    AuthenticationController(final AuthenticationManager am) { 
     this.am = am; 
    } 

    @RequestMapping(path = "password", method = RequestMethod.POST, consumes = { 
     "!" + MediaType.APPLICATION_FORM_URLENCODED_VALUE 
    }) 
    ResponseEntity<?> login(@Valid @RequestBody final PasswordCredentials credentials) { 
     Authentication authenticate = am.authenticate(credentials.toAuthentication()); 
     if (authenticate.isAuthenticated()) { 
      return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); 
     } 
     return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); 
    } 

} 

если, например pass является недействительным будет ошибка проверки, и 400 будет, никогда не называя мой контроллер, который Это хорошо. У этого 400, однако, нет контента, есть ли способ получить выходные данные контроллеров BindResults в качестве контента, чтобы потребитель API знал, что вызвало проблему? В идеале я бы не сделал этого в методе контроллера, чтобы это произошло на всех контроллерах?

Мне удалось получить это поведение с учетом данных весны следующим образом, но я хотел бы получить его для всех контроллеров API.

class RestConfig extends RepositoryRestConfigurerAdapter { 

    @Bean 
    Validator validator() { 
     return new LocalValidatorFactoryBean(); 
    } 


    @Override 
    public void configureValidatingRepositoryEventListener(
      final ValidatingRepositoryEventListener validatingListener) { 
     Validator validator = validator(); 
     //bean validation always before save and create 
     validatingListener.addValidator("beforeCreate", validator); 
     validatingListener.addValidator("beforeSave", validator); 
    } 

    @Override 
    public void configureRepositoryRestConfiguration(final RepositoryRestConfiguration config) { 
     config.setBasePath("/v0"); 
     config.setReturnBodyOnCreate(false); 
     config.setReturnBodyOnUpdate(false); 
    } 

ответ

0

Spring есть @ControllerAdvice и @ExceptionHandler аннотации для обработки ошибок в контроллерах.

@ControllerAdvice 
public class ExceptionTranslator { 

    @ExceptionHandler(MethodArgumentNotValidException.class) 
    @ResponseStatus(HttpStatus.BAD_REQUEST) 
    @ResponseBody 
    public Error processValidationError(MethodArgumentNotValidException ex) { 
     BindingResult result = ex.getBindingResult(); 
     ..... 
     return new Error(); 
    } 

    // Other exceptions 
} 
-1

Я хочу улучшить ответ Антона Новопашина: просто верните ошибку в объекте ответа.

@ControllerAdvice 
public class ExceptionTranslator { 

    @ExceptionHandler(MethodArgumentNotValidException.class) 
    @ResponseBody 
    public ResponseEntity<String> processValidationError(MethodArgumentNotValidException ex) { 
     return new ResponseEntity(ex.getMessage, HttpStatus.BAD_REQUEST); 
    } 

    // Other exceptions 
} 
0

Я не знаю, кто и почему downvoted существующие ответы, но они оба правы - лучший способ обработки ошибок валидации должен был бы объявить @ControllerAdvice, а затем обрабатывать исключения там. Вот отрывок из моего глобального обработчика ошибок, взятый из существующего проекта:

@ControllerAdvice 
@ResponseBody 
public class RestfulErrorHandler { 

    @ResponseStatus(HttpStatus.BAD_REQUEST) 
    @ExceptionHandler(MethodArgumentNotValidException.class) 
    public ErrorResponse methodValidationError(MethodArgumentNotValidException e) { 
     final ErrorResponse response = new ErrorResponse(); 
     for (ObjectError error : e.getBindingResult().getAllErrors()) { 
      if (error instanceof FieldError) { 
       response.addFieldError((FieldError) error); 
      } else { 
       response.addGeneralError(error.getDefaultMessage()); 
      } 
     } 
     return response; 
    } 

    @ResponseStatus(HttpStatus.BAD_REQUEST) 
    @ExceptionHandler(ConstraintViolationException.class) 
    public ErrorResponse constraintViolationError(ConstraintViolationException e) { 
     final ErrorResponse response = new ErrorResponse(); 
     for (ConstraintViolation<?> v : e.getConstraintViolations()) { 
      response.addFieldError(v.getPropertyPath(), v.getMessage()); 
     } 

     return response; 
    } 
} 

Вы также должны обрабатывать ConstraintViolationException сек, так как они тоже могут быть выброшены. Вот a link to my ErrorResponse class, я включаю его как Gist, чтобы не заслонять основной момент.

Возможно, вы также должны обработать RepositoryConstraintViolationException, я не уверен, что spring-data-rest уже обрабатывает их.