如何使用 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 配置选项来禁用覆盖。