6. 客户端支持
本节介绍 Spring HATEOAS 对客户端的支持。
6.1. 特拉弗森
Spring HATEOAS 提供了一个用于客户端服务遍历的 API。它的灵感来自Traverson JavaScript库。 以下示例演示如何使用它:
Map<String, Object> parameters = new HashMap<>();
parameters.put("user", 27);
Traverson traverson = new Traverson(URI.create("http://localhost:8080/api/"), MediaTypes.HAL_JSON);
String name = traverson
.follow("movies", "movie", "actor").withTemplateParameters(parameters)
.toObject("$.name");
您可以设置一个Traverson
实例,方法是将其指向 REST 服务器并配置要设置为的媒体类型Accept
头。然后,您可以定义要发现和关注的关系名称。关系名称可以是简单名称或 JSONPath 表达式(以 开头)。$
然后,样本将参数映射交给Traverson
实例。这些参数用于扩展遍历期间找到的 URI(模板化)。通过访问最终遍历的表示来结束遍历。在前面的示例中,我们计算 JSONPath 表达式以访问参与者的名称。
前面的示例是遍历的最简单版本,其中rel
值是字符串,在每个跃点中,都会应用相同的模板参数。
每个级别都有更多选项可以自定义模板参数。 以下示例显示了这些选项。
ParameterizedTypeReference<EntityModel<Item>> resourceParameterizedTypeReference = new ParameterizedTypeReference<EntityModel<Item>>() {};
EntityModel<Item> itemResource = traverson.//
follow(rel("items").withParameter("projection", "noImages")).//
follow("$._embedded.items[0]._links.self.href").//
toObject(resourceParameterizedTypeReference);
静态rel(…)
function 是定义单个Hop
.用.withParameter(key, value)
使指定 URI 模板变量变得简单。
.withParameter() 返回一个新的Hop 可链接的对象。您可以将任意数量串在一起.withParameter 随心所欲。结果是单一Hop 定义。
以下示例显示了一种执行此作的方法: |
ParameterizedTypeReference<EntityModel<Item>> resourceParameterizedTypeReference = new ParameterizedTypeReference<EntityModel<Item>>() {};
Map<String, Object> params = Collections.singletonMap("projection", "noImages");
EntityModel<Item> itemResource = traverson.//
follow(rel("items").withParameters(params)).//
follow("$._embedded.items[0]._links.self.href").//
toObject(resourceParameterizedTypeReference);
您还可以加载整个Map
参数的.withParameters(Map)
.
follow() 是可链接的,这意味着您可以将多个跃点串在一起,如前面的示例所示。您可以放置多个基于字符串的rel 值 (follow("items", "item") ) 或具有特定参数的单跃点。 |
6.1.1.EntityModel<T>
与。CollectionModel<T>
到目前为止显示的示例演示了如何避开 Java 的类型擦除并将单个 JSON 格式的资源转换为EntityModel<Item>
对象。但是,如果您获得像\_embedded
HAL 系列?
只需稍作调整即可做到这一点,如以下示例所示:
CollectionModelType<Item> collectionModelType =
new TypeReferences.CollectionModelType<Item>() {};
CollectionModel<Item> itemResource = traverson.//
follow(rel("items")).//
toObject(collectionModelType);
这个资源不是获取单个资源,而是将集合反序列化为CollectionModel
.
6.2. 使用LinkDiscoverer
实例
在使用启用了超媒体的表示时,一项常见任务是找到具有特定关系类型的链接。Spring HATEOAS 提供了基于 JSONPath 的LinkDiscoverer
界面,用于默认表示渲染或开箱即用的 HAL。使用时@EnableHypermediaSupport
,我们会自动将支持配置的超媒体类型的实例公开为 Spring bean。
或者,您可以按如下方式设置和使用实例:
String content = "{'_links' : { 'foo' : { 'href' : '/foo/bar' }}}";
LinkDiscoverer discoverer = new HalLinkDiscoverer();
Link link = discoverer.findLinkWithRel("foo", content);
assertThat(link.getRel(), is("foo"));
assertThat(link.getHref(), is("/foo/bar"));
6.3. 配置WebClient实例
如果需要配置WebClient
说到超媒体,这很容易。获取HypermediaWebClientConfigurer
如下图所示:
WebClient
你自己@Bean
WebClient.Builder hypermediaWebClient(HypermediaWebClientConfigurer configurer) { (1)
return configurer.registerHypermediaTypes(WebClient.builder()); (2)
}
1 | 在您的内部@Configuration 类,获取HypermediaWebClientConfigurer 豆弹簧 HATEOAS 寄存器。 |
2 | 创建WebClient.Builder ,则使用配置器注册超媒体类型。 |
什么HypermediaWebClientConfigurer 它是否注册了所有正确的编码器和解码器WebClient.Builder .为了利用它,
您需要将构建器注入到应用程序的某个位置,并运行build() 生成WebClient . |
如果您使用的是 Spring Boot,还有另一种方法:WebClientCustomizer
.
@Bean (4)
WebClientCustomizer hypermediaWebClientCustomizer(HypermediaWebClientConfigurer configurer) { (1)
return webClientBuilder -> { (2)
configurer.registerHypermediaTypes(webClientBuilder); (3)
};
}
1 | 创建 Spring bean 时,请求 Spring HATEOAS 的HypermediaWebClientConfigurer 豆。 |
2 | 使用 Java 8 lambda 表达式定义WebClientCustomizer . |
3 | 在函数调用中,应用registerHypermediaTypes 方法。 |
4 | 将整个内容作为 Spring bean 返回,以便 Spring Boot 可以拾取它并将其应用于其自动配置的WebClient.Builder 豆。 |
在这个阶段,每当您需要混凝土WebClient
,只需注射WebClient.Builder
到代码中,然后使用build()
.这WebClient
实例
将能够使用超媒体进行交互。
6.4. 配置WebTestClient
实例
在使用启用超媒体的表示时,一个常见的任务是使用WebTestClient
.
配置WebTestClient
在测试用例中,请查看以下示例:
WebTestClient
使用 Spring HATEOAS 时@Test // #1225
void webTestClientShouldSupportHypermediaDeserialization() {
// Configure an application context programmatically.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(HalConfig.class); (1)
context.refresh();
// Create an instance of a controller for testing
WebFluxEmployeeController controller = context.getBean(WebFluxEmployeeController.class);
controller.reset();
// Extract the WebTestClientConfigurer from the app context.
HypermediaWebTestClientConfigurer configurer = context.getBean(HypermediaWebTestClientConfigurer.class);
// Create a WebTestClient by binding to the controller and applying the hypermedia configurer.
WebTestClient client = WebTestClient.bindToApplicationContext(context).build().mutateWith(configurer); (2)
// Exercise the controller.
client.get().uri("http://localhost/employees").accept(HAL_JSON) //
.exchange() //
.expectStatus().isOk() //
.expectBody(new TypeReferences.CollectionModelType<EntityModel<Employee>>() {}) (3)
.consumeWith(result -> {
CollectionModel<EntityModel<Employee>> model = result.getResponseBody(); (4)
// Assert against the hypermedia model.
assertThat(model.getRequiredLink(IanaLinkRelations.SELF)).isEqualTo(Link.of("http://localhost/employees"));
assertThat(model.getContent()).hasSize(2);
});
}
1 | 注册使用@EnableHypermediaSupport 以启用 HAL 支持。 |
2 | 用HypermediaWebTestClientConfigurer 以应用超媒体支持。 |
3 | 要求回复CollectionModel<EntityModel<Employee>> 使用 Spring HATEOAS 的TypeReferences.CollectionModelType 助手。 |
4 | 在获得 Spring HATEOAS 格式的“身体”后,断言反对它! |
WebTestClient 是不可变的值类型,因此您无法就地更改它。HypermediaWebClientConfigurer 返回一个
然后您必须捕获该变体才能使用它。 |
如果您使用的是 Spring Boot,还有其他选项,如下所示:
WebTestClient
使用 Spring Boot 时@SpringBootTest
@AutoConfigureWebTestClient (1)
class WebClientBasedTests {
@Test
void exampleTest(@Autowired WebTestClient.Builder builder, @Autowired HypermediaWebTestClientConfigurer configurer) { (2)
client = builder.apply(configurer).build(); (3)
client.get().uri("/") //
.exchange() //
.expectBody(new TypeReferences.EntityModelType<Employee>() {}) (4)
.consumeWith(result -> {
// assert against this EntityModel<Employee>!
});
}
}
1 | 这是 Spring Boot 的测试注解,它将配置一个WebTestClient.Builder 对于这个测试类。 |
2 | Autowire 弹簧靴的WebTestClient.Builder 到builder 和 Spring HATEOAS 的配置器作为方法参数。 |
3 | 用HypermediaWebTestClientConfigurer 以注册对超媒体的支持。 |
4 | 表示您想要一个EntityModel<Employee> 使用TypeReferences . |
同样,您可以使用与前面示例类似的断言。
还有许多其他方法来构建测试用例。WebTestClient
可以绑定到控制器、函数和 URL。本节并不打算展示所有这些。相反,这提供了一些入门示例。重要的是,通过申请HypermediaWebTestClientConfigurer
,任何实例WebTestClient
可以更改以处理超媒体。
6.5. 配置 RestTemplate 实例
如果您想创建自己的副本RestTemplate
,配置为说超媒体,您可以使用HypermediaRestTemplateConfigurer
:
RestTemplate
你自己/**
* Use the {@link HypermediaRestTemplateConfigurer} to configure a {@link RestTemplate}.
*/
@Bean
RestTemplate hypermediaRestTemplate(HypermediaRestTemplateConfigurer configurer) { (1)
return configurer.registerHypermediaTypes(new RestTemplate()); (2)
}
1 | 在您的内部@Configuration 类,获取HypermediaRestTemplateConfigurer 豆弹簧 HATEOAS 寄存器。 |
2 | 创建RestTemplate ,请使用配置器应用超媒体类型。 |
您可以自由地将此模式应用于RestTemplate
无论是创建已注册的 bean,还是在您定义的服务中。
如果您使用的是 Spring Boot,还有另一种方法。
总的来说,Spring Boot 已经放弃了注册RestTemplate
bean 的 bean 中。
-
与不同的服务通信时,您通常需要不同的凭据。
-
什么时候
RestTemplate
使用底层连接池时,您会遇到其他问题。 -
用户通常需要不同的实例而不是单个 bean。
为了弥补这一点,Spring Boot 提供了一个RestTemplateBuilder
.这个自动配置的 bean 允许您定义用于
一个RestTemplate
实例。你要求一个RestTemplateBuilder
bean,调用其build()
方法,然后应用最终设置(例如凭据和其他详细信息)。
若要注册基于超媒体的消息转换器,请将以下内容添加到代码中:
@Bean (4)
RestTemplateCustomizer hypermediaRestTemplateCustomizer(HypermediaRestTemplateConfigurer configurer) { (1)
return restTemplate -> { (2)
configurer.registerHypermediaTypes(restTemplate); (3)
};
}
1 | 创建 Spring bean 时,请求 Spring HATEOAS 的HypermediaRestTemplateConfigurer 豆。 |
2 | 使用 Java 8 lambda 表达式定义RestTemplateCustomizer . |
3 | 在函数调用中,应用registerHypermediaTypes 方法。 |
4 | 将整个内容作为 Spring bean 返回,以便 Spring Boot 可以拾取它并将其应用于其自动配置的RestTemplateBuilder . |
在这个阶段,每当您需要混凝土RestTemplate
,只需注射RestTemplateBuilder
到代码中,然后使用build()
.这RestTemplate
实例
将能够使用超媒体进行交互。