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

时间:2016-04-12 13:56:59

标签: java spring-boot spring-data-rest

我们通过spring boot(v1.3.3)使用spring数据休息,并通过标准REST Repository Exporter公开以下实体:

@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

}

/例如/ project或PUT到/ projects / 1234的POST会创建一个带有etag /版本0的文档。即使客户端没有提供版本/ etag,/ projects / 1234的另一个PUT也会覆盖文档。此外,即使客户端未提供版本/ etag,/ projects / 1234上的DELETE也会删除该文档。

当且仅当客户端提供有效版本/ etag时,如何配置spring data rest以更新和删除文档?

2 个答案:

答案 0 :(得分:3)

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

If-Match: <value of previous ETag>

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

客户端负责添加条件标头。

从我理解的问题中,您希望服务器禁止任何不提供有效ETag的操作,但据我所知Spring Data Rest不支持此操作。

您可以更改客户端以包含正确的标头(假设它们在您的控制之下),或者您自己实现此功能。

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

答案 1 :(得分:2)

  

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

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

  

当且仅当客户端提供有效版本/ etag时,如何配置spring data rest以更新和删除文档?

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

@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;
    }

}

要处理标题,可以使用其他选项,例如使用RequestHeader注释。您还可以查看RequestEntity以立即获取请求正文和标题(只是不要混合RequestEntity参数和@RequestBody + @RequestHeader参数)。