java 如何在 Spring 中处理 DataIntegrityViolationException?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2109476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 19:30:32  来源:igfitidea点击:

How to handle DataIntegrityViolationException in Spring?

javaspringexception-handlingspring-mvc

提问by Javi

I need to show custom messages in my Spring 3.0 application. I have a database with Hibernate and there are several constraints. I have doubts in how DataIntegrityViolationExceptionshould be handled in a good way. I wonder if there is a way to map the exception with a message set in a properties file, as it is possible in Constraints validation. Could I handle it automatically in any way or I have to catch this exception in each controller?

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

采纳答案by axtavt

The problem with showing user-friendly messages in the case of constraint violation is that the constraint name is lost when Hibernate's ConstraintViolationExceptionis being translated into Spring's DataIntegrityViolationException.

在违反约束的情况下显示用户友好消息的问题在于,当 HibernateConstraintViolationExceptionDataIntegrityViolationException.

However, you can customize this translation logic. If you use LocalSessionFactoryBeanto access Hibernate, you can supply it with a custom SQLExceptionTranslator(see LocalSessionFactoryBean.jdbcExceptionTranslator). This exception translator can translate a ConstraintViolationExceptioninto your own exception class, preserving the constraint name.

但是,您可以自定义此翻译逻辑。如果您用于LocalSessionFactoryBean访问 Hibernate,则可以为其提供自定义SQLExceptionTranslator(请参阅 参考资料LocalSessionFactoryBean.jdbcExceptionTranslator)。此异常翻译器可以将 aConstraintViolationException转换为您自己的异常类,同时保留约束名称。

回答by Grigory Kislin

I treat DataIntegrityViolationExceptionin ExceptionInfoHandler, finding DB constraints occurrences in root cause message and convert it into i18n message via constraintCodeMap:

我对待DataIntegrityViolationExceptionExceptionInfoHandler,在根源消息寻找DB约束出现,它通过转换成国际化的消息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);
  }
  ...
}

Can be simulated in my Java Enterprise training applicationby adding/editing user with duplicate mail or meal with duplicate dateTime.

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

UPDATE:

更新

Other solution: use 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);
    }

回答by skaffman

Spring 3 provides two ways of handling this - HandlerExceptionResolverin your beans.xml, or @ExceptionHandlerin your controller. They both do the same thing - they turn the exception into a view to render.

Spring 3 提供了两种处理方式 -HandlerExceptionResolver在 beans.xml 中或@ExceptionHandler在控制器中。他们都做同样的事情 - 他们将异常转换为要呈现的视图。

Both are documented here.

两者都记录在此处

回答by Kishan Solanki

1. In your request body class check for not null or not empty like this

1. 在您的请求正文类中,像这样检查非空或非空

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. Then in your service check for this

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. Hereis your ErrorResponse class

3.是你的 ErrorResponse 类