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

查看:91
本文介绍了使用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标头中.我宁愿在集合GET中获取@Version,而不必在集合中的每个资源上调用GET,因此我可以编写我的应用程序来检查每个资源更新上的@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.

是否有一种方法可以将@Version字段包含在每个资源的集合GET中?

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是HTTP等效于后端中表示为@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. PUT,而没有If-Match标头-强制覆盖服务器上存在的所有内容,因为要加载聚合,将传入的数据映射到其上并将其写回.如果其他客户端在此期间更改了聚合,您仍然会获得乐观锁定(尽管窗口很短).如果是这种情况,您会看到409 Conflict.
  2. PUT具有If-Match标头-Spring Data REST根据聚合的version属性的当前值检查提交的ETag并返回412 Precondition Failed,以防万一此时不匹配.在这种情况下,客户端可以查找资源的当前状态并决定如何进行.他们可能只是决定使用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. GETIf-None-Match(ETag)/If-Modified-Since(具有Last-Modified标头值)—如果资源仍与以前一样,您将看到304 Not Modified花费响应带宽.
  2. 普通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天全站免登陆