【本人禿頂程序員】技巧分享丨spring的RestTemplate的妙用,你知道嗎?

←←←←←←←←←←←← 快!點關注

為什么要使用RestTemplate?

隨著微服務的廣泛使用,在實際的開發中,客戶端代碼中調用RESTful接口也越來越常見。在系統的遺留代碼中,你可能會看見有一些代碼是使用HttpURLConnection來調用RESTful接口的,類似于下面這樣:

URL url = ...   
// 打開連接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {conn.setRequestMethod("POST");conn.setDoInput(true);conn.setDoOutput(true);conn.connect();// 發送數據...BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));bw.write(str);// 接收數據 ...BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));String line = null;while ((line = br.readLine()) != null) {...}
} finally {conn.disconnect();
}
復制代碼

從上面的代碼可以看出,使用HttpURLConnection調用RESTful接口是比較麻煩的,假如要調用30個接口,每個接口都使用類似于上面的代碼 進行調用,那簡直是一場災難(寫這么多無聊的樣板代碼,內心絕對是崩潰的)。有人可能會想,將常用的RESTful操作(例如GET、POST、DELETE)封裝成工具類,再調用不是也可以嗎!這樣做確實可行,但是要封裝成通用的工具類不是那么簡單的(需要一定的經驗)。調用RESTful接口,還有另外一種選擇:Apache HttpComponents。雖然使用它發送HTTP請求確實挺方便的,但是使用它調用RESTful接口好像也挺麻煩的!

直到我遇到了RestTemplate,世界頓時都明亮了,腰也不酸了,腿也不疼了,一下子就對接好了10個RESTful接口。寫的代碼可能變成是這樣子的:

RestTemplate template = ...
// 請求地址
String url = ...
// 請求參數
UserParams request = ...
// 執行POST請求
User u = template.postForObject(url, request, User.class);
...
復制代碼

上面的調用代碼變的簡潔了很多,是不是很爽啊!RestTemplate是spring提供用來調用RESTful接口的類,里面提供了大量便捷的方法,如下:

執行不同的請求,只需找到這種請求方式所對應的方法就行,上例中的postForObject就是發送的POST請求。如果上面的請求沒有找到對應的方法,可以使用更加通用的exchangeexecute方法。

RestTemplate的可擴展性也很強(下面列出比較常用的幾種方式):

  1. RestTemplate默認使用的是JDK中的HttpURLConnection實現的,如果你想要切換到其他的HTTP庫,例如,Apache HttpComponents, Netty和OkHttp,只需要調用setRequestFactory方法來進行設置,甚至可以使用自己實現的類型,只需要繼承自ClientHttpRequestFactory。(一般情況下,使用默認的實現就好)
  2. RestTemplate默認使用的是DefaultResponseErrorHandler響應錯誤處理器,你可以調用setErrorHandler來定制自己的響應錯誤處理器。
  3. 客戶端請求攔截器:ClientHttpRequestInterceptor,實現這個接口,并在org.springframework.web.client.RestTemplate#setInterceptors(java.util.List)中進行注冊,能對請求頭和請求體的內容進行修改,并能對響應的內容進行修改。(下面將會講解)
  4. RestTemplate中的doExecute方法,所有請求方式最終都會執行這個方法,重寫此方法能完成一些必要的操作。

RestTemplate的妙用

考慮這樣一個場景:假如說A部門開發的用戶相關的微服務接口,提供給B部門來使用,在使用時需要在請求頭中加入基本的認證頭信息,認證頭的格式如下:

Authorization=Basic {token}
復制代碼

token的格式是:base64(username:password)。假如username是zfx,密碼是123,結果是先拼接用戶名和密碼:zfx:123,再用utf-8格式獲取其字節碼,進行base64編碼的結果為:emZ4OjEyMw==

假如要調用A部門的接口,根據id來獲取用戶的信息,代碼如下:

