Spring Rest中的ConstraintViolationException

Iur*_*rii 6 spring hibernate

我有下一个spring rest控制器来处理我的异常:

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody
ExceptionResponseDTO hiberAnnotationExceptionHandler(ConstraintViolationException exception) {
    return  new ExceptionResponseDTO("Entity is null or we are out of range!", exception.getMessage(), ExceptionMapper.INSTANCE.exceptionToExceptionDTO(exception));
}
Run Code Online (Sandbox Code Playgroud)

我的实体类:

@Entity
public class Device {

    @Id
    @Column(name="name", nullable = false)
    private String Name;

    @Column(name = "send_date")
    @NotNull
    private Date sendDate;
}
Run Code Online (Sandbox Code Playgroud)

我尝试模拟ConstraintViolationException,因此在我的控制器中使用下一个代码:

Device d = new Device();
d.setName("sdsdsd");
d.setSendDate(null);
deviceRepository.save(d);
Run Code Online (Sandbox Code Playgroud)

结果,我收到下一个异常:

[dispatcherServlet] :?-具有路径[]的上下文中Servlet [dispatcherServlet]的Servlet.service()引发异常[请求处理失败;嵌套的异常是org.springframework.transaction.TransactionSystemException:无法提交JPA事务。嵌套的异常是javax.persistence.RollbackException:根本原因提交事务时出错,原因是javax.validation.ConstraintViolationException:组[javax.validation.groups.Default,]的更新期间,对类[com.entity.Device]的验证失败违反约束的列表:[ConstraintViolationImpl {interpolatedMessage ='可能不为空',propertyPath = sendDate,rootBeanClass = class com.entity.Device,messageTemplate ='{javax.validation.constraints.NotNull.message}'}]

因此,从堆栈跟踪中可以看到,我首先收到TransactionSystemException,因此,我的ExceptionHandler方法(hiberAnnotationExceptionHandler)不被调用。所以我的问题是如何模拟此异常(ConstraintViolationException)?提前致谢。

Anu*_*ade 4

TransactionSystemException 的原因

  1. Hibernate实体管理器负责抛出所有hibernate异常

如果您进入代码AbstractEntityManagerImpl.convert()方法,您将看到默认情况下它不会处理任何特定异常,例如 ConstraintViolation,而是仅抛出并包装在 PersistenceException 中。

  1. 如果您在 @Transaction 中调用代码并转换为 TransactionSystemException,JPA 事务管理器会捕获上述异常,您可以看到 spring JPA 事务管理器 class="org.springframework.orm.jpa.JpaTransactionManager" 的代码

正确解决异常的解决方案

  1. 首先注册一个 JPA 方言,它可以拦截这些 HibernateException 并包装到事务管理器 bean 中的特定 spring 异常中。
 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="jpaDialect" ref="jpaDialect"/>
</bean>

<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
Run Code Online (Sandbox Code Playgroud)

HibernateJpaDialect 捕获这些异常并转换为 spring 特定异常,如下所示

if (ex instanceof ConstraintViolationException) {
          ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
          return new DataIntegrityViolationException(ex.getMessage()  + "; SQL [" + jdbcEx.getSQL() +
                  "]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
      }
Run Code Online (Sandbox Code Playgroud)
  1. 您还可以注册您的实体管理器正在使用 hibernate jpaVendorAdapter 来完成您在各处使用 hibernate 的情况。
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="packagesToScan" value="com.pack.model" />
        <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
        <property name="persistenceUnitName" value="entityManager"/>
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
    </bean>    <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
Run Code Online (Sandbox Code Playgroud)
  1. 现在,在您的控制器中,您可以期待来自 hibernate 方言的 dataIntegrityException,该异常是由于 ConstraintViolationException 引发的

@ExceptionHandler(DataIntegrityViolationException.class)