RestTemplate 詳解

在項目中,當我們需要遠程調用一個 HTTP 接口時,我們經常會用到 RestTemplate 這個類。這個類是 Spring 框架提供的一個工具類。Spring 官網對它的介紹如下:

RestTemplate: The original Spring REST client with a synchronous, template method API.

從上面的介紹中我們可以知道:RestTemplate 是一個同步的 Rest API 客戶端。下面我們就來介紹下 RestTemplate 的常用功能。

?

RestTemplate 簡單使用#

RestTemplate 提供高度封裝的接口,可以讓我們非常方便地進行 Rest API 調用。常見的方法如下:

表格:RestTemplate 的方法

上面的方法我們大致可以分為三組:

  • getForObject --- optionsForAllow 分為一組,這類方法是常規的 Rest API(GET、POST、DELETE 等)方法調用;
  • exchange:接收一個?RequestEntity?參數,可以自己設置 HTTP method,URL,headers 和 body,返回 ResponseEntity;
  • execute:通過 callback 接口,可以對請求和返回做更加全面的自定義控制。

一般情況下,我們使用第一組和第二組方法就夠了。

創建 RestTemplate#

@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {RestTemplate restTemplate = new RestTemplate(factory);return restTemplate;
}@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();factory.setReadTimeout(5000);factory.setConnectTimeout(15000);// 設置代理//factory.setProxy(null);return factory;
}

創建 RestTemplate 時需要一個 ClientHttpRequestFactory,通過這個請求工廠,我們可以統一設置請求的超時時間,設置代理以及一些其他細節。通過上面代碼配置后,我們直接在代碼中注入 RestTemplate 就可以使用了。

有時候我們還需要通過 ClientHttpRequestFactory 配置最大鏈接數,忽略SSL證書等,大家需要的時候可以自己查看代碼設置。

?

接口調用#

1. 普通接口調用

