6. 客户端支持

本节描述了 Spring HATEOAS 对 Client 端的支持。spring-doc.cn

6.1. 遍历

Spring HATEOAS 提供了一个用于客户端服务遍历的 API。它的灵感来自 Traverson JavaScript 库。 以下示例演示如何使用它:spring-doc.cn

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");

您可以通过将实例指向 REST 服务器并配置要设置为标头的媒体类型来设置实例。然后,您可以定义要发现和关注的关系名称。关系名称可以是简单名称或 JSONPath 表达式(以 an 开头)。TraversonAccept$spring-doc.cn

然后,该示例将 parameter map 传递到实例中。这些参数用于扩展遍历期间找到的 URI(模板化)。遍历通过访问最终遍历的表示来结束。在前面的示例中,我们评估 JSONPath 表达式以访问参与者的名称。Traversonspring-doc.cn

前面的示例是遍历的最简单版本,其中值是字符串,并且在每个跃点处应用相同的模板参数。relspring-doc.cn

每个级别都有更多选项可用于自定义模板参数。 以下示例显示了这些选项。spring-doc.cn

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);

static 函数是定义单个 .使用 使指定 URI 模板变量变得简单。rel(…​)Hop.withParameter(key, value)spring-doc.cn

.withParameter()返回一个可链接的新对象。您可以根据需要串在一起。结果是单个定义。 以下示例显示了一种执行此操作的方法:Hop.withParameterHop
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)spring-doc.cn

follow()是可链接的,这意味着您可以将多个跃点串在一起,如前面的示例所示。您可以放置多个基于字符串的值 () 或具有特定参数的单个跃点。relfollow("items", "item")

6.1.1. 与EntityModel<T>CollectionModel<T>

到目前为止显示的示例演示了如何绕过 Java 的类型擦除并将单个 JSON 格式的资源转换为对象。但是,如果您获得像 HAL 集合这样的集合怎么办? 您只需稍作调整即可执行此操作,如下例所示:EntityModel<Item>\_embeddedspring-doc.cn

CollectionModelType<Item> collectionModelType =
    TypeReferences.CollectionModelType<Item>() {};

CollectionModel<Item> itemResource = traverson.//
    follow(rel("items")).//
    toObject(collectionModelType);

此资源不是获取单个资源,而是将集合反序列化为 .CollectionModelspring-doc.cn

当使用支持超媒体的表示时,一个常见的任务是找到一个具有特定关系类型的链接。Spring HATEOAS 为默认表示渲染或开箱即用的 HAL 提供了基于 JSONPath 的接口实现。使用 时,我们会自动将支持配置的超媒体类型的实例公开为 Spring Bean。LinkDiscoverer@EnableHypermediaSupportspring-doc.cn

或者,您可以按如下方式设置和使用实例:spring-doc.cn

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 实例

如果您需要配置 a 来表示超媒体,这很容易。获取如下所示的 :WebClientHypermediaWebClientConfigurerspring-doc.cn

例 43.配置自身WebClient
@Bean
WebClient.Builder hypermediaWebClient(HypermediaWebClientConfigurer configurer) { (1)
 return configurer.registerHypermediaTypes(WebClient.builder()); (2)
}
1 在您的类中,获取 bean Spring HATEOAS 寄存器的副本。@ConfigurationHypermediaWebClientConfigurer
2 创建 后,使用配置程序注册超媒体类型。WebClient.Builder
它用 .要利用它, 您需要将构建器注入到应用程序中的某个位置,并运行该方法以生成 .HypermediaWebClientConfigurerWebClient.Builderbuild()WebClient

如果您使用的是 Spring Boot,还有另一种方法: .WebClientCustomizerspring-doc.cn

例 44.让 Spring Boot 配置内容
@Bean (4)
WebClientCustomizer hypermediaWebClientCustomizer(HypermediaWebClientConfigurer configurer) { (1)
    return webClientBuilder -> { (2)
        configurer.registerHypermediaTypes(webClientBuilder); (3)
    };
}
1 创建 Spring bean 时,请求 Spring HATEOAS 的 bean 的副本。HypermediaWebClientConfigurer
2 使用 Java 8 lambda 表达式定义 .WebClientCustomizer
3 在函数调用中,应用该方法。registerHypermediaTypes
4 将整个事情作为 Spring bean 返回,以便 Spring Boot 可以拾取它并将其应用于其自动配置的 bean。WebClient.Builder

在这个阶段,每当你需要一个具体的 ,只需注入到你的代码中,然后使用 .实例 将能够使用超媒体进行交互。WebClientWebClient.Builderbuild()WebClientspring-doc.cn

