gpt4 book ai didi

spring - 在 Spring Boot 中为自定义 Controller 方法启用 HAL 序列化

转载 作者:IT老高 更新时间:2023-10-28 13:47:59 25 4
gpt4 key购买 nike

我正在尝试使用 spring-boot-starter-data-rest 使用 Spring Boot 构建一个 RESTful API。有一些实体:帐户、交易、类别和用户 - 只是普通的东西。

当我在 http://localhost:8080/transactions 检索对象时通过默认生成的 API,一切顺利,我得到了一个列表,其中包含所有事务作为 JSON 对象,如下所示:

{
"amount": -4.81,
"date": "2014-06-17T21:18:00.000+0000",
"description": "Pizza",
"_links": {
"self": {
"href": "http://localhost:8080/transactions/5"
},
"category": {
"href": "http://localhost:8080/transactions/5/category"
},
"account": {
"href": "http://localhost:8080/transactions/5/account"
}
}
}

但现在的目标是只检索该 URL 下的最新事务,因为我不想序列化整个数据库表。于是我写了一个Controller:

@Controller
public class TransactionController {
private final TransactionRepository transactionRepository;

@Autowired
public TransactionController(TransactionRepository transactionRepository) {
this.transactionRepository = transactionRepository;
}

// return the 5 latest transactions
@RequestMapping(value = "/transactions", method = RequestMethod.GET)
public @ResponseBody List<Transaction> getLastTransactions() {
return transactionRepository.findAll(new PageRequest(0, 5, new Sort(new Sort.Order(Sort.Direction.DESC, "date")))).getContent();
}
}

当我现在尝试访问 http://localhost:8080/transactions 时有一个

java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

因为用户和帐户之间的循环引用。当我通过向用户中的帐户列表添加@JsonBackReference 注释来解决此问题时,我可以检索交易列表,但只能使用这种“经典”格式:

{
"id": 5,
"amount": -4.5,
"date": "2014-06-17T21:18:00.000+0000",
"description": "Pizza",
"account": {
"id": 2,
"name": "Account Tilman",
"owner": {
"id": 1,
"name": "Tilman"
},
"categories": [
{
"id": 1,
"name": "Groceries"
},
{
"id": 2,
"name": "Restaurant"
}
],
"users": [
{
"id": 1,
"name": "Tilman"
}
]
},
"category": {
"id": 2,
"name": "Restaurant"
}
}

不再有 HAL 链接,一切都由 jackson 直接序列化。我尝试添加

@EnableHypermediaSupport(type = HypermediaType.HAL)

到实体类,但这并没有让我到任何地方。我只希望我的 Controller 返回与生成的 API 相同的对象,使用 HAL _links 而不是序列化每个引用。有什么想法吗?

编辑:好的,经过深思熟虑,我意识到@EnableHypermediaSupport 注释必须添加到配置,当然。这解决了循环引用的问题,我可以从用户中删除 @JsonBackReference。但是只有对象本身的属性被序列化,没有_links部分:

{
"amount": -4.81,
"date": "2014-06-17T21:18:00.000+0000",
"description": "Pizza"
}

我知道我可以为我的所有实体编写扩展 ResourceSupport 的包装类,但这似乎毫无意义。由于 spring-hateoas 能够神奇地使用自动创建的 REST 接口(interface)的 _link 部分生成表示,因此应该有一种方法可以从自定义 Controller 返回相同的表示,对吧?

最佳答案

这里有很多方面:

  1. 我怀疑 /transactions 的收藏资源如您所述,确实返回了单个交易。为项目资源返回这些表示。

  2. 如果 TransactionRepository已经是 PageableAndSortingRepository可以通过扩展在 API 根中为名为 transactions 的链接公开的 URI 模板来调整集合资源.默认情况下是 page , sizesort范围。这意味着客户已经可以请求您想要公开的内容。

  3. 如果你想默认分页和排序选项,实现 Controller 是正确的方法。但是,要实现像 Spring Data REST 公开这样的表示,您至少需要返回 ResourceSupport 的实例。因为这是注册 HAL 映射的类型。

    如果你仔细想想,这里并没有什么神奇之处。普通实体没有任何链接,ResourcesSupport和类型如 Resource<T>允许您包装实体并使用您认为合适的链接来丰富它。 Spring Data REST 基本上为您使用大量关于隐式可用的域和存储库结构的知识。您可以重复使用很多,如下所示。

    这里有一些你需要注意的助手:

    • PersistentEntityResourceAssembler - 通常注入(inject)到 Controller 方法中。它以 Spring Data REST 方式呈现单个实体,这意味着指向托管类型的关联将呈现为链接等。
    • PagedResourcesAssembler - 通常注入(inject) Controller instance。负责准备页面中包含的项目,可选择使用专用的 ResourceAssembler .

    Spring Data REST 对页面的基本作用如下:

    PersistentEntityResourceAssembler entityAssembler = …;
    Resources<?> … = pagedResourcesAssembler.toResources(page, entityAssembler);

    这基本上是使用 PagedResourcesAssemblerPersistentEntityResourceAssembler渲染项目。

    返回 Resources实例应该会给你你期望的表示设计。

关于spring - 在 Spring Boot 中为自定义 Controller 方法启用 HAL 序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31758862/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com