网站首页 > 技术文章 正文
问题
你需要为你的应用程序连接到一个REST资源,并希望使用RestTemplate或RestClient来完成这个任务。
解决方案
Spring Boot提供了配置和构建器来帮助构建所需的类。这个食谱将会构建一个可以用来消费API的应用程序,如食谱3-2所示。
您可以使用RestTemplateBuilder来创建一个RestTemplate并在您的应用程序中使用它,或者使用暴露的RestClient.Builder来创建一个RestClient。最后一个选择是使用带有@HttpExchange注解的声明式客户端。
RestClient是一种比RestTemplate更流畅的方式来构建、执行和处理REST调用。它被构建为Webflux的WebClient的阻塞变体(参见第4章)。
它是如何工作的
尽管每种方法使用的类不同,我们仍然需要对Spring MVC的web类有依赖。为此,我们可以添加spring-boot-starter-web依赖。参见列表3-50。
如果你正在编写一个不需要servlet容器的独立客户端,你可能想要添加一个排除项,排除spring-boot-starter-tomcat。
我们将使用配方3-2作为我们的服务器API,并将编写一个应用程序,该程序在该API上查找一本书,调用另一个API(在https://openlibrary.org)以检索有关该书的额外信息,并返回一个丰富的响应。
EnrichedBook看起来像列表3-51。
这是在食谱3-2中创建的Book类的一个稍微扩展的版本(见列表3-6)。对于Open Library API,我们将使用一个HashMap来存放响应并检索我们需要的元素。
使用RestTemplate
要创建一个RestTemplate,我们可以使用RestTemplateBuilder,理想情况下作为@Bean方法的一个参数。这样我们就可以创建一个新的RestTemplate作为bean。RestTemplateBuilder负责配置我们需要的RestTemplate。参见列表3-52。
这将为我们的应用程序构建一个新的RestTemplate。
也可以通过辅助方法为RestTemplateBuilder指定额外的配置。
每个方法都将构建一个新的RestTemplateBuilder,因为RestTemplateBuilder本身是不可变的。
因此,设置的更改不会反映在使用RestTemplateBuilder的其他地方。
参见表3-14。
让我们编写一个控制器,它将从我们自己的服务器(参见食谱3-2)获取一本书,
并且还将调用开放图书馆API来获取书籍的出版日期。参见列表3-53。
控制器首先使用RestTemplate上的getForObject方法检索一本书(还有其他各种方法)。接下来,我们使用相同的方法从Open Library API检索额外的信息,然后使用这两个响应编写结果。
当你使用curl或HTTPie从命令行调用http://localhost:8090/books/9780618260300时,你将得到类似于图3-20的输出。
使用 RestClient
除了使用 RestTemplate,也可以使用更流畅的 RestClient。Spring Boot 自动暴露了 RestClient.Builder。参见代码清单 3-54。
RestClient.Builder 提供了一些方法来增强配置。
每个方法都会产生一个新的RestClient.Builder实例。参见表3-15和列表3-55。
控制器使用RestClient来调用URL。首先,我们确定我们想要的请求类型,以便在我们的案例中使用get()。接下来,我们使用uri()方法指定我们想要调用的带有参数的URL。这完成了我们的请求,现在我们可以通过receive()方法执行它。最后,我们使用body()方法映射响应体。
由于RestClient重用了RestTemplate使用的相同基础设施的一部分,我们可以重用我们之前相同的异常处理。当你使用curl或HTTPie从命令行调用http://localhost:8090/books/9780618260300时,你将得到类似于图3-20的输出。
使用声明式客户端
Spring Framework 6 引入了声明式 HTTP 客户端。通过这个功能,可以编写一个带有注解的接口。在运行时,会创建一个代理来处理请求/响应,包括映射和异常处理。
起点是一个带有 @HttpExchange 注解的接口(或者像 @GetExchange 或 @PostExchange 这样的派生注解),这些注解可以放在类上或方法上。它的功能与服务器 API 中的 @RequestMapping 非常相似。
使用 @HttpExchange,可以设置一些属性(见表 3-16)。
除了@HttpExchange注解之外,还有@DeleteExchange、@GetExchange、@PatchExchange、@PostExchange和@PutExchange。这些可以用来代替带有特定方法值的@HttpExchange。使用这些注解可以使其更加明确。
就像带有@RequestMapping的请求处理方法一样,声明式客户端支持多个参数、注解和返回类型。它重用了Web基础设施的通用部分。参见表3-17。
除了方法参数外,还支持几种方法返回类型。参见表 3-18。
根据这些信息,我们可以提供两个接口来访问我们需要调用的API。让我们从书籍的API开始。参见列表3-56。
BookServiceClient有一个方法,该方法使用了@GetExchange注解。
提供了一个值http://localhost:8080/books/{isbn},这是一个URI模板。
该方法接受一个参数isbn,该参数被@PathVariable注解。
当我们调用这个方法时,我们传入的值将会被放置在URI的{isbn}部分,然后执行请求。
当请求发送后,会收到一个响应,该响应会被转换成一个Book对象,
接下来我们也需要一个用于Open Library API的界面。参见列表3-57。
OpenLibraryClient 有一个带有 url 属性设置的 @HttpExchange 方法。这将为这个接口中的所有其他方法设置一个基础 URI。这允许我们只为所有其他方法指定相对 URL。现在只有一个带有 @GetExchange 的方法。这个方法还接受一个参数 isbn,在执行之前也会将其放置在 URI 模板中。响应再次被转换成一个 Map,就像之前一样。
现在接口已经准备好了,我们需要在我们的配置中公开它们,但我们不能从接口创建实例。这就是 HttpServiceProxyFactory 发挥作用的地方;它在运行时为这些接口创建一个代理。为此,我们需要向我们的应用程序添加一些配置。参见列表 3-58。
RestClient.Builder 用于构建一个用于 HttpServiceProxyFactory 的 RestClient。由于无法直接使用 RestClient,我们需要将其包装在 RestClientAdapter 中,后者将 RestClient 适配到 HttpExchangeAdapter 接口。
HttpExchangeAdapter 有三种实现:RestClientAdapter、RestTemplateAdapter 和 WebClientAdapter。后者在第 4 章中使用,并且是非阻塞的。然而,也可以使用 RestTemplate 来执行请求,而不是使用 RestClient。
HttpServiceProxyFactory 反过来用于为 BookServiceClient 和 OpenLibraryClient 创建代理。这只需在 HttpServiceProxyFactory 上调用带有给定接口的 createClient 方法即可轻松完成。参见列表 3-59。
请注意,我们现在可以直接在接口上调用方法,而无需担心构建适当的请求。所有这些都被隐藏在接口外观和代理内部。这使得编写可重用的API客户端以供应用程序使用变得更加容易。
最后,请注意,异常处理并未改变,因为声明式客户端仍然使用相同的基础设施,RestClient的异常处理无需更改。
当重新运行应用程序并请求书籍信息时,输出应该仍然与图3-20所示相同。
使用RestTemplate或RestClient-Based Code进行测试
为了使用RestTemplate或RestClient测试客户端代码,Spring Test框架提供了MockRestServiceServer。MockRestServiceServer可用于返回特定请求的响应(基于URL、头部、内容等)。
Spring Boot通过提供@RestClientTest注解,使得使用它变得更加容易。这将设置MockRestServiceServer,使其可以自动装配,并将测试类配置好。参见列表3-60。
测试使用@RestClientTest来设置服务器并为测试准备EnrichedBookController。MockRestServiceServer和EnrichedBookController都被注入,以便它们可用于测试。
在实际的测试方法中,我们首先通过我们想要的行为来设置MockRestServiceServer。这里我们只匹配URL并设置它们返回特定的JSON响应和HTTP 200 OK(更多可能性请参见表3-19)。测试运行后,我们在MockRestServiceServer上调用verify()来验证我们记录的请求是否也被发出,表明我们的客户端按预期工作。
响应是通过使用MockRestResponseCreators创建的,目前我们只使用了withSuccess,但也可以设置错误场景(表3-20)。
在调用设置方法后,返回了一个DefaultResponseCreator,可以用来进一步定义响应,通过添加头部、cookies,甚至是正文。
我们可以使用@RestClientTest,也可以使用@WebMvcTest,因为EnrichedBookController是一个控制器。自动设置MockRestServiceServer需要一个额外的注解@AutoConfigureMockRestServiceServer;否则,它将不会被配置。
猜你喜欢
- 2024-12-25 Spring Boot整合Spring Cloud GateWay代理第三方应用的调用接口?
- 2024-12-25 Java 近期新闻:Hibernate 6.0、JobRunr 5.0、JHipster 7.8.0
- 2024-12-25 Keycloak Servlet Filter Adapter使用
- 2024-12-25 如何在Spring Boot中保证RESTful接口的安全性?
- 2024-12-25 Java项目实战第6天:登录业务的实现
- 2024-12-25 JavaEE概述总结:Servlet生命周期+JSP内置对象
- 2024-12-25 SpringBoot 无感刷新 Token springboot的token
- 2024-12-25 若依开发框架解析笔记(7)-jwt的应用
- 2024-12-25 Spring MVC中提供了哪些扩展机制?如何使用这些扩展机制?
- 2024-12-25 49个Spring经典面试题总结(附带答案)
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)