Spring HATEOAS 如何在自定义属性旁生成 HAL _embedded?
数据小陈
结论
Spring HATEOAS 的 HalModelBuilder 可以组合根级状态、_links 和 _embedded。把根级属性放在普通对象中,传给 halModelOf(...),再用 embed(collection, relation) 添加嵌入集合。若将 CollectionModel 作为另一个模型的普通属性,它通常会按属性名序列化,不会自动成为根级 _embedded。
Spring HATEOAS 从 1.1 起提供 HalModelBuilder,用于通过 HAL 风格的 API 构建表示。它可以接受任意对象作为主体,并添加嵌入文档和链接。Spring HATEOAS HAL 表示模型文档
示例
下面用一个对象保存示例中的两个根级状态字段,并将订单集合以 ea:order 关系嵌入:
import java.util.List;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.hal.HalModelBuilder;
record OrdersState(int currentlyProcessing, int shippedToday) {}
List<EntityModel<Order>> orderResources = List.of(
EntityModel.of(firstOrder)
.add(Link.of("/orders/123").withSelfRel()),
EntityModel.of(secondOrder)
.add(Link.of("/orders/124").withSelfRel())
);
RepresentationModel<?> model = HalModelBuilder
.halModelOf(new OrdersState(14, 20))
.link(Link.of("/orders").withSelfRel())
.embed(orderResources, LinkRelation.of("ea:order"))
.build();
Order、firstOrder 和 secondOrder 分别代表应用自己的订单类型和数据。示例中的 EntityModel 为每个嵌入的订单附加了 self 链接。实际使用时,也可以继续添加 ea:basket、ea:customer 等链接。若运行环境不支持 Java record,可以将 OrdersState 换成带有可序列化属性的普通 Java 类。
HalModelBuilder 的 embed(Collection<?>, LinkRelation) 重载可以显式指定集合在 _embedded 中的关系名。即使集合为空,也能通过这个重载保留关系名。HalModelBuilder API
需要留意的地方
LinkRelation.of("ea:order")指定关系名。要让带ea:前缀的关系与 CURIE 配合使用,还需在 HAL 配置中提供对应的 CURIE。问题中的示例暂时排除了 CURIES,因此这里不展开配置。- 直接嵌入普通
Order对象时,对象是否包含各自的链接,取决于对象类型和序列化方式。如果需要让每个订单都显示_links,传入带链接的EntityModel<Order>会更明确。 - 如果集合为空,但仍要输出
ea:order: [],应使用带显式关系名的embed重载。仅根据集合元素推导关系名时,空集合没有元素可供推导。
要生成根级 _embedded,可以用 HalModelBuilder 设置根级主体、链接和嵌入项;业务字段则由根级状态对象承载。
备注:内容仅供参考。
