【问题标题】:How to handle DataIntegrityViolationException in Spring?如何在 Spring 中处理 DataIntegrityViolationException?
【发布时间】:2011-01-07 17:52:15
【问题描述】:

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

【问题讨论】:

    标签: java spring exception-handling spring-mvc


    【解决方案1】:

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

    @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 training application 中通过添加/编辑具有重复邮件的用户或具有重复日期时间的膳食来模拟。

    更新

    其他解决方案:使用Controller Based Exception Handling:

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

    【讨论】:

    • 您是否有不同的配置来获得该约束友好?我的约束是这样的UK_6DOTKOTT2KJSP8VW4D0M25FB7_INDEX_4
    • 有几种方法可以创建可读约束: 1. 在初始 SQL 脚本中。 2.@Table注解中带有uniqueConstraints参数的DB自动生成,例如@Table(name = "meals", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "date_time"}, name = "meals_unique_user_datetime_idx")})
    【解决方案2】:

    1.在您的请求正文类中检查 not null 或 not empty 像这样

    public class CustomerRegisterRequestDto {
        @NotEmpty(message = "first name is empty")
        @NotNull(message = Constants.EntityValidators.FIRST_NAME_NULL)
        private String first_name;
        //other fields
        //getters and setters
    }
    

    2。然后在你的服务中检查这个

    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        Set<ConstraintViolation<CustomerRegisterRequestDto>> violations = validator.validate(userDto);
        if (!violations.isEmpty()) {
            //something is wrong in request parameters
            List<String> details = new ArrayList<>();
            for (ConstraintViolation<CustomerRegisterRequestDto> violation : violations) {
                details.add(violation.getMessage());
            }
            ErrorResponse error = new ErrorResponse(Constants.ErrorResponse.REQUEST_PARAM_ERROR, details);
            return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
        }
    

    3. Here 是你的 ErrorResponse 类

    【讨论】:

      【解决方案3】:

      Spring 3 提供了两种处理方式 - 在 beans.xml 中使用 HandlerExceptionResolver,或者在控制器中使用 @ExceptionHandler。他们都做同样的事情——他们把异常变成要渲染的视图。

      两者都记录在here

      【讨论】:

        【解决方案4】:

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

        但是,您可以自定义此翻译逻辑。如果你使用LocalSessionFactoryBean 来访问Hibernate,你可以为它提供一个自定义的SQLExceptionTranslator(参见LocalSessionFactoryBean.jdbcExceptionTranslator)。此异常转换器可以将ConstraintViolationException 转换为您自己的异常类,同时保留约束名称。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-07
          • 1970-01-01
          • 2013-10-24
          • 2015-05-20
          • 2020-07-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多