嗨,我正在我的项目中使用带有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)
}