如何在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); }