Map<String, String> vars = Collections.singletonMap("hotel", "42");
// 通過 GET 方式調用,返回一個 String 值,還可以給 URL 變量設置值(也可通過 uriTemplateHandler 這個屬性自定義)
String result = restTemplate.getForObject("https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);String url = "http://127.0.0.1:8080/hello";
JSONObject param = new JSONObject();
//restTemplate 會根據 params 的具體類型,調用合適的 HttpMessageConvert 將請求參數寫到請求體 body 中,并在請求頭中添加合適的 content-type;
// 也會根據 responseType 的類型(本列子中是 JSONObject),設置 head 中的 accept 字段,當響應返回的時候再調用合適的 HttpMessageConvert 進行響應轉換
ResponseEntity<JSONObject> responseEntity=restTemplate.postForEntity(url,params,JSONObject.class);
int statusCodeValue = responseEntity.getStatusCodeValue();
HttpHeaders headers = responseEntity.getHeaders();
JSONObject body = responseEntity.getBody();

2. 添加 Header 和 Cookie

有時候,我們需要在請求中的 Head 中添加值或者將某些值通過 cookie 傳給服務端,那么上面這種調用形式就不太滿足要求了。

 UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("127.0.0.1:8080").path("/test").build(true);URI uri = uriComponents.toUri();RequestEntity<JSONObject> requestEntity = RequestEntity.post(uri).// 添加 cookie(這邊有個問題,假如我們要設置 cookie 的生命周期,作用域等參數我們要怎么操作)header(HttpHeaders.COOKIE,"key1=value1").// 添加 headerheader(("MyRequestHeader", "MyValue")accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON).body(requestParam);
ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(requestEntity,JSONObject.class);
// 響應結果
JSONObject responseEntityBody = responseEntity.getBody();

3. 文件上傳

上面兩個列子基本能覆蓋我們平時開發的大多數功能了。這邊再講個文件上傳的列子(RestTemplate 功能還是蠻全的)。

public Object uplaod(@RequestBody JSONObject params) throws Exception{final String url = "http://localhost:8888/hello/m3";// 設置請求頭HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.MULTIPART_FORM_DATA);// 設置請求體,注意是 LinkedMultiValueMapFileSystemResource resource1 = new FileSystemResource("D:\\dir1\\ss\\pic1.jpg");FileSystemResource resource2 = new FileSystemResource("D:\\dir1\\ss\\pic2.jpg");MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();form.add("file", resource1);form.add("file", resource2);form.add("param1","value1");HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<>(form, headers);JSONObject s = restTemplate.postForObject(url, files, JSONObject.class);return s;}

上面的代碼中上傳了兩個本地圖片,通過下面代碼可以順利接收。

@RequestMapping("/m3")
public Object fileUpload(@RequestParam("file") MultipartFile[] files, HttpServletRequest request) throws Exception {// 攜帶的其他參數可以使用 getParameter 方法接收String param1 = request.getParameter("param1");Response response = new Response();if (files == null) {response.failure("文件上傳錯誤, 服務端未拿到上傳的文件!");return response;}for (MultipartFile file : files) {if (!file.isEmpty() && file.getSize() > 0) {String fileName = file.getOriginalFilename();// 參考 FileCopyUtils 這個工具類file.transferTo(new File("D:\\" + fileName));logger.info("文件:{} 上傳成功...",fileName);}}response.success("文件上傳成功");return response;}

但是我們發現上面的上傳代碼中,上傳文件的類必須使用 FileSystemResource。有時我們會碰到這種情況:文件我們會從文件服務下載到內存中一個 InputStream 的形式存在,那此時在使用 FileSystemResource 就不行了。

當然,我們使用討巧一點的辦法也是可以的:先將下載下來的 InputStream 保存到本地,然后再讀取到 FileSystemResource,上傳后再刪除本地臨時文件。

但是總覺得這個方法不夠完美。最后發現有個同事已經寫了相關的實現。這邊就直接拿來用了。

// 自己實現了一個 Resource
public class InMemoryResource extends ByteArrayResource {private final String filename;private final long lastModified;public InMemoryResource(String filename, String description, byte[] content, long lastModified) {super(content, description);this.lastModified = lastModified;this.filename = filename;}@Overridepublic long lastModified() throws IOException {return this.lastModified;}@Overridepublic String getFilename() {return this.filename;}
}

調整后的上傳代碼

 @PostMapping("/m3")public Object m3(@RequestBody JSONObject params) throws Exception{final String url = "http://localhost:8888/hello/m3";// 設置請求頭HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.MULTIPART_FORM_DATA);// 設置請求體,注意是 LinkedMultiValueMap// 下面兩個流從文件服務下載,這邊省略(注意最后關閉流)InputStream fis1 = InputStream fis2 = InMemoryResource resource1 = new InMemoryResource("file1.jpg","description1", FileCopyUtils.copyToByteArray(fis1), System.currentTimeMillis());InMemoryResource resource2 = new InMemoryResource("file2.jpg","description2", FileCopyUtils.copyToByteArray(fis2), System.currentTimeMillis());MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();form.add("file", resource1);form.add("file", resource2);form.add("param1","value1");HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<>(form, headers);JSONObject s = restTemplate.postForObject(url, files, JSONObject.class);return s;}

4. 文件下載

private InputStream downLoadVideoFromVod(String url) throws Exception {byte[] bytes = restTemplate.getForObject(url, byte[].class);return new ByteArrayInputStream(bytes);
}

?

一些其他設置#

1. 攔截器配置

RestTemplate 也可以設置攔截器做一些統一處理。這個功能感覺和 Spring MVC 的攔截器類似。配置也很簡單:

class MyInterceptor implements ClientHttpRequestInterceptor{@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {logger.info("enter interceptor...");return execution.execute(request,body);}}
 @Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {RestTemplate restTemplate = new RestTemplate(factory);MyInterceptor myInterceptor = new MyInterceptor();List<ClientHttpRequestInterceptor> list = new ArrayList<>();list.add(myInterceptor);restTemplate.setInterceptors(list);return restTemplate;
}

2. ErrorHandler 配置

ErrorHandler 用來對調用錯誤對統一處理。

public class MyResponseErrorHandler extends DefaultResponseErrorHandler {@Overridepublic boolean hasError(ClientHttpResponse response) throws IOException {return super.hasError(response);}@Overridepublic void handleError(ClientHttpResponse response) throws IOException {HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());if (statusCode == null) {throw new UnknownHttpStatusCodeException(response.getRawStatusCode(), response.getStatusText(),response.getHeaders(), getResponseBody(response), getCharset(response));}handleError(response, statusCode);}@Overrideprotected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {switch (statusCode.series()) {case CLIENT_ERROR:HttpClientErrorException exp1 = new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), getResponseBody(response), getCharset(response));logger.error("客戶端調用異常",exp1);throw  exp1;case SERVER_ERROR:HttpServerErrorException exp2 = new HttpServerErrorException(statusCode, response.getStatusText(),response.getHeaders(), getResponseBody(response), getCharset(response));logger.error("服務端調用異常",exp2);throw exp2;default:UnknownHttpStatusCodeException exp3 = new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(),response.getHeaders(), getResponseBody(response), getCharset(response));logger.error("網絡調用未知異常");throw exp3;}}}
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {RestTemplate restTemplate = new RestTemplate(factory);MyResponseErrorHandler errorHandler = new MyResponseErrorHandler();restTemplate.setErrorHandler(errorHandler);List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();// 通過下面代碼可以添加新的 HttpMessageConverter//messageConverters.add(new );return restTemplate;
}

