使用 Spring Data REST,为什么 @Version 属性成为 ETag 而未包含在表示中? [英] With Spring Data REST, why is the @Version property becoming an ETag and not included in the representation?

查看:14
本文介绍了使用 Spring Data REST,为什么 @Version 属性成为 ETag 而未包含在表示中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Spring Data REST(通过 Spring Boot 1.3.3)中,当我 GET 一个资源集合,比如,people@Version 属性不包含在资源中:

In Spring Data REST (via Spring Boot 1.3.3), when I GET a resource collection of, say, people, the @Version property is not included with the resources:

$curl -v http://localhost:8080/api/people/1
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /api/people/1 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.42.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< ETag: "0"
< Last-Modified: Tue, 26 Apr 2016 00:08:12 GMT
< Content-Type: application/hal+json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 26 Apr 2016 00:12:56 GMT
< 
{
  "id" : 1,
  "createdDate" : {
    "nano" : 351000000,
    "epochSecond" : 1461629292
  },
  "lastModifiedDate" : {
    "nano" : 351000000,
    "epochSecond" : 1461629292
  },
  "firstName" : "Bilbo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/api/people/1"
    },
    "person" : {
      "href" : "http://localhost:8080/api/people/1"
    }
  }
* Connection #0 to host localhost left intact

默认情况下,或者当我配置我的 Spring Data 存储库时:

by default, or when I configure my Spring Data repository:

@Configuration
public class ApplicationRepositoryConfiguration 
    extends RepositoryRestMvcConfiguration 
{    
    @Override
    protected void configureRepositoryRestConfiguration(
        RepositoryRestConfiguration config
        ) 
    {
        config.exposeIdsFor(Person.class);
        config.setBasePath("/api/");
    }
}

@Version 是在更新时递增的数据行的版本,并包含在 ETag HTTP Header 数据中时我查询特定资源.不必在集合中的每个资源上调用 GET,我更喜欢在集合 GET 中获取 @Version 以便我可以编写我的应用程序来检查每个资源更新的 @Version 不执行 n 添加 GET 往返.

The @Version is the version of the row of data which is incremented on updates, and included in the ETag HTTP Header data when I query a specific resource. Instead of having to invoke a GET on each resource in the collection, I'd prefer getting the @Version in the collection GET so I can write my application to check the @Version value on each resource update without performing the n addition GET round-trips.

有没有办法在集合 GET 的每个资源中包含 @Version 字段?

Is there a way to include the @Version field in each of the resources a collection GET?

实体定义如下所示:

@Data @Entity @EntityListeners(AuditingEntityListener.class)
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @CreatedDate
    @Column(nullable=false)
    private Instant createdDate;

    @LastModifiedDate
    @Column(nullable=false)
    private Instant lastModifiedDate;

    @Version
    @JsonProperty
    private Long version;

    …
}

推荐答案

不,没有.ETag 是等效于后端中表示为 @Value 属性的 HTTP.Spring Data REST 将所有在 HTTP 协议中具有相应机制的后端相关属性完全转换为:id 变成 URI(也不应该成为有效负载的一部分),@LastModifiedDate 属性变成标题,@Version 属性,变成 ETags.

No, there is not. The ETag is the HTTP equivalent to what's expressed as @Value property in the backend. Spring Data REST turns all backend related properties that have a corresponding mechanism in the HTTP protocol into exactly those: ids become URIs (and shouldn't be part of the payload either), @LastModifiedDate properties become headers, @Version properties, become ETags.

原因很简单:如果您使用 HTTP,请使用您可用的协议方式来实现在数据访问级别上实现的事情.这是 Spring Data REST 不是简单地将数据库暴露给 Web 而是实际检查您的模型并将模型特征转换为协议特定方式的一方面.

The reason is pretty simple: if you use HTTP, use the protocol means that are available to you to achieve things that are implemented on the data access level. That's one aspect in which Spring Data REST is not simply exposing a database to the web but actually inspects your model and translates model characteristics into protocol specific means.

长话短说:使用 Spring Data REST,您有两个更新选项:

Long story short: with Spring Data REST you have two options for updates:

  1. Just PUT 没有 If-Match 标头 - 在聚合加载时强制覆盖服务器上存在的任何内容,传入数据映射到它并写回.如果在此期间另一个客户端更改了聚合,您仍然会应用乐观锁定(尽管这是一个非常短的窗口).如果是这种情况,您将看到 409 Conflict.
  2. PUT 带有 If-Match 标头 - Spring Data REST 根据聚合的 version 属性的当前值检查提交的 ETag 并返回 412前提条件失败 以防此时不匹配.在这种情况下,客户端可以查找资源的当前状态并决定如何继续.他们可能只是决定使用 PUT 覆盖服务器上的内容,而不使用 If-Match 标头.
  1. Just PUT without an If-Match header — enforces overriding whatever is present on the server as the aggregate gets loaded, incoming data mapped onto it and it written back. You still get optimistic locking applied if another client changed the aggregate in the meantime (although an admittedly very short window). If that's the case you'll see a 409 Conflict.
  2. PUT with an If-Match header - Spring Data REST checks the ETag submitted against the current value of the version property of the aggregate and return a 412 Precondition Failed in case there's a mismatch at that point. In that case clients can lookup the current state of the resource and decide how to proceed. They might just decide to override what's on the server using PUT without an If-Match header.

可以对 GET 请求进行类似的优化:

Similar optimizations can made for GET requests:

  1. GET with If-None-Match (ETag)/If-Modified-Since(带有 Last-Modified 标头值)——你将看到 304 Not Modified,以防资源仍处于与以前相同的状态,从而避免为响应花费带宽.
  2. Plain GET 将始终返回表示.
  1. GET with If-None-Match (ETag) / If-Modified-Since (with Last-Modified header value) — You'll see a 304 Not Modified in case the resource is still in the same state as before and you thus avoid spending bandwidth for the response.
  2. Plain GET will always return the representation.

这篇关于使用 Spring Data REST,为什么 @Version 属性成为 ETag 而未包含在表示中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