使用Spring Data REST,为什么@Version属性成为ETag并且不包含在表示中?

Jan*_*sen 7 rest spring spring-data spring-data-rest spring-boot

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

$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
Run Code Online (Sandbox Code Playgroud)

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

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

@Version是数据行的版本,在更新时递增,并在查询特定资源时包含在ETag HTTP标头数据中.GET我不想在集合中调用每个资源,而是更喜欢获取@Version集合,GET因此我可以编写应用程序来检查@Version每个资源更新的值,而无需执行n额外GET的往返.

有没有办法@Version在每个资源中包含字段集合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;

    …
}
Run Code Online (Sandbox Code Playgroud)

Oli*_*ohm 17

不,那里没有.ETag是HTTP等同@Value于后端中表示为属性的HTTP .Spring Data REST将所有在HTTP协议中具有相应机制的后端相关属性转换为:ids成为URI(也不应成为有效负载的一部分),@LastModifiedDate属性成为头,@Version属性,成为ETag.

原因很简单:如果您使用HTTP,请使用可用的协议方法来实现在数据访问级别上实现的内容.这是一个方面,其中春季数据REST是不是简单地暴露一个数据库到网络,但实际上检查您的模型和转换模型特征分为协议的具体手段.

简而言之:使用Spring Data REST,您有两种更新选项:

  1. 只是PUT没有If-Match标题 - 强制覆盖服务器上存在的任何内容,因为聚合被加载,传入的数据映射到它并且它被写回.如果另一个客户端在此期间更改了聚合(尽管这是一个非常短的窗口),您仍然可以应用乐观锁定.如果是这样的话,你会看到一个409 Conflict.
  2. PUT带有If-Match标题 - Spring Data REST根据聚合的version属性的当前值检查提交的ETag,并412 Precondition Failed在该点出现不匹配的情况下返回.在这种情况下,客户端可以查找资源的当前状态并决定如何继续.他们可能只是决定在PUT没有If-Match标题的情况下覆盖服务器上的内容.

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

  1. GETwith If-None-Match(ETag)/ If-Modified-Since(带有Last-Modified标头值) - 如果304 Not Modified资源仍然处于与之前相同的状态,您将看到以下情况,从而避免为响应花费带宽.
  2. Plain GET将始终返回表示.