3. HttpMessageConverter 配置
RestTemplate 也可以配置 HttpMessageConverter,配置的原理和 Spring MVC 中類似。

?

簡單總結#

通過 RestTemplate,我們可以非常方便的進行 Rest API 調用。但是在 Spring 5 中已經不再建議使用 RestTemplate,而是建議使用 WebClient。WebClient 是一個支持異步調用的 Client。所以喜歡研究新東西的同學可以開始研究下新東西了。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284003.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284003.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284003.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

初識Spark2.0之Spark SQL

內存計算平臺Spark在今年6月份的時候正式發布了spark2.0&#xff0c;相比上一版本的spark1.6版本&#xff0c;在內存優化&#xff0c;數據組織&#xff0c;流計算等方面都做出了較大的改變&#xff0c;同時更加注重基于DataFrame數據組織的MLlib&#xff0c;更加注重機器學習整…

webpack開發Vue配置

一直以來使用webpack都是用的別人的配置&#xff0c;這幾天自己學習了一下。 項目地址&#xff1a;https://github.com/donghaohao... 新建整個工程 npm init安裝依賴&#xff0c;這里我們開發vue項目&#xff0c;npm install vue --save&#xff0c;然后是開發時的依賴npm ins…

ABP詳細教程——模塊類

概述模塊化是ABP vNext的最大亮點&#xff0c;也是ABP vNext框架的核心&#xff0c;而模塊類是ABP vNext框架模塊化的核心要素。這一章節&#xff0c;我就從模塊類的用法、運行機制、源代碼等層面&#xff0c;帶大家詳細了解ABP vNext的模塊類。用法在ABP的約定中&#xff0c;每…

[轉]Eureka工作原理

目錄 Eureka 工作原理 Eureka 核心概念 自我保護機制 Eureka 集群原理 Eurka 工作流程 總結 Eureka 工作原理 上節內容為大家介紹了&#xff0c;注冊中心 Eureka 產品的使用&#xff0c;以及如何利用 Eureka 搭建單臺和集群的注冊中心。這節課我們來繼續學習 Eureka&…

centos7下別名(alias)的特殊用法

版權聲明&#xff1a;轉載請注明出處:http://blog.csdn.net/dajitui2024 https://blog.csdn.net/dajitui2024/article/details/79438200 參考&#xff1a;https://www.cyberciti.biz/faq/bash-bypass-alias-command-on-linux-macos-unix/ 正常情況下&#xff0c;定義過的別名&a…

解決WDCP3環境gbk網站編碼程序亂碼問題

因為默認WDCP V3版本環境編碼格式是UTF-8版本&#xff0c;如果我們程序采用的是GBK編碼肯定都會有亂碼問題。 我們到WDCP后臺&#xff0c;"網站管理"-"PHP設置"&#xff0c;看到上圖所示&#xff0c;準備直接在線編輯PHP.INI文件。 這里我們找到"defa…

重談聯想5G編碼投票事件

此前&#xff0c;司馬南談了聯想好幾個問題&#xff0c;其中最尖銳的要屬國有資產流失&#xff0c;這是聯想管理層無法回避的死穴。不過&#xff0c;司馬南批判聯想5G投票背刺H公司&#xff0c;這基本就是造謠了。當年&#xff0c;媒體把編碼投票炒作的很厲害&#xff0c;抨擊聯…

JStorm2.1.1集群的安裝和使用

為什么80%的碼農都做不了架構師&#xff1f;>>> JStorm2.1.1集群的安裝和使用 Storm是一個免費開源、分布式、高容錯的實時計算系統&#xff0c;而JStorm是阿里巴巴開源的基于Storm采用Java重寫的一套分布式實時流計算框架&#xff0c;在性能和支持的集群規模上做了…

Hystrix 原理

Hystrix是什么&#xff1f; Hystrix是Netflix開源庫&#xff0c;這是一個針對分布式系統的延遲和容錯庫。 Hystrix 供分布式系統使用&#xff0c;提供延遲和容錯功能&#xff0c;隔離遠程系統、訪問和第三方程序庫的訪問點&#xff0c;防止級聯失敗&#xff0c;保證復雜的分布…

「深度」無人機實名制政策特稿|市場看好、資本關注,“反黑飛”正在崛起

