消费REST服务

目录

    • 概述
    • GET资源
    • PUT资源
    • DELETE资源
    • POST资源

概述

Spring应用除了提供对外API之外,同时要对另一个应用的API发起请求。实际上,在微服务领域,这正变得越来越普遍。因此,花点时间研究一下如何使用Spring与RESTAPI交互是非常值得的。
Spring应用可以采用多种方式来消费RESTAPI

  • RestTemplatc:由Spring核心框架提供的简单、同步REST客户端。
  • Traverson:对 Spring RestTemplate 的包装,由Spring HATEOAS 提供的支持超链接、同步的 REST客户端,其灵感来源于同名的 JavaScript库。
  • WebClient:反应式、异步REST的客户端。

现在,我们主要关注使用 RestTemplate 创建客户端。
从客户端的角度来看,与 REST 资源进行交互涉及很多工作,而且大多数都是很单调乏味的样板式代码。如果使用较低层级HTTP 库,客户端需要创建一个客户端实例和请求对象,执行请求,解析响应,将响应映射为领域对象,还要处理这个过程中可能会抛出的所有异常。不管发送什么样的 HTTP 请求,这种样板代码都要不断重复。
为了避免这种样板代码,Spring 提供了 RestTemplate。就像JDBCTemplate 能够处理JDBC 中丑陋的那部分代码一样,RestTemplate 也能够将你从消费 REST 资源所面临的单调工作中解放出来。
RestTemplat 提供了 41个与 REST 资源交互的方法。我不会介绍它所提供的所有方法,而是只考虑独立的12个操作,这些操作的重载形式组成了完整的41个方法。