6.4. 配置实例WebTestClient

当使用支持超媒体的表示时,一个常见的任务是使用 运行各种测试。WebTestClientspring-doc.cn

要在测试用例中配置 的实例,请查看以下示例:WebTestClientspring-doc.cn

例 45.使用 Spring HATEOAS 时进行配置WebTestClient
@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 注册用于启用 HAL 支持的配置类。@EnableHypermediaSupport
2 用于应用超媒体支持。HypermediaWebTestClientConfigurer
3 请求使用 Spring HATEOAS 的 helper 的响应。CollectionModel<EntityModel<Employee>>TypeReferences.CollectionModelType
4 在获得 Spring HATEOAS 格式的 “body” 后,断言反对它!
WebTestClient是不可变的值类型,因此您无法就地更改它。 返回一个 mutated 变体,然后必须捕获该变体才能使用它。HypermediaWebClientConfigurer

如果您使用的是 Spring Boot,则还有其他选项,如下所示:spring-doc.cn

例 46.使用 Spring Boot 时配置WebTestClient
@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 的 test 注释,它将为此测试类配置 a。WebTestClient.Builder
2 将 Spring Boot 的 autowire 导入和 Spring HATEOAS 的配置器作为方法参数。WebTestClient.Builderbuilder
3 用于注册对超媒体的支持。HypermediaWebTestClientConfigurer
4 使用 .EntityModel<Employee>TypeReferences

同样,您可以使用与前面的示例类似的断言。spring-doc.cn

还有许多其他方法可以设计测试用例。 可以绑定到控制器、函数和 URL。本节并不是要展示所有这些。相反,这为您提供了一些入门示例。重要的是,通过应用 ,可以更改 的任何实例以处理超媒体。WebTestClientHypermediaWebTestClientConfigurerWebTestClientspring-doc.cn

6.5. 配置 RestTemplate 实例

如果要创建自己的 副本 ,配置为代言超媒体,则可以使用 :RestTemplateHypermediaRestTemplateConfigurerspring-doc.cn

例 47.配置您自己RestTemplate
/**
 * Use the {@link HypermediaRestTemplateConfigurer} to configure a {@link RestTemplate}.
 */
@Bean
RestTemplate hypermediaRestTemplate(HypermediaRestTemplateConfigurer configurer) { (1)
	return configurer.registerHypermediaTypes(new RestTemplate()); (2)
}
1 在您的类中,获取 bean Spring HATEOAS 寄存器的副本。@ConfigurationHypermediaRestTemplateConfigurer
2 创建 后,使用配置器应用超媒体类型。RestTemplate

你可以自由地将此模式应用于你需要的任何实例,无论是创建一个已注册的 bean,还是在你定义的服务中。RestTemplatespring-doc.cn

如果您使用的是 Spring Boot,还有另一种方法。spring-doc.cn

一般来说, Spring Boot 已经摆脱了在应用程序上下文中注册 bean 的概念。RestTemplatespring-doc.cn

  • 与不同的服务通信时,您通常需要不同的凭证。spring-doc.cn

  • 使用底层连接池时,您会遇到其他问题。RestTemplatespring-doc.cn

  • 用户通常需要不同的实例,而不是单个 bean。spring-doc.cn

为了补偿这一点, Spring Boot 提供了一个 .这个自动配置的 bean 允许你定义用于时尚的各种 bean 一个实例。您请求一个 Bean,调用其方法,然后应用最终设置(例如凭据和其他详细信息)。RestTemplateBuilderRestTemplateRestTemplateBuilderbuild()spring-doc.cn

要注册基于超媒体的消息转换器,请将以下内容添加到您的代码中:spring-doc.cn

例 48.让 Spring Boot 配置内容
@Bean (4)
RestTemplateCustomizer hypermediaRestTemplateCustomizer(HypermediaRestTemplateConfigurer configurer) { (1)
    return restTemplate -> { (2)
        configurer.registerHypermediaTypes(restTemplate); (3)
    };
}
1 创建 Spring bean 时,请求 Spring HATEOAS 的 bean 的副本。HypermediaRestTemplateConfigurer
2 使用 Java 8 lambda 表达式定义 .RestTemplateCustomizer
3 在函数调用中,应用该方法。registerHypermediaTypes
4 将整个内容作为 Spring bean 返回,以便 Spring Boot 可以拾取它并将其应用于其 autoconfigured。RestTemplateBuilder

在这个阶段,每当你需要一个具体的 ,只需注入到你的代码中,然后使用 .实例 将能够使用超媒体进行交互。RestTemplateRestTemplateBuilderbuild()RestTemplatespring-doc.cn