Как вернуть сообщения ConstraintViolationException в теле ответа? - PullRequest
0 голосов
/ 15 октября 2019

Я занимаюсь разработкой REST API на основе Spring Boot. Я проверяю входные объекты с помощью пользовательских аннотаций ConstraintValidator. Моя проблема заключается в том, что я не могу вернуть сообщения ConstraintViolationException в ответе. Мой обработчик исключений не перехватывает исключения (возможно, потому что они заключены в другие типы исключений).

Могу ли я получить несколько советов о том, как справиться с ситуацией?

Я искал по всему Интернету, но не смог найти подходящего решения для себя, и я тоже потратил на это несколько часов.

Пример аннотации:

@Documented
@Retention(RUNTIME)
@Target({FIELD, PARAMETER})
@Constraint(validatedBy = BirthDateValidator.class)
public @interface ValidBirthDate {

    String message() default "The birth date is not valid.";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

Класс валидатора:

public class BirthDateValidator extends FieldValidationBase implements ConstraintValidator<ValidBirthDate, LocalDate> {

    private static final Logger LOGGER = LoggerFactory.getLogger(BirthDateValidator.class);

    @Override
    public void initialize(ValidBirthDate constraintAnnotation) {
    }

    @Override
    public boolean isValid(LocalDate birthDate, ConstraintValidatorContext constraintValidatorContext) {
        constraintValidatorContext.disableDefaultConstraintViolation();
        LOGGER.info("Starting the validation process for birth date {}.", birthDate);

        if(birthDate == null) {
            constraintValidatorContext.buildConstraintViolationWithTemplate("The birth date is null.")
                    .addConstraintViolation();
            return false;
        }

        //other validations

        return true;
    }

Класс модели:

public class Manager extends BaseUser {

    //other fields 

    @Valid
    @ValidBirthDate
    private LocalDate birthDate;

    //setters & getters

Обработчик исключений:

@ExceptionHandler(value = ConstraintViolationException.class)
    public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
        List<String> errors = new ArrayList<>();

        for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
            errors.add(violation.getRootBeanClass().getName() + ": " + violation.getMessage());
        }

        Error response = new Error(errors);
        return new ResponseEntity<Object>(response, new HttpHeaders(), BAD_REQUEST);
    }

Контроллер:

@RestController
@RequestMapping(value = "/register", consumes = "application/json", produces = "application/json")
public class RegistrationController {

    @Autowired
    private RegistrationService registrationService;

    @PostMapping(value = "/manager")
    public ResponseEntity registerManager(@RequestBody @Valid Manager manager) {
        registrationService.executeSelfUserRegistration(manager);
        return new ResponseEntity<>(new Message("User " + manager.getEmailAddress() + " registered successfully!"), CREATED);
    }
}

Я получил код ответа 400, но не вижу тела ответа, содержащего сообщения о нарушенном ограничении.

1 Ответ

0 голосов
/ 16 октября 2019

После некоторой дополнительной отладки я обнаружил, что все нарушения ограничений были заключены в MethodArgumentNotValidException (из-за аннотаций @Valid) - мне пришлось немного покопаться в этом исключении, чтобы получить информацию.

Я переопределил метод handleMethodArgumentNotValid() из ResponseEntityExceptionHandler, и вот как я заставил его работать:

@Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

        List<String> errorMessages = new ArrayList<>();
        BindingResult bindingResult = ex.getBindingResult();
        List<ObjectError> errors = bindingResult.getAllErrors();
        for(ObjectError error : errors) {
            String message = error.getDefaultMessage();
            errorMessages.add(message);
        }

        return new ResponseEntity<>(new Error(errorMessages), new HttpHeaders(), BAD_REQUEST);
    }

Может быть, это кому-то поможет.

...