2. 基本原理
本节涵盖了 Spring HATEOAS 的基础知识及其基本域抽象。
2.1. 链接
超媒体的基本思想是用超媒体元素来丰富资源的表示。 最简单的形式是链接。 它们指示客户端可以导航到特定资源。 相关资源的语义在所谓的链接关系中定义。 您可能已经在 HTML 文件的头上看到了这一点:
<link href="theme.css" rel="stylesheet" type="text/css" />
如您所见,该链接指向一个资源,并指示它是一个样式表。
链接通常包含其他信息,例如资源指向的媒体类型将返回。
但是,链接的基本构建块是其引用和关系。theme.css
Spring HATEOAS 允许你通过其不可变的值类型使用链接。
它的构造函数同时采用超文本引用和链接关系,后者默认为 IANA link relation 。
在 Link relations 中阅读更多关于后者的信息。Link
self
Link link = Link.of("/something");
assertThat(link.getHref()).isEqualTo("/something");
assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF);
link = Link.of("/something", "my-rel");
assertThat(link.getHref()).isEqualTo("/something");
assertThat(link.getRel()).isEqualTo(LinkRelation.of("my-rel"));
Link
公开 RFC-8288 中定义的其他属性。
你可以通过在实例上调用相应的 wither 方法来设置它们。Link
有关如何创建指向 Spring MVC 和 Spring WebFlux 控制器的链接的更多信息,请参阅在 Spring MVC 中构建链接和在 Spring WebFlux 中构建链接。
2.2. URI 模板
对于 Spring HATEOAS ,超文本引用不仅可以是 URI,还可以是符合 RFC-6570 的 URI 模板。
URI 模板包含所谓的模板变量,并允许扩展这些参数。
这允许客户端将参数化模板转换为 URI,而无需了解最终 URI 的结构,它只需要知道变量的名称。Link
Link link = Link.of("/{segment}/something{?parameter}");
assertThat(link.isTemplated()).isTrue(); (1)
assertThat(link.getVariableNames()).contains("segment", "parameter"); (2)
Map<String, Object> values = new HashMap<>();
values.put("segment", "path");
values.put("parameter", 42);
assertThat(link.expand(values).getHref()) (3)
.isEqualTo("/path/something?parameter=42");
1 | 该实例指示 已模板化,即它包含一个 URI 模板。Link |
2 | 它公开模板中包含的参数。 |
3 | 它允许扩展参数。 |
可以手动构建 URI 模板,并在以后添加模板变量。
UriTemplate template = UriTemplate.of("/{segment}/something")
.with(new TemplateVariable("parameter", VariableType.REQUEST_PARAM);
assertThat(template.toString()).isEqualTo("/{segment}/something{?parameter}");
2.3. 链接关系
为了指示目标资源与当前资源的关系,使用了所谓的链接关系。
Spring HATEOAS 提供了一种类型,可以轻松创建基于它的实例。LinkRelation
String
2.3.1. IANA 链接关系
Internet Assigned Numbers Authority 包含一组预定义的链接关系。
可以通过以下方式引用它们。IanaLinkRelations
Link link = Link.of("/some-resource"), IanaLinkRelations.NEXT);
assertThat(link.getRel()).isEqualTo(LinkRelation.of("next"));
assertThat(IanaLinkRelation.isIanaRel(link.getRel())).isTrue();
2.4. 表示模型
为了轻松创建超媒体丰富的表示形式,Spring HATEOAS 提供了一组以 为根的类。
它基本上是一个 s 集合的容器,并且有将它们添加到模型中的便捷方法。
这些模型稍后可以渲染为各种媒体类型格式,这些格式将定义超媒体元素在表示中的外观。
有关更多信息,请查看 媒体类型.RepresentationModel
Link
RepresentationModel
class RepresentationModel class EntityModel class CollectionModel class PagedModel EntityModel -|> RepresentationModel CollectionModel -|> RepresentationModel PagedModel -|> CollectionModel
使用 a 的默认方法是创建它的子类以包含表示应该包含的所有属性,创建该类的实例,填充属性并使用链接来丰富它。RepresentationModel
class PersonModel extends RepresentationModel<PersonModel> {
String firstname, lastname;
}
通用的自类型化是 let 返回自身实例的必要条件。
模型类型现在可以像这样使用:RepresentationModel.add(…)
PersonModel model = new PersonModel();
model.firstname = "Dave";
model.lastname = "Matthews";
model.add(Link.of("https://myhost/people/42"));
如果您从 Spring MVC 或 WebFlux 控制器返回这样的实例,并且 Client 端发送了一个 Headers set to ,则响应将如下所示:Accept
application/hal+json
{ "_links" : { "self" : { "href" : "https://myhost/people/42" } }, "firstname" : "Dave", "lastname" : "Matthews" }
2.4.1. Item 资源表示模型
对于由单个对象或概念支持的资源,存在便捷类型。
您无需为每个概念创建自定义模型类型,只需重用已存在的类型并将其实例包装到 .EntityModel
EntityModel
EntityModel
Person person = new Person("Dave", "Matthews");
EntityModel<Person> model = EntityModel.of(person);
2.4.2. 集合资源表示模型
对于概念上是集合的资源,a 可用。
它的元素可以是简单对象,也可以是实例。CollectionModel
RepresentationModel
CollectionModel
Collection<Person> people = Collections.singleton(new Person("Dave", "Matthews"));
CollectionModel<Person> model = CollectionModel.of(people);
虽然 an 被限制为始终包含有效负载,因此允许推理唯一实例上的类型排列,但 a 的基础集合可以为空。
由于 Java 的类型擦除,我们实际上无法检测到 a 实际上是 a,因为我们看到的只是运行时实例和一个空集合。
该缺失的类型信息可以通过在构造时通过或作为回退(如果底层集合可能为空)添加到模型中:EntityModel
CollectionModel
CollectionModel<Person> model = CollectionModel.empty()
CollectionModel<Person>
CollectionModel.empty(Person.class)
Iterable<Person> people = repository.findAll();
var model = CollectionModel.of(people).withFallbackType(Person.class);