String userId = "11";
String url = "http://127.0.0.1:8080/v1/users/{id}";RestTemplate restTemplate = new RestTemplate();// 基本的認證頭信息
String username  = "zfx";
String password = "123";
String token = Base64Utils.encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + token);
HttpEntity<Void> requestEntity = new HttpEntity<>(headers);ResponseEntity<User> exchange = restTemplate.exchange(url, HttpMethod.GET, requestEntity, User.class, userId);
User result = exchange.getBody();
復制代碼

首先先創建RestTemplate的實例,在實際的開發中,最好不要每次都創建RestTemplate的實例,最好在spring中以單例的方式來配置,要使用的地方直接注入。用base64來編碼了用戶名和密碼,然后在請求頭中進行設置。restTemplate.exchange執行請求,并獲取返回的結果。上面的代碼其實并不難,但是這樣寫會不會有啥問題呢!假如說,叫你對接A部門的根據機構id來獲取機構信息的接口,你豈不是又要把上面的代碼再重新復制一下嗎?這樣不是很麻煩,代碼會很臃腫。

spring提供了ClientHttpRequestInterceptor這個類,適合用來處理這種情況,加入基本的認證頭信息,可以使用spring提供的這個類:BasicAuthorizationInterceptor。使用配置的方式來配置RestTemplate:

@Configuration
public class RestTemplateConfig {@Value("${zfx.username}")private String username;@Value("${zfx.password}")private String password;@Bean("basicAuthRestTemplate")public RestTemplate createBasicAuthRestTemplate() {RestTemplate restTemplate = new RestTemplate();List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();interceptors.add(new BasicAuthorizationInterceptor(username, password));restTemplate.setInterceptors(interceptors);return restTemplate;}}
復制代碼

上面的代碼在創建basicAuthRestTemplate時,會加入基本的認證頭信息的攔截器,來設置基本認證頭信息。

再次調用上面的接口時,代碼可以這樣寫:

@Autowired
RestTemplate basicAuthRestTemplate;
...
String userId = "11";
String url = "http://127.0.0.1:8080/v1/users/{id}";
User result = basicAuthRestTemplate.getForObject(url, User.class, userId);
復制代碼

代碼一下子簡潔了這么多,假如說要調用根據機構id來獲取機構信息的接口呢?如下:

@Autowired
RestTemplate basicAuthRestTemplate;
...
String orgId = "11";
String url = "http://127.0.0.1:8080/v1/orgs/{id}";
Org result = basicAuthRestTemplate.getForObject(url, Org.class, orgId);
復制代碼

代碼一下子簡潔了很多,對接這些接口的程序員不用再關心認證是怎么一回事,認證這件事對于他們完全是透明的,他們只需要專注于編寫他們自己的邏輯代碼就可以了。ClientHttpRequestInterceptor的實現也很簡單,代碼如下:

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,ClientHttpRequestExecution execution) throws IOException {String token = Base64Utils.encodeToString((this.username + ":" + this.password).getBytes(StandardCharsets.UTF_8));request.getHeaders().add("Authorization", "Basic " + token);return execution.execute(request, body);
}
復制代碼

在intercept方法中加入了基本的認證頭信息。

假如說,有一天認證方式變了,改成OAuth2.0了,那么我們只需要實現自己的請求攔截器就行了,如下:

public class BearerAuthorizationInterceptimplements ClientHttpRequestInterceptor {@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body,ClientHttpRequestExecution execution) throws IOException {String token = 這些寫獲取token的邏輯;request.getHeaders().add("Authorization", "Bearer " + token);return execution.execute(request, body);}}
復制代碼

然后配置restTemplate:

    @Bean("bearerAuthRestTemplate")public RestTemplate createBearerAuthRestTemplate() {RestTemplate restTemplate = new RestTemplate();List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();interceptors.add(new BearerAuthorizationIntercept());restTemplate.setInterceptors(interceptors);return restTemplate;}
