0 環境
- 系統環境: win10
- 編輯器: IDEA
1 簡介
RestTemplate
- spring3.0開始支持
- Http請求工具
- 該工具與springboot或springcloud無關
- 提供常見的REST請求模版
- 例如支持GET、PUT、POST、DELETE
- 通用請求方法 --> exchange和execute
- 實現RestOperations接口
- 該接口定義了常見的RESTful操作
2 GET操作
2.1 GET相關的2種方法介紹(重載)
@Nullable
<T> T getForObject(String var1, Class<T> var2, Object... var3) throws RestClientException;
@Nullable
<T> T getForObject(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
@Nullable
<T> T getForObject(URI var1, Class<T> var2) throws RestClientException;
<T> ResponseEntity<T> getForEntity(String var1, Class<T> var2, Object... var3) throws RestClientException;
<T> ResponseEntity<T> getForEntity(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
<T> ResponseEntity<T> getForEntity(URI var1, Class<T> var2) throws RestClientException;
public class ResponseEntity<T> extends HttpEntity<T>{xxxx}
// 屬性 比如x
public static final HttpEntity<?> EMPTY = new HttpEntity();
private final HttpHeaders headers;
@Nullable
private final T body;
private final Object status;
// 用到的方法 比如
public HttpStatus getStatusCode() {
return this.status instanceof HttpStatus ? (HttpStatus)this.status : HttpStatus.valueOf((Integer)this.status);
}
public int getStatusCodeValue() {
return this.status instanceof HttpStatus ? ((HttpStatus)this.status).value() : (Integer)this.status;
}
這2種方法的返回值
- getForObject返回一個對象(服務返回的具體值)
- getForEntity不僅返回具體數據 還可以返回狀態碼 頭信息...
2.2 首先在provider中定一個hello1接口
/**
* @Description: consumer訪問該接口 調用RestTemplate的get請求
* @Param: [name]
* @return: java.lang.String
* @Author: 水面行走
* @Date: 2020/3/4
*/
@GetMapping("/hello1")
public String hello1(String name){
return "hello provider: " + name;
}
2.3 2種方法返回值驗證
/**
* @Description: 對比2種方法的不同與相同
* @Param:
* @return:
* @Author: xxxx
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello5")
public void userHello5(){
// 獲取服務返回值
String fish = restTemplateOne.getForObject("http://provider/hello1?name={1}", String.class, "love fish");
System.out.println("getForObject --> " + fish);
// 獲取服務返回值 http響應碼 頭信息...
ResponseEntity<String> milk = restTemplateOne.getForEntity("http://provider/hello1?name={1}", String.class, "milk");
String body = milk.getBody();
System.out.println("body --> " + body);
HttpStatus statusCode = milk.getStatusCode();
System.out.println("HttpStatus --> " + statusCode);
int statusCodeValue = milk.getStatusCodeValue();
System.out.println("getStatusCodeValue --> " + statusCodeValue);
System.err.println("----------------------遍歷heards----------------------");
// 需要遍歷
HttpHeaders headers = milk.getHeaders();
Set<String> strings = headers.keySet();
for (String s : strings) {
System.out.println(s + " => " + headers.get(s));
}
}
啟動Eureka server provider consumer 訪問consumer useHello5接口
2.4 getForObject三種重載方法
getForObject和getForEntity分別有三個重載方法(傳參方式)且很類似 那么只展示一個方法即可
/**
* @Description:
* @Nullable
* <T> T getForObject(String var1, Class<T> var2, Object... var3) throws RestClientException;
*
* @Nullable
* <T> T getForObject(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
*
* @Nullable
* <T> T getForObject(URI var1, Class<T> var2) throws RestClientException;
* -------------------------------------------------------------------------------------------------------------------------------
* <T> ResponseEntity<T> getForEntity(String var1, Class<T> var2, Object... var3) throws RestClientException;
*
* <T> ResponseEntity<T> getForEntity(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
*
* <T> ResponseEntity<T> getForEntity(URI var1, Class<T> var2) throws RestClientException;
* @Param:
* @return:
* @Author: xxxx
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello6")
public void userHello6() throws UnsupportedEncodingException {
// getForObject與getForEntity類似(不是為了偷懶)
// Object... var3
System.out.println(" <---- Object... -----> ");
String fish = restTemplateOne.getForObject("http://provider/hello1?name={1}", String.class, "love fish");
System.out.println("fish --> " + fish);
// Map<String, ?> var3
System.out.println(" <---- Map<String, ?> -----> ");
HashMap<String, Object> map = new HashMap<>();
map.put("name", "lusi");
String object = restTemplateOne.getForObject("http://provider/hello1?name={name}", String.class, map);
System.out.println("map: " + object);
// URI var1
System.out.println(" <---- URI -----> ");
// 漢字需要轉碼
String encode = "李思思";
String url = "http://provider/hello1?name=" + URLEncoder.encode(encode, "UTF-8");
// string轉化為URI
URI uri = URI.create(url);
// 裝載
String forUri = restTemplateOne.getForObject(uri, String.class);
System.err.println("url --> " + forUri);
}
啟動三個服務
2.5 小結
- getForObject和getForEntity返回值區別
- getForObject返回一個對象(服務返回的具體值)
- getForEntity不僅返回具體數據 還可以返回狀態碼 頭信息...
- getForObject和getForEntity 三種重載方式的類似
- Object... --> 占位符 (?xxx={1}, xx.class, "xxxxx")
- Map<String, ?> --> 占位符為自定義key(name)需要提前聲明map (?xxx={key}, xx.class, 返回的map)
- URI --> 字符串中包含中文的需要轉碼才能創建為URI 在被調用
3 POST操作
3.1 准備
- 因為post請求可能是k:v或是json形式 需要提供2種接口 傳參對象 需要創建一個model 為了以后方便使用 直接新建一個普通的maven項目作為commons模塊 管理
步驟
1.創建maven項目作為commons項目 添加依賴 也可以不添加直接get set 隨意
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.創建一個User類
@Data
@ToString
public class User {
private Integer id;
private String name;
private String nickName;
}
3.provider和consumer引用commons模塊
<dependency>
<groupId>xxx你定義的gruopIdxxx</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3.2 provider提供接口
- 不僅要提供2個post接口 因為還有一個postForLocation方法 需要添加類 2個接口 一個重定向和一個重定向的地址
// 在provider 提供2個post接口
/**
* @Description: key:value形式傳參
* @Param: [user]
* @return: model.User
* @Author:
* @Date: 2020/xx/xx
*/
@PostMapping("/user")
public User addUser(User user){
return user;
}
/**
* @Description: json形式傳參
* @Param: [user]
* @return: model.User
* @Author:
* @Date: 2020/xx/xx
*/
@PostMapping("/user1")
public User addUser1(@RequestBody User user){
return user;
}
- 新建一個類存在重定向
// 為了重定向
@Controller
public class RegisterController {
/**
* @Description: 該post接口重定向到login頁面 是為了體驗postForLocation方法 所以響應一定是302 否則無效
* @Param: [user]
* @return: java.lang.String
* @Author:
* @Date: 2020/xx/xx
*/
@PostMapping("/register")
public String register(User user) throws UnsupportedEncodingException {
// 一定是絕對路徑 否則consumer中會報錯
// 因為是重定向 若傳參為中文 需要轉換為utf-8
return "redirect:http://provider/login?name=" + URLEncoder.encode(user.getName(), "UTF-8");
}
@GetMapping("/login")
@ResponseBody
public String login(String name){
return "login: " + name;
}
}
4 consumer的使用
由於postForObject和ResponseEntity類似 寫一種即可
4.1 postForObject的使用
/**
* @Description: 測試postForObject方法 k/v還是json形式 -> 取決於看postForObject第二個參數
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello7")
public void userHello7(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("id", 77);
map.add("name", "小明");
map.add("nickName", "笑嘻嘻");
// k/v形式
User user = restTemplateOne.postForObject("http://provider/user", map, User.class);
System.out.println(user);
user.setId(45);
// 普通object對象 --> json形式
User user1 = restTemplateOne.postForObject("http://provider/user1", user, User.class);
System.err.println(user1);
}
4.2 postForLocation的使用
當我執行post請求完后 立馬重定向(例如注冊 注冊完成后 立馬重定向到登陸頁面 postForLocation該上場了)
/**
* @Description: 測試postForLocation register接口 k/v傳參
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello8")
public void userHello8(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("id", 77);
map.add("name", "小明的");
map.add("nickName", "笑哈哈");
// 返回uri -> 重定向的地址和參數
URI uri = restTemplateOne.postForLocation("http://provider/register", map);
System.out.println("uri:" + uri);
String s = restTemplateOne.getForObject(uri, String.class);
System.out.println("打印:" + s);
}
postForLocation調用返回uri->重定向的地址(例如http://provider/login?name=%E5%B0%8F%E6%98%8E%E7%9A%84) 拿到uri后 獲取uri 發送uri請求獲取值(例如 打印:login: 小明的)
4.3 小結
- 2種傳參方式 處理方式注意一下 使用postForObject 將值傳給它的第二個參數上
- k/v形式 需要new LinkedMultiValueMap add值
- json形式 無需添加map進行處理 直接普通的對象即可 但是我們該url時 別忘了添加@RequestBody
- post接口 響應碼必須得302 不然postForLocation無效 重定向地址一定是絕對路徑 相對路徑 consumer調用就涼了
5 PUT操作
PUT重載方法少
5.1 provider提供接口
/**
* @Description: k/v形式 因為是更新操作 put方法返回為void 所以返回值為void就行 有返回值不會報錯(put和post傳參很像)
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@PutMapping("/user")
public void updateUser(User user){
System.out.println("k/v形式:" + user);
}
/**
* @Description: json形式 別忘了傳參添加注解 因為是更新操作 put方法返回為void 所以返回值為void就行 有返回值不會報錯
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@PutMapping("/user1")
public void updateUser1(@RequestBody User user){
System.out.println("json形式:" + user);
}
5.2 consumer消費接口
/**
* @Description: 2種形式 put調用的方式
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello9")
public void userHello9(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("id", 38);
map.add("name", "不過煩惱");
map.add("nickName", "笑哈哈");
// k/v形式
restTemplateOne.put("http://provider/user", map);
User user = new User();
user.setId(1);
user.setName("小米是地方");
user.setNickName("母老虎");
restTemplateOne.put("http://provider/user1", user);
}
5.3 在provider查看顯示結果
啟動項目(三個)
6 Delete操作
介紹2種傳參方式 k/v形式(xx?id=xxx) PathVariable(參數放在路徑中 xx/1)
6.1 provider提供接口
/**
* @Description: k/v形式的刪除 xxx?id=1
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@DeleteMapping("/user")
public void delUser(Integer id){
System.out.println("k/v形式:" + id);
}
/**
* @Description: PathVariable(參數放在路徑中 xxx/1)形式的刪除
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@DeleteMapping("/user1/{id}")
public void delUser1(@PathVariable Integer id){
System.out.println("json形式:" + id);
}
6.2 consumer消費接口
/**
* @Description:
* public void delete(String url, Object... uriVariables) throws RestClientException {
* this.execute(url, HttpMethod.DELETE, (RequestCallback)null, (ResponseExtractor)null, (Object[])uriVariables);
* }
* // 刪除支持map和get類似 自己測試
* public void delete(String url, Map<String, ?> uriVariables) throws RestClientException {
* this.execute(url, HttpMethod.DELETE, (RequestCallback)null, (ResponseExtractor)null, (Map)uriVariables);
* }
*
* public void delete(URI url) throws RestClientException {
* this.execute(url, HttpMethod.DELETE, (RequestCallback)null, (ResponseExtractor)null);
* }
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello10")
public void useHello10(){
// k/v --> id={1} 或是map形式 id={id},可參考getForObject中的map方式
restTemplateOne.delete("http://provider/user?id={1}", 99);
// PathVariable
restTemplateOne.delete("http://provider/user1/{1}", 99);
}
6.3 在provider上查看結果
啟動項目(三個服務)