如何在Spring Boot中捕获hibernate/jpa约束冲突?
我无法在中捕获ConstraintViolationException(或DataIntegrityViolationException) ResponseEntityExceptionHandler。 我想在响应中返回jpa失败(例如,违反了哪个约束)。 (我不希望在方法参数和catch handleMethodArgumentNotValid上使用@Valid)如何在Spring Boot中捕获hibernate/jpa约束冲突?,hibernate,spring-mvc,spring-boot,spring-data-jpa,Hibernate,Spring Mvc,Spring Boot,Spring Data Jpa,我无法在中捕获ConstraintViolationException(或DataIntegrityViolationException) ResponseEntityExceptionHandler。 我想在响应中返回jpa失败(例如,违反了哪个约束)。 (我不希望在方法参数和catch handleMethodArgumentNotValid上使用@Valid) 。。。 导入org.hibernate.exception.ConstraintViolationException; 导入org
。。。
导入org.hibernate.exception.ConstraintViolationException;
导入org.springframework.dao.DataIntegrityViolationException;
@控制器建议
公共类PstExceptionHandler扩展了ResponseEntityExceptionHandler{
@ExceptionHandler({ConstraintViolationException.class})
公共责任处理培训暴力(
ConstraintViolationException(例如,WebRequest请求){
...
返回新的ResponseEntity(…);
}
}
导入javax.persistence.*;
导入javax.validation.constraints.NotNull;
导入javax.validation.constraints.Size;
@实体
公立班学生{
@身份证
私人长id;
@NotNull
私有字符串名称;
@NotNull
@大小(最小值=7,message=“Passport应至少包含7个字符”)
私人字符串护照号码;
公立学生(){
}
...
}
@请求映射(value=“/addstudent”…)
@应答器
公共响应添加学生(@RequestBody StudentDto StudentDto){
学生=新生();
student.setId(studentDto.getId());//1L
student.setName(studentDto.getName());/“helen”
student.setPassportNumber(studentDto.getPassportNumber());/“321”
studentRepository.save(学生);
返回ResponseEntity.accepted().主体(学生);
}
谢谢…像ConstraintViolationException这样的异常不被考虑在内,因为它们是从HibernateException扩展而来的。您可以查看一下,这些异常都包装在Hibernate异常中
@ExceptionHandler({TransactionSystemException.class})
public ResponseEntity<Object> handleConstraintViolation(TransactionSystemException ex, WebRequest request) {
if (ex.getCause() instanceof RollbackException) {
RollbackException rollbackException = (RollbackException) ex.getCause();
if (rollbackException.getCause() instanceof ConstraintViolationException) {
return new ResponseEntity<Object>(...);
}
...
}
...
return new ResponseEntity<Object>(...);
}
@ExceptionHandler({TransactionSystemException.class})
公共响应handleConstraintViolation(TransactionSystemException除外,WebRequest请求){
如果(例如getCause()实例RollbackException){
RollbackException RollbackException=(RollbackException)ex.getCause();
if(rollbackException.getCause()instanceof ConstraintViolationException){
返回新的ResponseEntity(…);
}
...
}
...
返回新的ResponseEntity(…);
}
有三种方法:
@Valid
\@Validated
注释
一旦在参数级别使用了它们,就可以通过方法注入错误
\BindingResult
类型实现使用冲突
.save()
或.persist()
休眠方法时,都会引发ConstraintViolationException
LocalValidatoryFactoryBean.validate()
方法进行手动验证。然后,通过传递错误对象的实现,可以获得约束冲突。
确切地说,如何在内部实现@Valid
\@Validated
注释
您无法捕获ConstraintViolationException.class,因为它没有传播到代码的该层,而是由较低的层捕获,并在另一个类型下包装和重新发布。因此,命中web层的异常不是ConstraintViolationException。所以你可以这样做:
@ExceptionHandler({TransactionSystemException.class})
protected ResponseEntity<Object> handlePersistenceException(final Exception ex, final WebRequest request) {
logger.info(ex.getClass().getName());
//
Throwable cause = ((TransactionSystemException) ex).getRootCause();
if (cause instanceof ConstraintViolationException) {
ConstraintViolationException consEx= (ConstraintViolationException) cause;
final List<String> errors = new ArrayList<String>();
for (final ConstraintViolation<?> violation : consEx.getConstraintViolations()) {
errors.add(violation.getPropertyPath() + ": " + violation.getMessage());
}
final ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, consEx.getLocalizedMessage(), errors);
return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
final ApiError apiError = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex.getLocalizedMessage(), "error occurred");
return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
@ExceptionHandler({TransactionSystemException.class})
受保护的响应handlePersistenceException(最终异常,例如,最终WebRequest请求){
logger.info(例如getClass().getName());
//
可丢弃原因=((TransactionSystemException)ex).getRootCause();
如果(导致ConstraintViolationException的实例){
ConstraintViolationException consEx=(ConstraintViolationException)原因;
最终列表错误=新建ArrayList();
for(最终约束冲突:consEx.getConstraintViolations()){
添加(违例。getPropertyPath()+“:“+违例。getMessage());
}
final APIRROR APIRROR=新的APIRROR(HttpStatus.BAD_请求,consEx.getLocalizedMessage(),errors);
返回新的ResponseEntity(APIRROR,new-HttpHeaders(),APIRROR.getStatus());
}
final APIRROR APIRROR=新的APIRROR(HttpStatus.INTERNAL_SERVER_ERROR,例如getLocalizedMessage(),“发生错误”);
返回新的ResponseEntity(APIRROR,new-HttpHeaders(),APIRROR.getStatus());
}
我遇到了同样的问题,因此我必须捕获jdbception
异常:
@ExceptionHandler({JDBCException.class})
public ResponseEntity<Object> handleConstraintViolation(TransactionSystemException ex, WebRequest request) {
if (ex.getCause() instanceof ConstraintViolationException) {
...
}
return new ResponseEntity<Object>(...);
}
@ExceptionHandler({jdbception.class})
公共响应handleConstraintViolation(TransactionSystemException除外,WebRequest请求){
if(例如getCause()instanceof ConstraintViolationException){
...
}
返回新的ResponseEntity(…);
}
像这样的东西会有帮助:
@ExceptionHandler(value = {DataIntegrityViolationException.class})
public ResponseEntity<String> handlePreconditionFailed(DataIntegrityViolationException exception) {
LOG.error(ERROR_MESSAGE, exception);
return ResponseEntity.status(HttpStatus.CONFLICT).build();
}
@ExceptionHandler(值={DataIntegrityViolationException.class})
公共响应句柄修复失败(DataIntegrityViolationException异常){
日志错误(错误消息,异常);
返回ResponseEntity.status(HttpStatus.CONFLICT.build();
}
您能试试HibernateException吗?只需更新这个@ExceptionHandler({HibernateeException.class}),并让我知道您的答案是什么..?谢谢-尽管它并没有解决问题。问题依然存在。哦,对了,我已经看了一下,像ConstraintViolationException这样的异常并没有被考虑在内,因为正如我所想,它们是从HIbernateException扩展而来的。因此,将引发PersistenceException,而不是从HibernateeException扩展的任何异常。所以我认为您应该更新如下内容:@ExceptionHandler({PersistenceException.class})public ResponseEntity handleConstraintViolation(PersistenceException ex,WebRequest request){if(ex instanceof ConstraintViolationException){ConstraintViolationException consEx=
@ExceptionHandler(value = {DataIntegrityViolationException.class})
public ResponseEntity<String> handlePreconditionFailed(DataIntegrityViolationException exception) {
LOG.error(ERROR_MESSAGE, exception);
return ResponseEntity.status(HttpStatus.CONFLICT).build();
}