復制代碼

那么只需要注入bearerAuthRestTemplate,就能使用他了:

@Autowired
RestTemplate bearerAuthRestTemplate;
...
String userId = "11";
String url = "http://127.0.0.1:8080/v1/users/{id}";
User result = bearerAuthRestTemplate.getForObject(url, User.class, userId);
復制代碼

轉載于:https://juejin.im/post/5c8cba09e51d453e2762de2f

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

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

相關文章

譯?:Top Three Use Cases for Dapr and Kubernetes

有關譯者&#xff1a;陳東海(seachen)&#xff0c;?前就職于騰訊&#xff0c;同時在社區也是?名Dapr Member.導語&#xff1a;在SDLC(Software Development Lifecycle軟件開發?命周期中)&#xff0c;絕?多數CNCF項?都是專注于軟件開發的中后期階段&#xff0c;特別是運維和…

MySQL數據庫的datetime與timestamp

MySQL數據庫中有datetime與timestamp兩種日期時間型數據類型&#xff0c;其中timestamp可以用timestamp(n)來表示年月日時分秒的取值精度&#xff0c;如果n14則完整匹配于datetime的精度&#xff0c;那為什么還需要datetime這種類型呢&#xff1f;我做過試驗&#xff0c;timest…

平視相機svo開源項目_什么是平視顯示器(HUD),我應該得到一個嗎?

平視相機svo開源項目In a world full of augmented reality snowboard goggles and Google Glass, it seems only fair that our cars get to enjoy some of the same treatment. Heads-up displays, or “HUDs” as they’re better known, are a new type of add-on for cons…

yum 下載RPM包而不進行安裝

yum命令本身就可以用來下載一個RPM包&#xff0c;標準的yum命令提供了--downloadonly(只下載)的選項來達到這個目的。 $ sudo yum install --downloadonly <package-name> 默認情況下&#xff0c;一個下載的RPM包會保存在下面的目錄中: /var/cache/yum/x86_64/[centos/fe…

react項目打包后路徑找不到,項目打開后頁面空白的問題

使用 npm install -g create-react-app快速生成項目腳手架打包后出現資源找不到的路徑問題&#xff1a; 解決辦法&#xff1a;在package.json設置homepage 轉載于:https://www.cnblogs.com/lan-cheng/p/10541606.html

linux 下實現ssh免密鑰登錄

小伙伴經常在運維的時候需要ssh到很多其他的服務器&#xff0c;但是又要每次輸入密碼&#xff0c;一兩臺還沒什么&#xff0c;多了就煩了。所以這里教大家如何直接ssh到其他機器而不用輸入密碼。[rootjw ~]# ssh-keygen -t rsaGenerating public/private rsa key pair.Enter fi…

一些部署django用到的linux命令

mv untitled45/ /1601F/wang/ 將XXXX移動到XXX&#xff0c;也可以用于給XXX重新命名 zip -r -q -o hello.zip /1601F/3/untitled45 安靜的遞歸壓縮成zip文件 gunicorn -w 3 -b 0.0.0.0:8080 untitled45.wsgi:application啟動項目&#xff08;需要在manage.py同級目錄下運行&am…

ios 拍照 實現 連拍_如何在iOS設備上使用連拍模式拍照

ios 拍照 實現 連拍We’re sure you’ve tried to capture that perfect moment with your camera and you’re just a tad too late or too early and you miss it. If you own an iPhone or iPad, you can use burst mode and never miss that perfect shot again. 我們確定您…

pta l2-6(樹的遍歷)

題目鏈接&#xff1a;https://pintia.cn/problem-sets/994805046380707840/problems/994805069361299456 題意&#xff1a;給出一個二叉樹的結點數目n&#xff0c;后序遍歷序列post&#xff0c;中序遍歷序列in&#xff0c;求其層序遍歷序列。 思路&#xff1a;首先給二叉樹每個…

