https://github.com/lenve/SimpleSpringCloud/tree/master/RestTemplate在Spring Cloud中服務的發現與消費一文中,當我們從服務消費端去調用服務提供者的服務的時候,使用了一個很好用的對象,叫做RestTemplate,當時我們只使用了RestTemplate中最簡單的一個功能getForEntity發起了一個get請求去調用服務端的數據,同時,我們還通過配置@LoadBalanced注解開啟客戶端負載均衡,RestTemplate的功能不可謂不強大,那么今天我們就來詳細的看一下RestTemplate中幾種常見請求方法的使用。
本文是Spring Cloud系列的第六篇文章,了解前五篇文章的內容有助於更好的理解本文:
1.使用Spring Cloud搭建服務注冊中心
2.使用Spring Cloud搭建高可用服務注冊中心
3.Spring Cloud中服務的發現與消費
4.Eureka中的核心概念
5.什么是客戶端負載均衡
本文主要從以下四個方面來看RestTemplate的使用:
- GET請求
- POST請求
- PUT請求
- DELETE請求
OK,開始吧。
環境搭建
首先我們要搭建一個測試環境,方便我們一會驗證相應的API。
服務注冊中心我就直接使用前文(使用Spring Cloud搭建服務注冊中心)中創建的服務注冊中心。
服務提供者和服務消費者我創建在一個maven工程中,如果小伙伴對IntelliJ IDEA中創建maven多模塊項目還不了解的話,可以參考IntelliJ IDEA中創建Web聚合項目(Maven多模塊項目)。創建好的maven項目如下圖所示:
其中commons是一個公共模塊,是一個普通的JavaSE工程,我們一會主要將實體類寫在這個模塊中,provider和consumer是兩個spring boot項目,provider將扮演服務提供者的角色,consumer扮演服務消費者的角色。
commons模塊主要用來提供實體類,內容如下:
然后在provider和consumer模塊中添加對commons的依賴,依賴代碼如下:
<dependency> <groupId>org.sang</groupId> <artifactId>commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
- 1
- 2
- 3
- 4
- 5
provider和consumer的開發小伙伴們可以參考使用Spring Cloud搭建服務注冊中心和Spring Cloud中服務的發現與消費,我這里就不再贅述了。下文中我只列出provider和consumer的核心代碼,文末可以下載源碼。
GET請求
在RestTemplate中,發送一個GET請求,我們可以通過如下兩種方式:
第一種:getForEntity
getForEntity方法的返回值是一個ResponseEntity<T>
,ResponseEntity<T>
是Spring對HTTP請求響應的封裝,包括了幾個重要的元素,如響應碼、contentType、contentLength、響應消息體等。比如下面一個例子:
@RequestMapping("/gethello") public String getHello() { ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class); String body = responseEntity.getBody(); HttpStatus statusCode = responseEntity.getStatusCode(); int statusCodeValue = responseEntity.getStatusCodeValue(); HttpHeaders headers = responseEntity.getHeaders(); StringBuffer result = new StringBuffer(); result.append("responseEntity.getBody():").append(body).append("<hr>") .append("responseEntity.getStatusCode():").append(statusCode).append("<hr>") .append("responseEntity.getStatusCodeValue():").append(statusCodeValue).append("<hr>") .append("responseEntity.getHeaders():").append(headers).append("<hr>"); return result.toString(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
關於這段代碼,我說如下幾點:
- getForEntity的第一個參數為我要調用的服務的地址,這里我調用了服務提供者提供的/hello接口,注意這里是通過服務名調用而不是服務地址,如果寫成服務地址就沒法實現客戶端負載均衡了。
- getForEntity第二個參數String.class表示我希望返回的body類型是String
- 拿到返回結果之后,將返回結果遍歷打印出來
最終顯示結果如下:
有時候我在調用服務提供者提供的接口時,可能需要傳遞參數,有兩種不同的方式,如下:
@RequestMapping("/sayhello") public String sayHello() { ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/sayhello?name={1}", String.class, "張三"); return responseEntity.getBody(); } @RequestMapping("/sayhello2") public String sayHello2() { Map<String, String> map = new HashMap<>(); map.put("name", "李四"); ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/sayhello?name={name}", String.class, map); return responseEntity.getBody(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 可以用一個數字做占位符,最后是一個可變長度的參數,來一一替換前面的占位符
- 也可以前面使用name={name}這種形式,最后一個參數是一個map,map的key即為前邊占位符的名字,map的value為參數值
第一個調用地址也可以是一個URI而不是字符串,這個時候我們構建一個URI即可,參數神馬的都包含在URI中了,如下:
@RequestMapping("/sayhello3") public String sayHello3() { UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://HELLO-SERVICE/sayhello?name={name}").build().expand("王五").encode(); URI uri = uriComponents.toUri(); ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class); return responseEntity.getBody(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
通過Spring中提供的UriComponents來構建Uri即可。
當然,服務提供者不僅可以返回String,也可以返回一個自定義類型的對象,比如我的服務提供者中有如下方法:
@RequestMapping(value = "/getbook1", method = RequestMethod.GET) public Book book1() { return new Book("三國演義", 90, "羅貫中", "花城出版社"); }
- 1
- 2
- 3
- 4
對於該方法我可以在服務消費者中通過如下方式來調用:
@RequestMapping("/book1") public Book book1() { ResponseEntity<Book> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/getbook1", Book.class); return responseEntity.getBody(); }
- 1
- 2
- 3
- 4
- 5
運行結果如下:
第二種:getForObject
getForObject函數實際上是對getForEntity函數的進一步封裝,如果你只關注返回的消息體的內容,對其他信息都不關注,此時可以使用getForObject,舉一個簡單的例子,如下:
@RequestMapping("/book2") public Book book2() { Book book = restTemplate.getForObject("http://HELLO-SERVICE/getbook1", Book.class); return book; }
- 1
- 2
- 3
- 4
- 5
getForObject也有幾個重載方法,如下:
這幾個重載方法參數的含義和getForEntity一致,我就不再贅述了。
POST請求
在RestTemplate中,POST請求可以通過如下三個方法來發起:
第一種:postForEntity
該方法和get請求中的getForEntity方法類似,如下例子:
@RequestMapping("/book3") public Book book3() { Book book = new Book(); book.setName("紅樓夢"); ResponseEntity<Book> responseEntity = restTemplate.postForEntity("http://HELLO-SERVICE/getbook2", book, Book.class); return responseEntity.getBody(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 方法的第一參數表示要調用的服務的地址
- 方法的第二個參數表示上傳的參數
- 方法的第三個參數表示返回的消息體的數據類型
我這里創建了一個Book對象,這個Book對象只有name屬性有值,將之傳遞到服務提供者那里去,服務提供者代碼如下:
@RequestMapping(value = "/getbook2", method = RequestMethod.POST) public Book book2(@RequestBody Book book) { System.out.println(book.getName()); book.setPrice(33); book.setAuthor("曹雪芹"); book.setPublisher("人民文學出版社"); return book; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
服務提供者接收到服務消費者傳來的參數book,給其他屬性設置上值再返回,調用結果如下:
postForEntity的其他重載方法如下:
這些方法的參數含義和getForEntity參數的含義一致,不再贅述。
第二種:postForObject
如果你只關注,返回的消息體,可以直接使用postForObject。用法和getForObject一致。
第三種:postForLocation
postForLocation也是提交新資源,提交成功之后,返回新資源的URI,postForLocation的參數和前面兩種的參數基本一致,只不過該方法的返回值為Uri,這個只需要服務提供者返回一個Uri即可,該Uri表示新資源的位置。
PUT請求
在RestTemplate中,PUT請求可以通過put方法調用,put方法的參數和前面介紹的postForEntity方法的參數基本一致,只是put方法沒有返回值而已。舉一個簡單的例子,如下:
@RequestMapping("/put") public void put() { Book book = new Book(); book.setName("紅樓夢"); restTemplate.put("http://HELLO-SERVICE/getbook3/{1}", book, 99); }
- 1
- 2
- 3
- 4
- 5
- 6
book對象是我要提交的參數,最后的99用來替換前面的占位符{1}
DELETE請求
delete請求我們可以通過delete方法調用來實現,如下例子:
@RequestMapping("/delete") public void delete() { restTemplate.delete("http://HELLO-SERVICE/getbook4/{1}", 100); }
- 1
- 2
- 3
- 4
delete方法也有幾個重載的方法,不過重載的參數和前面基本一致,不贅述。
OK,以上就是我們對RestTemplate能夠發送的請求的一個詳細介紹,有問題歡迎留言討論。
本文案例地址:https://github.com/lenve/SimpleSpringCloud/tree/master/RestTemplate