如何使用 Spring 数据 REST 抽象引入 ETAG 和版本标头



嗨,我正在我的项目中使用带有Jpa的spring数据rest来公开基于HAL的rest Web服务。它适用于我的大多数情况,对于进一步的自定义,我确实使用其他控制器并调用 spring 数据存储库为我获取数据,并使用 hateos 资源来显示那些通过 hateos entityLinks 公开的链接。这很棒,适用于我的大多数用例。现在我有一些额外的要求,我想为服务器缓存和实例级版本链接标头 [https://www.rfc-editor.org/rfc/rfc5988] 更具体的 https://www.rfc-editor.org/rfc/rfc5829#page-3 为我的响应放置 etag 标头。

GET/81822 HTTP/1.1...

HTTP/1.1 OK
Host: dumbserver.com
Content-Type: application/json
Link: </81822 ;v=1.1>; rel="previous";
       </81822 >; rel="current";
       </81822 /version-history>; rel="version-history";
{

这是否可以通过使用 hateos 接口来实现,或者我是否必须通过 HttpServletResponse 或 responseentity.getHeaader 添加这些接口来采用自定义方法,并添加用于处理版本控制的自定义代码。我认为 Spring 数据休息或仇恨也必须努力为这些提供抽象。

我认为一旦您从控制器覆盖 Spring Data Rest 端点,即使您的控制器带有 @RepositoryRestController 注释,您几乎必须自己滚动。

我们通过创建一个基本控制器来实现这一点,该控制器负责将我们的entity包装为Resource而又包装在ResponseEntity

我们的ETag恰好基于具有@Version注释的实体versionNumber

protected ResponseEntity<Resource<T>> createResponse(T entity, 
                   PersistentEntityResourceAssembler assembler) 
{
    def bb = ResponseEntity.ok()
    bb.eTag(ETag.from("${entity.versionNumber}").toString())
    return bb.body(createResource(entity, assembler))
}
protected Resource<T> createResource(T entity, ResourceAssembler assembler) {
    def resource = resourceCreator.toResource(assembler, entity)
    resource.add(buildSelfLink(resource))
    resource
}
Link buildSelfLink(Resource<T> resource) {
    linkBuilder.buildSelfLinkWithId(this.class, resource.content.id)
}
Link prependLinkWithApiBase(ControllerLinkBuilder linkBuilder) {
    URI uri = linkBuilder.toUri()
    String origPath = uri.rawPath
    String newPath = "$API_BASE$origPath"
    log.debug("Replacing {} with {}", origPath, newPath)
    def uriBuilder = UriComponentsBuilder.fromUri(uri).replacePath(newPath)
    new Link(uriBuilder.toUriString())
}
Link buildSelfLinkWithId(Class c, def id) {
    /*
        When trying to use `methodOn` to properly build 
        the self URI, we ran into this. 
        Going the dumb route instead.
        java.lang.ClassCastException: 
          Cannot cast com.MyEntity$$EnhancerByCGLIB$$a1654b7b
        to com.MyEntity
        at java.lang.Class.cast(Class.java:3369) ~[na:1.8.0_92]
        at org.sfw.hateoas.core.DummyInvocationUtils
            $InvocationRecordingMethodInterceptor.intercept(DummyInvocationUtils.java:100)
            ~[spring-hateoas-0.20.0.RELEASE.jar:na]
     */
    //Due to https://github.com/spring-projects/spring-hateoas/issues/434 we have hoops to jump
    def linkBuilder = linkTo(c).slash(id)
    prependLinkWithApiBase(linkBuilder)
}

最新更新