如何强制客户端使用 spring 数据剩余发送 etag/version?

How to force clients to send etag/version using spring data rest?

我们正在通过 spring 引导 (v1.3.3) 使用 spring 数据休息,并通过标准 REST 存储库导出器公开以下实体:

@Document
public class Project {
  @Version
  private Long version;

  @CreatedDate
  private LocalDateTime createdDate;

  @CreatedBy
  private String createdBy;

  @LastModifiedDate
  private LocalDateTime lastModifiedDate;

  @LastModifiedBy
  private String lastModifiedBy;

  private String name;

  //getters and setters omitted

}
例如,

A​​ POST 到 /projects 或 PUT 到 /projects/1234 创建一个文档 etag/version 0。另一个 PUT 到 /projects/1234 会覆盖文档,即使客户没有提供 version/etag。此外,即使客户端未提供 version/etag.

,/projects/1234 上的 DELETE 也会删除文档

当且仅当客户端提供有效 version/etag 时,我如何配置 spring 数据更新和删除文档?

API 客户端 需要在请求中的 header 上指定有效的 ETag,如下所示:

If-Match: <value of previous ETag>

通过将此 header 添加到 HTTP 请求,您将其转换为条件操作,只有在满足条件时才会执行。还有其他条件,例如 If-None-MatchIf-Modified-Since.

客户有责任添加条件header。

根据这个问题,我了解到您希望 服务器 禁止任何未提供有效 ETag 的操作,但据我所知 Spring 数据休息不支持这个。

您可以更改您的客户端以包含适当的 header(假设它们在您的控制之下),或者您自己实施此功能。

您可以查看 Reference Documentation 了解更多信息。

How to force clients to send etag/version using spring data rest?

简单地说:你不能,除非你写客户端。

How can I configure spring data rest to update and delete the document if and only if the client provides a valid version/etag?

这需要覆盖 PUT/DELETE /projects/1234 处理程序 Spring Data Rest 并自行处理 ETag。
为了覆盖处理程序,您需要使用 RepositoryRestController and use RequestMapping at the method level 注释您的控制器以仍然受益于 Spring.
提供的其他处理程序 要处理 ETag 部分,您可以挖掘请求 headers 的内容(通过向处理程序添加 HttpServletRequest 参数来搜索 @ESala 提到的 If-* headers。

@RepositoryRestController
public class ProjectRepositoryRestController {

    @Autowired
    private ProjectRepository repository;

    @RequestMapping(value = "/projects/{id}", method = RequestMethod.PUT)
    @ResponseBody
    public Item update(@PathVariable(value = "id") String id, @RequestBody Project, HttpServletRequest request)
    {
        /* dig into the request headers */
        // for instance
        String header = request.getHeader("If-match"); 
        // or more likely do something with request.getHeaders(...) or request.getHeaderNames(...) to check if the relevant headers are present.
        /* apply your logic on Etags */
        if (null == header) {
            throw new ARelevantException();
        }

        /* go on with the processing of the request if everything is OK */
        Project project = repository.findOne(id);
        /* perform some magic with your entity and your input data */

        project = repository.save(project);

        return project;
    }

}

要处理 header,可以使用其他选项,例如使用 RequestHeader annotation. You may also give a look at RequestEntity 立即获取请求 body 和 header(只是不要t 混合 RequestEntity 参数和@RequestBody + @RequestHeader 参数)。