Я обрабатываю DataIntegrityViolationException
в ExceptionInfoHandler
, нахожу вхождения ограничений DB в сообщении первопричины и преобразую его в сообщение i18n через constraintCodeMap
:
@ControllerAdvice(annotations = RestController.class)
@Order(Ordered.HIGHEST_PRECEDENCE + 5)
public class ExceptionInfoHandler {
@Autowired
private MessageSource messageSource;
private static Map<String, String> constraintCodeMap = new HashMap<String, String>() {
{
put("users_unique_email_idx", "exception.users.duplicate_email");
put("meals_unique_user_datetime_idx", "exception.meals.duplicate_datetime");
}
};
@ResponseStatus(value = HttpStatus.CONFLICT) // 409
@ExceptionHandler(DataIntegrityViolationException.class)
@ResponseBody
public ErrorInfo conflict(HttpServletRequest req, DataIntegrityViolationException e) {
String rootMsg = ValidationUtil.getRootCause(e).getMessage();
if (rootMsg != null) {
Optional<Map.Entry<String, String>> entry = constraintCodeMap.entrySet().stream()
.filter((it) -> rootMsg.contains(it.getKey()))
.findAny();
if (entry.isPresent()) {
e=new DataIntegrityViolationException(
messageSource.getMessage(entry.get().getValue(), null, LocaleContextHolder.getLocale());
}
}
return new ErrorInfo(req, e);
}
...
}
Можно смоделировать в моем учебном приложении Java Enterprise , добавив / отредактировав пользователя с дубликатами почты или еды с дубликатом dateTime.
UPDATE
Другое решение: используйте Обработка исключений на основе контроллера :
@RestController
@RequestMapping("/ajax/admin/users")
public class AdminAjaxController {
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<ErrorInfo> duplicateEmailException(HttpServletRequest req, DataIntegrityViolationException e) {
return exceptionInfoHandler.getErrorInfoResponseEntity(req, e, EXCEPTION_DUPLICATE_EMAIL, HttpStatus.CONFLICT);
}