如何处理春季数据完整性暴力异常?

我需要在我的Spring 3.0应用程序中显示自定义消息。我有一个带有Hibernate的数据库,有几个约束。我对如何以一种好的方式处理有疑问。我想知道是否有一种方法可以将异常与属性文件中的消息集进行映射,就像在约束验证中一样。我可以以任何方式自动处理它,还是必须在每个控制器中捕获此异常?DataIntegrityViolationException


答案 1

在违反约束的情况下显示用户友好消息的问题是,当Hibernate的被翻译成Spring的时,约束名称会丢失。ConstraintViolationExceptionDataIntegrityViolationException

但是,您可以自定义此转换逻辑。如果用于访问休眠,则可以为其提供自定义(请参阅)。此异常转换器可以将 a 转换为您自己的异常类,同时保留约束名称。LocalSessionFactoryBeanSQLExceptionTranslatorLocalSessionFactoryBean.jdbcExceptionTranslatorConstraintViolationException


答案 2

我在 ExceptionInfoHandler 中处理,查找根本原因消息中出现的 DB 约束,并通过以下方式将其转换为 i18n 消息:DataIntegrityViolationExceptionconstraintCodeMap

@ControllerAdvice(annotations = RestController.class)
@Order(Ordered.HIGHEST_PRECEDENCE + 5)
public class ExceptionInfoHandler {

  @Autowired
  private final MessageSourceAccessor messageSourceAccessor;

  private static Map<String, String> CONSTRAINS_I18N_MAP = Map.of(
      "users_unique_email_idx", EXCEPTION_DUPLICATE_EMAIL,
      "meals_unique_user_datetime_idx", EXCEPTION_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) {
        String lowerCaseMsg = rootMsg.toLowerCase();
        for (Map.Entry<String, String> entry : CONSTRAINS_I18N_MAP.entrySet()) {
            if (lowerCaseMsg.contains(entry.getKey())) {
                return logAndGetErrorInfo(req, e, VALIDATION_ERROR, messageSourceAccessor.getMessage(entry.getValue()));
            }
        }
    }
    return logAndGetErrorInfo(req, e, DATA_ERROR);
  }
  ...
}

可以通过添加/编辑具有重复邮件的用户或具有重复日期时间的膳食,在我的Java Enterprise培训应用程序中进行模拟。

更新

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

@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);
    }

推荐