我开发了一个API服务,它可以向数据库添加一些数据。我为实体的
name
字段设置了唯一约束。每当我尝试插入重复的 name
值时,我都会给出以下堆栈跟踪。
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "uk_tten_courseservice_program_table_program_name"
Detail: Key (program_name)=(jkjkncj) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:388)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:334)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
... 119 more
这是嵌套异常之一,我希望将错误消息发送到前端。根本例外是:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [uk_tten_courseservice_program_table_program_name]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
我在实体类中添加的内容如下:
@Entity
@Table(name = "tten_courseservice_program_table", uniqueConstraints = {
@UniqueConstraint(name = "uk_tten_courseservice_program_table_program_name", columnNames = { "program_name" }) })
public class Program {
@Column(name = "program_name")
private String programName;
//other attributes and getter setters.
}
那么我在这里缺少什么?我试过放置:
catch(PSQLexception e)
但它没有捕获我的错误,因为它不是根异常。并且
DataIntegrityException
有非常模糊的消息,例如:
could not execute statement; SQL [n/a]; constraint [uk_tten_courseservice_program_table_program_name]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
还有其他方法可以实现这些吗?我知道的一种方法是在保存每条记录之前在数据库上运行搜索查询以检查它是否已经存在,但我认为这不会有效。提前致谢。
要处理此类异常,您可以实现 ExceptionHandler。要获取异常的根本原因,您可以使用实用程序方法
org.springframework.core.NestedExceptionUtils#getMostSpecificCause
。
示例:
@ControllerAdvice
public class ExceptionHandler {
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<?> conflict(DataIntegrityViolationException e) {
String message = NestedExceptionUtils.getMostSpecificCause(e).getMessage();
ErrorMessage errorMessage = new ErrorMessage(message);
return new ResponseEntity<>(errorMessage), HttpStatus.CONFLICT);
}
}
其中
ErrorMessage
是您的自定义错误消息类。
其他信息:https://www.toptal.com/java/spring-boot-rest-api-error-handling
我创建了一个可以捕获异常的类
@ControllerAdvice
public class CourseNameExist {
@ResponseBody
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(DataIntegrityViolationException.class)
public CourseResponse init(DataIntegrityViolationException e) {
return CourseResponse
.builder()
.codeStatus(HttpStatus.CONFLICT.value())
.message(e.fillInStackTrace().getMessage())
.build();
}
}
我创建了一个具有两个属性 statusCode 和 Massage 的 CourseResponse 类,一旦捕获错误,我将其作为响应返回
@Data
@Builder
public class CourseResponse {
private int codeStatus;
private String message;
}