從政策和需求來看&#xff0c;“反黑飛”越來越重要&#xff0c;市場也正在不斷崛起。 對于大多數人來說&#xff0c;今天是最適合明目張膽“裝嫩”的六一兒童節。不過&#xff0c;在無人機廠商和無人機玩家的眼里&#xff0c;今天是無人機實名制政策正式實施的日子。 近年來&…

在navicat中新建數據庫

前言&#xff1a; 在本地新建一個名為editor的數據庫&#xff1b; 過程&#xff1a; 1.&#xff1b; 2.選擇&#xff1a;utf8mb4 -- UTF-8 Unicode字符集&#xff0c;原因在于&#xff1a;utf8mb4兼容utf8&#xff0c;且比utf8能表示更多的字符。&#xff0c;而且它支持表情符號…

MASA Stack 第三期社區例會

MASA Blazor 0.5.0發版內容功能Autocomplete&#xff1a;支持通過設置AutoSelectFirst參數開啟自動選擇第一項的功能&#xff0c;支持CacheItems參數&#xff0c;增強使用上下鍵的用戶體驗。BottomNavigation&#xff1a;&#xff1a;一個替代側邊欄的新組件。它主要用于移動應…

MySQL添加用戶、刪除用戶與授權

MySql中添加用戶,新建數據庫,用戶授權,刪除用戶,修改密碼(注意每行后邊都跟個;表示一個命令語句結束): 1.新建用戶 1.1 登錄MYSQL&#xff1a; >mysql -u root -p >密碼 1.2 創建用戶&#xff1a; mysql> insert into mysql.user(Host,User,Password) values("lo…

[轉]高并發架構設計之--「服務降級」、「服務限流」與「服務熔斷」

目錄 服務降級 1 、簡介 2 、使用場景 3 、核心設計 3.1 分布式開關 3.2 自動降級分類 3.3 配置中心 3.4 處理策略 3.5 降級分類 3.6 服務降級要考慮的問題 4 、高級特性 4.1 分級降級 4.2 降級權值 5 、總結與展望 服務限流 一、為什么要做服務限流設計&…

【Linux】【Services】【nfs】nfs安裝與配置

1. 概念 1.1. NFS&#xff1a;Network File System&#xff0c;傳統意義上&#xff0c;文件系統在內核中實現。 1.2. RPC&#xff1a;Remote Procedure Call protocol&#xff0c;遠程過程調用&#xff0c;函數調用&#xff08;遠程主機上的函數&#xff09; 1.3. 端口&#xf…

SpringBoot獲取ApplicationContext

2019獨角獸企業重金招聘Python工程師標準>>> 有兩種方法&#xff1a; 創建Component實現ApplicationContextAware接口&#xff0c;SpringBoot會自動調用這個類的setApplicationConext()方法。鼓勵使用這種方式。SpringApplication.run(MyApplication.class, args)這…

SkiaSharp 之 WPF 自繪 投籃小游戲(案例版)

此案例主要是針對光線投影法碰撞檢測功能的示例&#xff0c;順便做成了一個小游戲&#xff0c;很簡單&#xff0c;但是&#xff0c;效果卻很不錯。投籃小游戲規則&#xff0c;點擊投籃目標點&#xff0c;就會有一個球沿著相關拋物線&#xff0c;然后&#xff0c;判斷是否進入籃…

zuul集成ribbon完成服務通信和負載均衡

目錄 Zuul2服務通信 超時相關 默認超時配置 自定義超時配置 負載均衡 Zuul2服務通信 描述&#xff1a;zuul2通過Ribbon完成客戶端負載均衡以及與服務器群集進行通信。 zuul2的通信是集成Ribbon實現的&#xff0c;在Origin中集成Ribbon基本配置&#xff08;例如IClientCo…

時任上海來伊份互聯網事業群總裁王戈鈞 :傳統企業(線上+線下)移動互聯網改造...

2017年12月22日-23日&#xff0c;第13屆信息化領袖峰會暨2017中國數字化貢獻人物頒獎盛典在上海盛大開幕。本次峰會由上海市經濟和信息化委員會指導&#xff0c;上海市國有資產信息中心、上海市計算機用戶協會、上海市信息服務業行業協會、上海大數據聯盟、上海市高等教育學會支…

Linux系統時間\硬件時間(date、tzselect、clock、hwclock、ntpdate)

1、系統時間和硬件時間 在Linux中有硬件時鐘與系統時鐘兩種時鐘。硬件時鐘是指主機板上的時鐘設備&#xff0c;也就是通常可在BIOS畫面設定的時鐘。系統時鐘則是指kernel中的時鐘。所有Linux相關指令與函數都是讀取系統時鐘的設定。因為存在兩種不同的時鐘&#xff0c;那么它們…