如何在Spring中处理DataIntegrityViolationException?

我需要在Spring 3.0应用程序中显示自定义消息。 我有一个Hibernate数据库,有几个约束。 我对如何以良好的方式处理DataIntegrityViolationException有疑问。 我想知道是否有一种方法可以在属性文件中使用消息集映射exception,因为它可以在约束validation中使用。 我能以任何方式自动处理它,或者我必须在每个控制器中捕获此exception吗?

在违反约束的情况下显示用户友好消息的问题是,当Hibernate的ConstraintViolationException被转换为Spring的DataIntegrityViolationException时,约束名称将丢失。

但是,您可以自定义此转换逻辑。 如果使用LocalSessionFactoryBean来访问Hibernate,则可以为其提供自定义SQLExceptionTranslator (请参阅LocalSessionFactoryBean.jdbcExceptionTranslator )。 此exception转换器可以将ConstraintViolationException转换为您自己的exception类,同时保留约束名称。

Spring 3提供了两种处理方法 – beans.xml中的@ExceptionHandler或控制器中的@ExceptionHandler 。 它们都做同样的事情 – 它们将exception转换为渲染视图。

两者都记录在这里 。

我在ExceptionInfoHandler处理DataIntegrityViolationException ,在根本原因消息中查找DB约束,并通过constraintCodeMap将其转换为i18n消息:

 @ControllerAdvice(annotations = RestController.class) @Order(Ordered.HIGHEST_PRECEDENCE + 5) public class ExceptionInfoHandler { @Autowired private MessageSource messageSource; private static Map constraintCodeMap = new HashMap() { { 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> 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培训应用程序中通过添加/编辑具有重复日期时间的重复邮件或餐件来模拟。

更新

其他解决方案:使用基于控制器的exception处理 :

 @RestController @RequestMapping("/ajax/admin/users") public class AdminAjaxController { @ExceptionHandler(DataIntegrityViolationException.class) public ResponseEntity duplicateEmailException(HttpServletRequest req, DataIntegrityViolationException e) { return exceptionInfoHandler.getErrorInfoResponseEntity(req, e, EXCEPTION_DUPLICATE_EMAIL, HttpStatus.CONFLICT); }