Ответ от Areus объясняет, что не следует путать валидатор Hibernate и ограничения базы данных, но, опираясь на это, не всегда легко получить имя затронутого столбца из полученного исключения базы данных. Например, когда у вас есть уникальное ограничение для столбца базы данных, трудно правильно вернуть это исключение пользователю.
То, что я сделал, было то, что у меня был класс, который обрабатывает мою обработку исключений вызова REST и находит, что специфицирует c сообщение об исключении. Я не нашел другого способа сделать это в Spring / Hibernate.
@ControllerAdvice
@RequestMapping(produces = APPLICATION_JSON_VALUE)
public class RestResponseEntityExceptionHandler {
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<ErrorDTO> dataIntegrityViolationException(final DataIntegrityViolationException e) {
String mostSpecificCauseMessage = e.getMostSpecificCause().getMessage();
if (e.getCause() instanceof ConstraintViolationException) {
String name = ((ConstraintViolationException) e.getCause()).getConstraintName();
log.debug("Encountered ConstraintViolationException, details: " + mostSpecificCauseMessage);
return determineError(mostSpecificCauseMessage, name);
} else {
log.debug("Encountered DataIntegrityViolation exception, details: " + mostSpecificCauseMessage);
ErrorDTO errorDTO =
new ErrorDTO("BAD_REQUEST_ERROR", "DataIntegrityViolation exception. " + mostSpecificCauseMessage);
return new ResponseEntity<>(errorDTO, HttpStatus.BAD_REQUEST);
}
}
//this catches the manually invoked entityManager.flush() exceptions
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorDTO> constraintViolationException(final ConstraintViolationException e) {
String message = e.getMessage();
String name = e.getConstraintName();
log.debug("Encountered ConstraintViolationException, details: {}", message);
return determineError(message, name);
}
private ResponseEntity<ErrorDTO> determineError(String message, String name) {
Map<String, String> errors = new HashMap<>();
switch (name) {
case Project.UNIQUE_CONSTRAINT_NAME:
errors.put("name", ALREADY_EXISTS);
break;
case Value.UNIQUE_CONSTRAINT_VALUE:
errors.put("value", ALREADY_EXISTS);
break;
//and so on
default:
break;
}
if (!errors.isEmpty()) {
ErrorDTO error = new ErrorDTO(VALIDATION_ERROR, VALIDATION_ERROR_MESSAGE, errors);
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
} else {
ErrorDTO errorDTO = new ErrorDTO("CONFLICT_ERROR", message);
return new ResponseEntity<>(errorDTO, HttpStatus.CONFLICT);
}
}
}
Вам также нужно определить имя ограничения в вашей сущности / базе данных модели, например:
@Table(uniqueConstraints = {
@UniqueConstraint(name = UNIQUE_CONSTRAINT_VALUE, columnNames = {"value"})})
public static final String UNIQUE_CONSTRAINT_VALUE = "unique_constraint_property_value";
И в определении базы данных, конечно же.