方法描述
delete(…)在特定的URL上对资源执行HTTP DELETE请求
exchange(…)在URL上执行特定的 HTTP 方法,返回包含对象的 ResponseEntity个对象是从响应体中映射得到的
execute(…)在URL上执行特定的 HTTP方法,返回一个从响应体映射得到的对象
getForEntity(…)发送一个HTTP GET 请求,返回的ResponseEntity 包含了响应体所映射成的对象
getForObject(…)发送一个HTTP GET 请求,返回响应体所映射成的对象
headForHeaders(…)发送HTTP HEAD 请求,返回包含特定资源 URL 的 HTTP头信息
optionsForAllow(…)发送HTTP OPTIONS 请求,返回特定 URL的Allow头信息
patchForObject(…)发送HTTP PATCH请求,返回一个从响应体映射得到的对象
postForEntity(…POST数据到一个URL,返回包含一个对象的 ResponseEntity,这个对象是从响应体中映射得到的
postForLocation(…)POST数据到一个URL,返回新创建资源的URL
postForObject(…)POST数据到一个URL,返回根据响应体映射形成的对象
put(…)PUT资源到特定的URL

除了 TRACE,RestTemplate 对每种标准的HTTP 方法都提供了至少一个方法。除之外,execute()exchange()提供了较低层次的通用方法,以便使用任意的HTTP 操作
表中的大多数操作都以如下的3种方法形式进行了重载:

  • 使用String作为URL格式,并使用可变参数列表指明 URL 参数;
  • 使用String作为URL格式,并使用Map<String,String>指明 URL参数;
  • 使用java.net.URI作为URL格式,不支持参数化URL。

明确了 RestTemplate 所提供的 12 个操作以及各个变种如何工作之后,我们就能以自己的方式编写消费 REST资源的客户端了。
要使用 RestTemplate,可以在需要的地方创建一个实例:

RestTemplate rest = new RestTemplate();

也可以将其声明为一个 bean 并注入到需要的地方:

@Bean
public RestTemplate restTemplate() {return new RestTemplate();
}

我们从其支持的4个主要 HTTP 方法(也就是GETPUTDELETEPOST)入手来研究 RestTemplate 的操作。不妨从 GET方法的 getForObject()getForEntity()开始。

GET资源

假设我们现在想要通过 Taco Cloud API(访问该RestAPI可以得到对应的数据)获取某个配料。为了实现这一点,我们可以使用RestTemplategetForObject()方法来获取配料。例如如下的代码使用RestTemplate来根据ID来获Ingredient 对象:

public Ingredient getIngredientById(string ingredientId){return rest.getForObject("http://localhost;8080/ingredients/{id}",Ingredient.class, ingredientId);
}

在这里,我们使用了gctForObject()的变种形式,它接收一个String 类型的URL并使用可变列表来指定URL变量。传递给getForObject()IngredientId 参数会用来填充给定URL{id}占位符。尽管在本例中只有一个URL 变量,但是有很重要的一点需要我们注意:变量参数会按照它们出现的顺序被设置到占位符中。
getForObject()方法的第二个参数是响应应该绑定的类型。在本例中,响应数据(很可能是JSON格式)应该被反序列化为要返回的Igredient对象。另外一种替代方案是使用Map 来指定URL变量:

public Ingredient getIngredientById(String ingredientId) (Map<String,String> urlVariables = new HashMap<>();urlVariables.put("id", ingredientId);return rest.getForObject("http://localhost:8080/ingredients/{id}",Ingredient.class, urlVariables);

在本例中,ingredicntId 的值会映射到名为 idkey 上。当发起请求的时候,{id}占位符将会被替换成keyidMap条目。
使用 URI参数要稍微复杂一些,这种方式需要我们在调用 getForObject()之前构建URI对象。在其他方面,它与另外两个变种非常类似:

public Ingred1ent getIngredientById(String ingredientId) {Map<String,String> urlVariables = new HashMap<>();urlVariables.put("id", ingredientId);URI	url=UriComponentsBuilder.fromHttpUrl("http://localhost:8080/ingredients/{id}").build(urlVariables);return rest,getForObject(url, Ingredient.class);
}

在这里,URI对象是通过 String 规范定义的,它的占位符会被 Map 中的条目替换。这与我们之前看到的 getForObject()变种非常相似。getForObject()是获取资源的有效式。但是,如果客户端需要的不仅仅是载荷体,那么可以考虑使用 getForEntity()getForEntity()的工作方式和 getForObject()类似,但是它所返回的并不是代表响应载荷的领域对象,而是会包裹领域对象的 ResponseEntity 对象。借助 ResponseEntity 对象能够访问很多响应细节,比如响应头信息。
例如,假设我们除了想要获取配料数据,还想要从响应中探查 Date 头信息。借助getForEntity(),这个需求能够很容易实现:

public Ingredient getIngredientById(String ingredientId) {
ResponseEntity<Ingredient> responseEntity =rest.getForEntity("http://localhost:8080/ingredients/{id}",Ingredient.class, ingredientId);
log.info("Fetched time: {}",
responseEntity.getHeaders().getDate());
return responseEntity.getBody();
}

getForEntity()有着与 getForObject()方法相同参数的重载形式,所以我们可以按照变列表参数的形式提供 URL变量,也可以按照 URI对象的形式调用 getForEntity()

PUT资源

为了发送HTTP PUT 请求,RestTemplate 提供了 put()方法。put()方法的3个变种形式都会接收一个会被序列化并发送至给定 URLObject。就URL本身来讲,它可以按照URI对象或 String 的形式来指定。与 getForObject()getForEntity()类似,URL变量能够以可变参数列表或Map的形式提供。
假设我们想要使用一个新 Igredient 对象的数据来替换某个配料资源,那么如下的代码片段就能做到这一点:

public void updateIngredient(Ingredient ingredient) {rest.put("http://localhost:8080/ingredients/{id}",ingredient,ingredient.getId());
}

在这里,URL 是以 String 的形式指定的,该 URL 包含一个占位符,它会被给定Ingredientid 属性所替换。要发送的数据是 Ingredient 对象本身。put()方法返回 void 所以我们没有必要处理返回值。

DELETE资源

假设 Taco Cloud 不想再提供某种配料,因此我们要从可选列表中将其完全删除。为了实现这一点,可以使用 RestTemplate 来调用 delete() 方法:

public void deleteIngredlent(Ingredient ingredient) {rest.delete("http://1ocalhost;8080/ingredients/{id})",ingredient.getId())
}

在本例中,我们只为 delete()提供了 URL(以 String 的形式指定)和 URL变量值但是,和其他的 RestTemplate 方法类似,URL 能够以URI对象的方式来指定,URL参数也能够以 Map 的方式来声明。

POST资源

现在,我们假设要添加新的配料到 Taco Cloud 菜单中。为了实现这一点,我“.../ingredients”端点发送 HTTP POST 请求,并将配料数据放到请求体中。RestTemplate 有 3种发送 POST 请求的方,每种方法都有相同的重载变种来指定URL。如果希望在 POST请求之后得到新创建的 Ingredient 资源,可以按照如下的方式使用 postForObject():

public Ingredient createIngredient(Ingredient ingredient) {return rest.postForObject("http://localhost:8080/ingredients",ingredient,Ingredient.class);
}

postForObject()方法的这个变种形式接收 String类型的URL规范、要提交给服务器端的对象,以及响应体应该绑定的领域类型。尽管我们在这里没有用到,但是第 4个参数可以是URL变量值的Map 或可变参数的列表。它们能够替换到 URL之中。如果客户端还想要知道新创建资源的地址,那么可以调用 postForLocation()方法如下所示:

public java,net.URI createIngredient(Ingredient ingredient) {return rest.postForLocation("http://localhost:8080/ingredients",ingredient);
}

注意,postForLocation()有与 postForObject()类似的工作方式,只不过它返回的是新创建资源的 URI,而不是资源对象本身。这里返回的 URI是从响应的 Location 头信息中派生出来的。如果同时需要地址和响应载荷,可以使用 postForEntity()方法:

public Ingredient createIngredient(Ingredient ingredient) (ResponseEntity<Ingredient> responseEntity=rest.postForEntity("http://localhost:8080/ingredients",ingredient,Ingredient.class);log.Info("New resource created at {}",responseEntity.getHeaders().getLocation());return responseEntity.getBody();
}

尽管 RestTemplate 的方法可以实现不同的目的,但是用法非常相似。因此,我们很容易就可以精通 RestTemplate,并将其用到客户端代码中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/599212.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言编译器(C语言编程软件)完全攻略(第五部分:VS2015使用教程(使用VS2015编写C语言程序))

介绍常用C语言编译器的安装、配置和使用。 五、VS2015使用教程&#xff08;使用VS2015编写C语言程序&#xff09; 前面我们给出了一段完整的C语言代码&#xff0c;就是在显示器上输出“C语言中文网”&#xff0c;如下所示&#xff1a; #include <stdio.h> int main() {…

MySQL运维实战(2.3)MySQL的权限体系

作者&#xff1a;俊达 MySQL权限划分 MySQL权限按授权范围可以分为三大类&#xff1a;全局权限、数据库权限和对象权限。 全局权限主要用于管理系统模块&#xff0c;这些权限涵盖了对MySQL服务器整体的操作和管理&#xff0c;与具体的数据库或对象无关&#xff0c;因此在授权…

Leetcode_day01_88合并两个有序数组

Leetcode_day01_88合并两个有序数组 题目描述&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺…

HarmonyOS应用开发学习笔记 包名、icon图标,应用名修改 UIAbility组件介绍、UIAbility启动模式、UIAbility组件基本用法

目前HarmonyOS应用主推的是Stage模型开发 一、Stage模型基本概念 项目描述UIAbility组件UIAbility组件是一种包含UI界面的应用组件&#xff0c;主要用于和用户交互。例如&#xff0c;图库类应用可以在UIAbility组件中展示图片瀑布流&#xff0c;在用户选择某个图片后&#xf…

Hotspot源码解析-第十二章-线程栈保护页

了解保护页&#xff0c;先从几个问题开始吧 1、为什么线程栈有栈帧了&#xff0c;还要有保护页&#xff1f; 答&#xff1a;在操作系统中内存可以看成是一个大数组&#xff0c;这就有一个问题&#xff0c;线程之间可能会互相踩了别人的内存空间&#xff0c;所以栈空间也存在这…

空间域图像增强之直方图均衡的python代码实现——冈萨雷斯数字图像处理

原理 直方图&#xff1a; 图像的直方图是一个图像中像素强度值分布的图表。 对于灰度图像&#xff0c;直方图展示了每个灰度级出现的频率。 直方图均衡步骤&#xff1a; 计算累积分布函数&#xff08;CDF&#xff09;&#xff1a;首先&#xff0c;计算图像的直方图&#xff0…

C语言中一些基本数据类型的典型大小

char&#xff1a;通常是1字节。表示一个字符。int&#xff1a;通常在现代系统中是4字节&#xff08;但这取决于编译器和架构&#xff0c;有时可能是2字节&#xff09;。float&#xff1a;通常是4字节。double&#xff1a;通常是8字节。short 和 short int&#xff1a;通常是2字…

解决:ERROR: Failed building wheel for xxx

解决&#xff1a;ERROR: Failed building wheel for xxx 文章目录 解决&#xff1a;ERROR: Failed building wheel for xxx背景报错问题报错翻译报错原因解决方法参考内容&#xff1a;今天的分享就到此结束了 背景 在使用之前的代码构建环境时&#xff0c;报错&#xff1a;ERRO…

普中STM32-PZ6806L开发板(有点悲伤的故事续-人灯还未了)

简介 继上篇 普中STM32-PZ6806L开发板(有点悲伤的故事) 说到 关于 普中STM32-PZ6806L开发板的LED流水灯也被烧坏掉了&#xff0c;再也无法玩流水灯, 内心充满了只会流水灯的不甘, 流水灯就是单片机的Hello World&#xff0c;怎么能没有呢&#xff1f; 事情发展 好巧不巧想起最近…

Linux操作系统基础(10):Linux的特殊权限

1. 特殊权限是什么 在Linux中&#xff0c;特殊权限是指针对文件或目录的特殊权限设置&#xff0c;包括SetUID、SetGID和Sticky Bit。 SetUID&#xff08;Set User ID&#xff09;&#xff1a; 当一个可执行文件被设置了SetUID权限后&#xff0c;当任何用户执行该文件时&#x…

强大好用的低代码开发工具,yyds!

现在市面上的很多开发工具更侧重代码编辑&#xff0c;针对数据库增删改查&#xff08;CRUD&#xff09;类的Web系统开发&#xff0c;在界面设计、前后端数据交互等环节主要还是靠写代码&#xff0c;效率比较低&#xff1b;而现在市面上很多所谓的低代码开发平台&#xff0c;大多…

View系列-onClick执行流程

1.设置监听器 //frameworks\base\core\java\android\view\View.java public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {/*** Register a callback to be invoked when this view is clicked. If this view is not* clickable, i…

服务器经常出现自动重启怎么办

服务器自动重启是一个复杂且常见的问题&#xff0c;可能由多种原因引起。从硬件故障到软件问题&#xff0c;从电源问题到散热问题&#xff0c;每一个环节都可能成为服务器的杀手。在处理此类问题时&#xff0c;需要我们有一套完整的策略和方案&#xff0c;以便快速准确地定位并…

envoy在arm机器上的编译整理

版本信息&#xff1a; 操作系统:GUN Linux操作系统AARCH64架构。istio-proxy版本&#xff1a;istio-proxy1.15.2 编译环境搭建&#xff1a; 设置代理&#xff0c;确保可以访问Google等外网&#xff0c;这里envoy的第一次编译需要从外网下载依赖库。// 备注&#xff1a;这里一定…

决策树--分类决策树

1、介绍 ① 定义 分类决策树通过树形结构来模拟决策过程&#xff0c;决策树由结点和有向边组成。结点有两种类型&#xff1a;内部结 点和叶结点。内部结点表示一个特征或属性&#xff0c;叶子节点表示一个类。 ② 生成过程 用决策树分类&#xff0c;从根结点开始&#xff…

深度学习之矩阵形式的链式法则推导

深度学习之矩阵形式的链式法则推导 对于深度学习的基础“梯度下降”和“自动微分”的数学原理网上讲解的博客有很多了&#xff0c;但是目前没看到有讲关于矩阵形式的链式法则的内容&#xff0c;所以写了这篇笔记&#xff0c;供自己学习和复习。 文章目录 深度学习之矩阵形式的…

Lazada商品API接口:item_search接口中指定搜索范围

store_code: 指定商店代码。你可以使用这个参数来限制搜索结果仅返回特定商店的商品。格式为&#xff1a;store_code商店代码。category_id: 指定商品类别ID。通过提供特定的类别ID&#xff0c;你可以限制搜索结果仅返回该类别下的商品。格式为&#xff1a;category_id类别ID。…

【自学笔记】01Java基础-09Java关键字详解

介绍java&#xff08;基于java11&#xff09;中所有关键字&#xff0c;以及主要重要的关键字详解。 1 Java 11中的关键字&#xff1a; 1.1 类型声明与变量定义 boolean&#xff1a;声明布尔类型变量&#xff0c;只有两个可能值 true 或 false。byte&#xff1a;声明一个8位有…

复制Ubuntu遇到的问题及解决办法、Ubuntu上git命令更改和查看账户、实现Ubuntu与Windows之间的文件共享

1、复制Ubuntu遇到的问题及解决办法 &#xff08;1&#xff09;问题一&#xff1a;“该虚拟机似乎正在使用中。如果该虚拟机未在使用&#xff0c;请按”获取所有权(T)”按钮获取它的所有权。否则&#xff0c;请按”取消(C)”按钮以防损坏。” 出现该问题的原因“未正确关闭虚…

关于java栈和堆

关于java栈和堆 在上一篇文章中我们了解了数组的声明和创建&#xff0c;本篇文章中我们了解一下声明数组&#xff0c;创建数组&#xff0c;给数组赋值以后&#xff0c;栈和堆都是怎么样子分配的&#xff0c;了解一下底层的逻辑知识&#xff0c;让大家可以更好的理解数组&#…