Spring Hateoas 渲染 HAL 内容的问题
Spring Hateoas issues rendering HAL content
我一直在检查类似的问题,但没有找到任何解决我所观察到的问题的答案。
问题是,当我检索 1 个资源时,我很容易设法在我的 REST API 中获得 HAL 格式的超媒体,但是当我点击控制器方法检索实体列表时,然后是超媒体不一样。
输出如下:
单个资源 returned
</p>
<p>“_链接”:{
“自己”: {
"href": "http://localhost:8080/celsvs/api/books/123567891099"
},
“书籍”:{
"href": "http://localhost:8080/celsvs/api/books"
}
}</p>
</li>
</ul>
资源列表
</p>
<p>“链接”:[
{
“rel”:“自我”,
"href": "http://localhost:8080/celsvs/api/books/123567891099"
},
{
“rel”:“书籍”,
"href": "http://localhost:8080/celsvs/api/books"
}
]</p>
</li>
</ul>
我从 Spring hateoas 0.25 开始,但无论如何我都必须提升 Spring 引导,我看到 Hateoas API 已经改变,我现在在 Spring hateoas 1.0...甚至在我的代码适应新的 API 我仍然得到相同的结果。
我正在使用 RepresentationModelAssemblerSupport class 让我的控制器远离代码以生成 hateoas 内容。这就是它的样子:
<pre><code>@Component
public class BookModelAssembler extends RepresentationModelAssemblerSupport<BookDto, BookDto> {
public BookModelAssembler() {
super(BooksController.class, BookDto.class);
}
@Override
public BookDto toModel(BookDto entity) {
return entity.add(linkTo(methodOn(BooksController.class).getResource(entity.getIsbn())).withSelfRel())
.add(linkTo(methodOn(BooksController.class).getAllResources()).withRel("books"));
}
}
并且在 Controller 中,用于检索一个或所有资源的端点:
<pre><code>@Override
@GetMapping(value = {QueryConstants.BOOKS_ISBN_PATH, QueryConstants.BOOKS_SIG_PATH})
public BookDto getResource(@PathVariable("isbn") final String isbn) {
return this.modelAssembler.toModel(this.findOneResource(isbn));
}
// GET - retrieve all resources
@Override
@GetMapping (produces = { "application/hal+json" })
public List<BookDto> getAllResources() {
return (findAllResources().stream().map(this.modelAssembler::toModel).collect(Collectors.toList()));
}
如您所见,即使列表中的所有实体 returned 都使用方法 getResource() 中使用的相同方法 toModel() 进行映射,呈现的超媒体也不同。
我设法在所有资源的情况下看到正确的 HAL 格式 returned 的唯一方法是当我将控制器的实现更改为 return 集合模型时:
<pre><code>//@GetMapping
public CollectionModel<BookDto> getAll() {
return this.modelAssembler.toCollectionModel(findAllResources());
}
但是所有实体都捆绑在一个 _embedded 元素中,这不是我 return 实体集合时想要的。
Spring Hateoas 文档指出 HAL 是默认设置,所以我暂时没有考虑配置任何东西...
所以,我只看到:
- 我缺少一些配置,以便当我可以获得呈现的实体集合时(不在 _embedded 元素下)...但是我没有在 HalConfiguration bean 中看到任何合适的东西。
- 我假设 return 收集请求的资源类型的正确方法不在 _embedded 属性 中...但也许我错了。到目前为止,我的理解是,当你请求资源 Person 并且你想要 return 它的联系人时,这些联系人也可以通过他们自己的端点直接访问,然后你将它们嵌入到内容中 returned与其余的 Person 属性......我没有发现任何说明集合应该在 _embedded 属性.
内呈现的内容
有人有什么建议吗?我 运行 没有时间和想法,实现客户端的团队正在等待使用超媒体内容。
谢谢!
HAL specification表示属性_embedded
用于存放资源对象数组
编辑:
在他自己的回答中回答阿尔贝托的问题
Still, if someone can tell me why in the previous implementation the attached links did not follow the HAL format, I would appreciate. Thanks
Spring HATEOAS 自定义 JSON RepresentationModel
的序列化,RepresentationModel
是 CollectionModel
的父 class。
// org.springframework.hateoas.mediatype.hal.RepresentationModelMixin
public abstract class RepresentationModelMixin extends RepresentationModel<RepresentationModelMixin> {
@Override
@JsonProperty("_links")
@JsonInclude(Include.NON_EMPTY)
@JsonSerialize(using = Jackson2HalModule.HalLinkListSerializer.class)
@JsonDeserialize(using = Jackson2HalModule.HalLinkListDeserializer.class)
public abstract Links getLinks();
}
@JsonProperty("_links")
将 JSON 属性 名称定义为 _links
。 @JsonSerialize 定义要使用的序列化程序。查看序列化逻辑的方法 org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize
。
经过更多阅读,我下定决心并得出结论,在响应中发回的正确内容是 _embedded 元素中的集合。
我关注了几个参考资料:
- JSON HAL rfc draft 的第 6 节(这是我找到的最新版本),有一个文档示例 returned 作为资源列表请求的结果,它们的列表嵌入在 _embedded 元素内的数组中。
- 在其他作者专门针对 Collections 的部分中,解释是相同的,并且集合的元素 returned 在 _embedded 属性 中。
因此与此一致,如果我将控制器更改为 return CollectionModel,那么我将获得在 HAL 中格式化的正确内容。
代码为:
@GetMapping
public CollectionModel<BookDto> getAll() {
return this.modelAssembler.toCollectionModel(findAllResources()).add(linkTo(methodOn(BooksController.class).getAll()).withSelfRel());
}
结果是:
{
"_embedded": {
"bookDtoList": [
{
"isbn": "123567891099",
"signature": "AA-23-EEE",
"title": "Electromagnetismo",
"subtitle": "Introducción a las aplicaciones del electromagnetismo",
"authors": [
"Idoia Mendieta",
"Bonifacio Pérez"
],
"available": false,
"numOfCopies": 0,
"library": null,
"detailedInfo": null,
"_links": {
"self": {
"href": "http://localhost:8080/celsvs/api/books/123567891099"
},
"books": {
"href": "http://localhost:8080/celsvs/api/books"
}
}
},
{
"isbn": "123567891012",
"signature": "AA-23-EFD",
"title": "Electromagnetismo",
"subtitle": "Introducción a las aplicaciones del electromagnetismo",
"authors": [
"Idoia Mendieta",
"Bonifacio Pérez"
],
"available": false,
"numOfCopies": 0,
"library": null,
"detailedInfo": null,
"_links": {
"self": {
"href": "http://localhost:8080/celsvs/api/books/123567891012"
},
"books": {
"href": "http://localhost:8080/celsvs/api/books"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/celsvs/api/books"
}
}
}
不过,如果有人能告诉我为什么在以前的实现中附加链接不遵循 HAL 格式,我将不胜感激。谢谢
我一直在检查类似的问题,但没有找到任何解决我所观察到的问题的答案。
问题是,当我检索 1 个资源时,我很容易设法在我的 REST API 中获得 HAL 格式的超媒体,但是当我点击控制器方法检索实体列表时,然后是超媒体不一样。
输出如下:
单个资源 returned
</p> <p>“_链接”:{ “自己”: { "href": "http://localhost:8080/celsvs/api/books/123567891099" }, “书籍”:{ "href": "http://localhost:8080/celsvs/api/books" } }</p> </li> </ul>
资源列表
</p> <p>“链接”:[ { “rel”:“自我”, "href": "http://localhost:8080/celsvs/api/books/123567891099" }, { “rel”:“书籍”, "href": "http://localhost:8080/celsvs/api/books" } ]</p> </li> </ul>
我从 Spring hateoas 0.25 开始,但无论如何我都必须提升 Spring 引导,我看到 Hateoas API 已经改变,我现在在 Spring hateoas 1.0...甚至在我的代码适应新的 API 我仍然得到相同的结果。
我正在使用 RepresentationModelAssemblerSupport class 让我的控制器远离代码以生成 hateoas 内容。这就是它的样子:
<pre><code>@Component public class BookModelAssembler extends RepresentationModelAssemblerSupport<BookDto, BookDto> { public BookModelAssembler() { super(BooksController.class, BookDto.class); } @Override public BookDto toModel(BookDto entity) { return entity.add(linkTo(methodOn(BooksController.class).getResource(entity.getIsbn())).withSelfRel()) .add(linkTo(methodOn(BooksController.class).getAllResources()).withRel("books")); } }
并且在 Controller 中,用于检索一个或所有资源的端点:
<pre><code>@Override @GetMapping(value = {QueryConstants.BOOKS_ISBN_PATH, QueryConstants.BOOKS_SIG_PATH}) public BookDto getResource(@PathVariable("isbn") final String isbn) { return this.modelAssembler.toModel(this.findOneResource(isbn)); } // GET - retrieve all resources @Override @GetMapping (produces = { "application/hal+json" }) public List<BookDto> getAllResources() { return (findAllResources().stream().map(this.modelAssembler::toModel).collect(Collectors.toList())); }
如您所见,即使列表中的所有实体 returned 都使用方法 getResource() 中使用的相同方法 toModel() 进行映射,呈现的超媒体也不同。
我设法在所有资源的情况下看到正确的 HAL 格式 returned 的唯一方法是当我将控制器的实现更改为 return 集合模型时:
<pre><code>//@GetMapping public CollectionModel<BookDto> getAll() { return this.modelAssembler.toCollectionModel(findAllResources()); }
但是所有实体都捆绑在一个 _embedded 元素中,这不是我 return 实体集合时想要的。
Spring Hateoas 文档指出 HAL 是默认设置,所以我暂时没有考虑配置任何东西...
所以,我只看到:
- 我缺少一些配置,以便当我可以获得呈现的实体集合时(不在 _embedded 元素下)...但是我没有在 HalConfiguration bean 中看到任何合适的东西。
- 我假设 return 收集请求的资源类型的正确方法不在 _embedded 属性 中...但也许我错了。到目前为止,我的理解是,当你请求资源 Person 并且你想要 return 它的联系人时,这些联系人也可以通过他们自己的端点直接访问,然后你将它们嵌入到内容中 returned与其余的 Person 属性......我没有发现任何说明集合应该在 _embedded 属性. 内呈现的内容
有人有什么建议吗?我 运行 没有时间和想法,实现客户端的团队正在等待使用超媒体内容。 谢谢!
HAL specification表示属性_embedded
用于存放资源对象数组
编辑: 在他自己的回答中回答阿尔贝托的问题
Still, if someone can tell me why in the previous implementation the attached links did not follow the HAL format, I would appreciate. Thanks
Spring HATEOAS 自定义 JSON RepresentationModel
的序列化,RepresentationModel
是 CollectionModel
的父 class。
// org.springframework.hateoas.mediatype.hal.RepresentationModelMixin
public abstract class RepresentationModelMixin extends RepresentationModel<RepresentationModelMixin> {
@Override
@JsonProperty("_links")
@JsonInclude(Include.NON_EMPTY)
@JsonSerialize(using = Jackson2HalModule.HalLinkListSerializer.class)
@JsonDeserialize(using = Jackson2HalModule.HalLinkListDeserializer.class)
public abstract Links getLinks();
}
@JsonProperty("_links")
将 JSON 属性 名称定义为 _links
。 @JsonSerialize 定义要使用的序列化程序。查看序列化逻辑的方法 org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize
。
经过更多阅读,我下定决心并得出结论,在响应中发回的正确内容是 _embedded 元素中的集合。
我关注了几个参考资料:
- JSON HAL rfc draft 的第 6 节(这是我找到的最新版本),有一个文档示例 returned 作为资源列表请求的结果,它们的列表嵌入在 _embedded 元素内的数组中。
- 在其他作者专门针对 Collections 的部分中,解释是相同的,并且集合的元素 returned 在 _embedded 属性 中。
因此与此一致,如果我将控制器更改为 return CollectionModel,那么我将获得在 HAL 中格式化的正确内容。
代码为:
@GetMapping
public CollectionModel<BookDto> getAll() {
return this.modelAssembler.toCollectionModel(findAllResources()).add(linkTo(methodOn(BooksController.class).getAll()).withSelfRel());
}
结果是:
{
"_embedded": {
"bookDtoList": [
{
"isbn": "123567891099",
"signature": "AA-23-EEE",
"title": "Electromagnetismo",
"subtitle": "Introducción a las aplicaciones del electromagnetismo",
"authors": [
"Idoia Mendieta",
"Bonifacio Pérez"
],
"available": false,
"numOfCopies": 0,
"library": null,
"detailedInfo": null,
"_links": {
"self": {
"href": "http://localhost:8080/celsvs/api/books/123567891099"
},
"books": {
"href": "http://localhost:8080/celsvs/api/books"
}
}
},
{
"isbn": "123567891012",
"signature": "AA-23-EFD",
"title": "Electromagnetismo",
"subtitle": "Introducción a las aplicaciones del electromagnetismo",
"authors": [
"Idoia Mendieta",
"Bonifacio Pérez"
],
"available": false,
"numOfCopies": 0,
"library": null,
"detailedInfo": null,
"_links": {
"self": {
"href": "http://localhost:8080/celsvs/api/books/123567891012"
},
"books": {
"href": "http://localhost:8080/celsvs/api/books"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/celsvs/api/books"
}
}
}
不过,如果有人能告诉我为什么在以前的实现中附加链接不遵循 HAL 格式,我将不胜感激。谢谢