路由熱備份(HSRP)DynamipsGUI小試牛刀

——好久不見啊&#xff0c;大家最近過的還好嗎&#xff1f;——學而不思則罔&#xff0c;思而不學則殆。好了&#xff0c;既然已經踏上了CCNP之旅&#xff0c;那就和大家一起分享一下學習HSRP的體會吧——在CCNA中我們設計網絡的目的主要是——通&#xff01;到了CCNP&#xf…

WPF 如何實現簡單放大鏡

WPF 如何實現簡單放大鏡控件名&#xff1a;Magnifier作 者&#xff1a;WPFDevelopersOrg - 驚鏵原文鏈接[1]&#xff1a;https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用.NET40&#xff1b;Visual Studio 2019;實現此功能需要用到 VisualBrush &#xff0c;放大鏡…

input 禁用智能提示_如何在智能手機上禁用緊急警報

input 禁用智能提示AMBER and emergency alerts occur when there’s a child abduction or there’s an important event such as a severe weather alert (tornado warning) that local governments needs to make people aware of. While we don’t recommend disabling the…

laravel中使用的PDF擴展包——laravel-dompdf和laravel-snappy

這兩天項目中需要將HTML頁面轉換為PDF文件方便打印&#xff0c;我在網上搜了很多資料。先后嘗試了laravel-dompdf和laravel-snappy兩種擴展包&#xff0c;個人感覺laravel-snappy比較好用。 一、使用laravel-dompdf擴展包 1、安裝擴展包 我們通過composer來安裝 composer requi…

「讀懂源碼系列2」我從 lodash 源碼中學到的幾個知識點

前言 上一篇文章 「前端面試題系列8」數組去重(10 種濃縮版) 的最后&#xff0c;簡單介紹了 lodash 中的數組去重方法 _.uniq&#xff0c;它可以實現我們日常工作中的去重需求&#xff0c;能夠去重 NaN&#xff0c;并保留 {...}。 今天要講的&#xff0c;是我從 _.uniq 的源碼實…

有小伙伴問:上位機用QT還是winform/wpf好?

楔子有小伙伴問&#xff1a;上位機用QT還是winform/wpf好&#xff1f;Qt是C寫的&#xff0c;跨平臺的UI框架&#xff0c;Winform/wpf是C#寫的不跨平臺的Windows上運行的UI框架。這兩個說到底是語言本質的爭論或者區別。優點Qt的優點是可以跨平臺運行UI界面&#xff0c;在Linux&…

使用jenkins進行項目的自動構建部署

jenkins 簡介 Jenkins是基于Java開發的一種持續集成工具&#xff0c;用于監控持續重復的工作&#xff0c;功能包括&#xff1a;持續的軟件版本發布/測試項目和監控外部調用執行的工作。 官網地址地址&#xff1a; https://jenkins.io 下載安裝啟動 CentOS 下用yum進行安裝啟動 …

如何刪除Apple Music中的連接功能

Love Apple Music, but tired of the intrusive Connect feature taking up space on your favorite artist’s page? Well, don’t worry, because getting “dis-Connected” is just a matter of changing a few simple settings in your iPhone or iPad running iOS 8.0 o…

python設計模式(十四):模板方法模式

定義一個算法或者流程&#xff0c;部分環節設計為外部可變&#xff0c;用類似于模板的思想來實例化一個實體&#xff0c;可以往模板中填充不同的內容&#xff1b;在模板思想下&#xff0c;實體的整體框架是確定的&#xff0c;他是一個模板&#xff0c;但是模板下內容可變&#…

FirstBird--項目流程

創建項目(英文路徑)—–img圖片文件創建窗體–設置大小(Basic—size–>320*480)—最大化功能禁用(Expert–>setResizable(false))添加面板–設置布局方式(set Layout—>AbsoluteLayout)自己創建面板 GameMain中將Jpanel1改為WinJpanel–創建對應類–>extends JPane…