如何使用 Spring Data REST 防止保存现有实体
How to prevent saving over an existing entity with Spring Data REST
(Kotlin 示例)
我有一个手动分配 ID 的实体:
@Entity
@Table(name = "Item")
class Item {
@Id
@Column(name = "ItemId", nullable = false, updatable = false)
var id: Int? = null
@Column(name = "Name", nullable = false)
var name: String? = null
}
及其 Spring 数据 REST 存储库:
interface ItemRepository : PagingAndSortingRepository<Item, Int>
如果我使用现有 ID 执行 POST
到 /items
,现有对象将被覆盖。我希望它会返回一个错误。有没有一种方法可以配置该行为,而无需为每种资源类型滚动我自己的保存方法?
谢谢。
您可以将版本属性添加到用 @Version
注释的实体,这将启用乐观锁定。如果您始终为新实体提供版本 0,那么当该实体已经存在(具有不同的版本)时,您应该会得到一个例外。
当然,您还需要提供该版本以进行更新。
我最终使用了 Spring Validator for this with the help of this article。
我这样创建了验证器:
class BeforeCreateItemValidator(private val itemRepository: ItemRepository) : Validator {
override fun supports(clazz: Class<*>) = Item::class.java == clazz
override fun validate(target: Any, errors: Errors) {
if (target is Item) {
itemRepository
.findById(target.id!!)
.ifPresent {
errors.rejectValue("id",
"item.exists",
arrayOf(target.id.toString()),
"no default message")
}
}
}
}
然后使用此配置进行设置:
@Configuration
class RestRepositoryConfiguration(
private val beforeCreateItemValidator: BeforeCreateItemValidator
) : RepositoryRestConfigurer {
override fun configureValidatingRepositoryEventListener(
validatingListener: ValidatingRepositoryEventListener) {
validatingListener.addValidator("beforeCreate", beforeCreateItemValidator)
}
}
这样做会导致服务器 return 变成 400 Bad Request
(我希望能够更改为 409 Conflict
,但是 400
也可以) JSON 正文和 errors
属性 包含我的自定义消息。这对于我检查一个实体的目的来说很好,但是如果我的整个应用程序都手动分配了 ID,那么必须这样做可能会有点混乱。我希望看到一个 Spring Data REST 配置选项来禁用覆盖。
(Kotlin 示例)
我有一个手动分配 ID 的实体:
@Entity
@Table(name = "Item")
class Item {
@Id
@Column(name = "ItemId", nullable = false, updatable = false)
var id: Int? = null
@Column(name = "Name", nullable = false)
var name: String? = null
}
及其 Spring 数据 REST 存储库:
interface ItemRepository : PagingAndSortingRepository<Item, Int>
如果我使用现有 ID 执行 POST
到 /items
,现有对象将被覆盖。我希望它会返回一个错误。有没有一种方法可以配置该行为,而无需为每种资源类型滚动我自己的保存方法?
谢谢。
您可以将版本属性添加到用 @Version
注释的实体,这将启用乐观锁定。如果您始终为新实体提供版本 0,那么当该实体已经存在(具有不同的版本)时,您应该会得到一个例外。
当然,您还需要提供该版本以进行更新。
我最终使用了 Spring Validator for this with the help of this article。
我这样创建了验证器:
class BeforeCreateItemValidator(private val itemRepository: ItemRepository) : Validator {
override fun supports(clazz: Class<*>) = Item::class.java == clazz
override fun validate(target: Any, errors: Errors) {
if (target is Item) {
itemRepository
.findById(target.id!!)
.ifPresent {
errors.rejectValue("id",
"item.exists",
arrayOf(target.id.toString()),
"no default message")
}
}
}
}
然后使用此配置进行设置:
@Configuration
class RestRepositoryConfiguration(
private val beforeCreateItemValidator: BeforeCreateItemValidator
) : RepositoryRestConfigurer {
override fun configureValidatingRepositoryEventListener(
validatingListener: ValidatingRepositoryEventListener) {
validatingListener.addValidator("beforeCreate", beforeCreateItemValidator)
}
}
这样做会导致服务器 return 变成 400 Bad Request
(我希望能够更改为 409 Conflict
,但是 400
也可以) JSON 正文和 errors
属性 包含我的自定义消息。这对于我检查一个实体的目的来说很好,但是如果我的整个应用程序都手动分配了 ID,那么必须这样做可能会有点混乱。我希望看到一个 Spring Data REST 配置选项来禁用覆盖。