1. 程式人生 > 其它 >Spring Cloud Alibaba - RestTemplate

Spring Cloud Alibaba - RestTemplate

Spring Cloud Alibaba - RestTemplate

Controller匯入依賴和相關屬性

@SuppressWarnings("all")
@RestController
public class TemplateController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired(required = false)
    private LoadBalancerClient loadBalancerClient;

    final String serviceName = "http://nacos-discovery-provider";  //可以通過配置檔案遠端獲取
    
}

Get請求,無引數,返回String

 //GET請求,無引數,返回String
@RequestMapping("/getstring")
public String get(){
    // ResponseEntity中包含關於這個請求返回的許多資訊,不光是結果
    ResponseEntity<String> responseEntity = restTemplate.getForEntity(serviceName+"/get",String.class);
    //String.class 指定返回型別為String
    //====================================================
    //開始獲取 ResponseEntity中的詳細資訊
    int statusCodeValue = responseEntity.getStatusCodeValue();  //狀態碼的值
    HttpStatus httpStatus = responseEntity.getStatusCode();     //狀態碼
    HttpHeaders httpHeaders = responseEntity.getHeaders();      //頭部資訊
    String body = responseEntity.getBody();                     //返回內容體
    //====================================================
    System.out.println(statusCodeValue);
    System.out.println(httpStatus);
    System.out.println(httpHeaders);
    System.out.println(body);
    //返回其中的內容體 , 等同於返回上面的 String body
    return restTemplate.getForEntity(serviceName+"/get",String.class).getBody();
}

因為此處沒有使用LoadBalancerClient做負載均衡,所以在啟動類中需要添加註解@LoadBalanced

結果為:

其中statusCodeValue = 200 httpStatus = 200 OK httpHeaders = [Content-Type:"text/plain;charset=UTF-8", Date:"Fri, 23 Jul 2021 09:02:34 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive", Content-Length:"22"] =[Content-Type:"text/plain;charset=UTF-8", Date:"Fri, 23 Jul 2021 09:02:34 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive", Content-Length:"22"]

body = this is a get response

restTemplate.getForEntity(); 方法獲取的是狀態碼、頭部資訊、結果體


Get請求,有引數,返回一個實體物件

首先在消費者和服務提供者的工程專案中都必須要含有同樣的實體類

@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private String age;
    private String msg;
}

在服務提供者中存在對應的呼叫介面:

@RestController
public class RestTemplateController {
    @RequestMapping("/getUser")
    public User getUser(@RequestParam("name")String name,
                        @RequestParam("age")String age,
                        @RequestParam("msg")String msg){
        return new User(name,age,msg);
    }
}

在消費者中呼叫:

@RequestMapping("/getEntity")
public String getUser(){
    String[] data = {"yangchen","18","from array"};
    //呼叫服務,獲取物件的statusCodeValue,httpStatus,httpHeaders,body
    ResponseEntity<User> responseEntity =
            restTemplate.getForEntity(serviceName+"/getUser?name={0}&age={1}&msg={2}",User.class,data);
    //通過將陣列中的引數放入請求連結中請求結果。通過{0} = data[0] 這樣的方式一一對應

    //getForObject僅返回該請求的內容體
    User user_array = restTemplate.getForObject(serviceName+"/getUser?name={0}&age={1}&msg={2}",User.class,data);
    //輸出資訊
    System.out.println("user_array = "+user_array);
    //============ 第二種方法 ================================
    Map<String,Object> param = new ConcurrentHashMap<String, Object>();
    param.put("name","yangchen");
    param.put("age","21");
    param.put("msg","from map");
    //呼叫服務,獲取物件的statusCodeValue,httpStatus,httpHeaders,body
    ResponseEntity<User> responseEntity1 =
            restTemplate.getForEntity(serviceName+"/getUser?name={name}&age={age}&msg={msg}",User.class,param);
    //通過將陣列中的引數放入請求連結中請求結果。通過{name} = map中的{name} 這個key的value 這樣的方式一一對應

    //getForObject僅返回該請求的內容體
    User user_map = restTemplate.getForObject(serviceName+"/getUser?name={name}&age={age}&msg={msg}",User.class,param);
    //輸出資訊
    System.out.println("user_map = "+user_map);

    return "success";
}

因為有兩種方法,暫且返回String型別,在控制檯將兩種方法獲得的User物件輸出:

tips:restTemplate.getForObject( )方法僅返回該請求的內容體


Post請求,有引數,返回實體物件

消費者中編寫介面:

//Post請求,有引數,返回實體物件
@RequestMapping("/postEntity")
public User postUser(){
    //Post請求的資料必須存放在這種型別的Map中
    MultiValueMap<String,Object> data = new LinkedMultiValueMap<String, Object>();
    data.add("name","yangchen");
    data.add("age","21");
    data.add("msg","from post map");
    //呼叫換成服務,注意這裡用的是postForEntity,其中的傳參位置有所變化!!!
    ResponseEntity<User> responseEntity =
            restTemplate.postForEntity(serviceName+"/getUser",data,User.class);

    //也可以通過postForObject直接返回請求的body
    User user_postForObject = restTemplate.postForObject(serviceName+"/getUser",data,User.class);
    System.out.println("user = "+user_postForObject);
    return restTemplate.postForEntity(serviceName+"/getUser",data,User.class).getBody();
}

結果為:

![image-20210723183459508](E:\software\JAVA\springcloud-alibaba\document\動力節點spring cloud alibaba\image-20210723183459508.png)

tips:注意引數存放只能存放在MultiValueMap介面實現類為LinkedMultiValueMap的map中,其次呼叫restTemplate.postForObject( )或者是restTemplate.postForEntity( )方法中的傳參順序與get不同,並且傳入的url中不需要帶有引數


從此以後,restTemplate.xxxForObject( ) 和 restTemplate.xxxForEntity( )兩種方法只選擇一種方法進行演示


Post請求,傳輸實體物件,返回實體物件

服務端提供相應的服務,通過@RequestBody註解來接收消費者端傳進來的物件:

@RequestMapping("/responseUser")
public User responseUser(@RequestBody User user){
    return user;
}

消費者端提供介面:

//Post請求,傳輸實體物件,返回實體物件
@RequestMapping("/postUser")
public User post(){
    User user = new User("yangchen","21","from user entity");
    User user_response = restTemplate.postForObject(serviceName+"/responseUser",user,User.class);
    return user_response;
}

將原先的資料集合替換為實體物件進行傳值。

結果為:


restTemplate呼叫傳輸JSON

消費者端:

​ 傳輸JSON格式的字串時,需要使用HttpEntity 對JSON

進行包裝才可以傳輸。

//restTemplate呼叫傳輸JSON
@RequestMapping("/postJson")
public User postJson(){
    //定義JSON字串
    String json = "{\"name\": \"yangchen\",\"age\": \"21\",\"msg\": \"from json\"}";
    HttpHeaders headers = new HttpHeaders();
    //設定格式為JSON格式
    headers.setContentType(MediaType.APPLICATION_JSON);
    //將http頭和json字串使用HttpEntity進行包裝然後傳輸
    HttpEntity<String> entity = new HttpEntity<String>(json,headers);
    User user_json=restTemplate.postForObject(serviceName+"/responseUser",entity,User.class);
    return user_json;
}

服務者端:

同樣使用註解@RequestBody 進行接收:

@RequestMapping("/responseUser")
public User responseUser(@RequestBody User user){
    return user;
}

結果如下:


tips:如果restTemplate.postForObject( )方法中除了傳輸的物件還存在另外需要傳的值,如:token,只需在後面繼續新增,逗號隔開即可。因為在底層這邊維護的是一個可變陣列

服務端可以通過@RequestParam註解的方式進行獲取:


Put請求--一般作為修改使用

同樣修改時的相關引數需要存在MultiValueMap<String,Object> dataMap = new LinkedMultiValueMap<String,Object>( );中。因為Put請求和Post請求類似,甚至可以使用Post請求去代替Put請求。

服務端:

@RequestMapping("/getUser")
public User getUser(@RequestParam("name")String name,
                    @RequestParam("age")String age,
                    @RequestParam("msg")String msg){
    return new User(name,age,msg);
}

不能使用@RequestBody【User user】 方法接收。

消費者端:

//PUT請求
@RequestMapping("/put")
public String put(){
    //只能使用MultiValueMap存,和Post一樣
    MultiValueMap<String,Object> multiValueMap = new LinkedMultiValueMap<String, Object>();
    multiValueMap.add("name","yangchen");
    multiValueMap.add("age","21");
    multiValueMap.add("msg","from put");
    //呼叫遠端服務,put方法沒有返回值
    restTemplate.put(serviceName+"/getUser",multiValueMap);
    return "success";
}

Delete請求

delete請求可以使用get請求代替。引數繫結方式和get請求類似:

消費端介面:

//delete請求
@RequestMapping("/delete")
public String delete(){
    //陣列存取引數
    String[] param_array = {"yangchen","21","from delete array"};
    //遠端呼叫服務
    restTemplate.delete(serviceName+"/getUser?name={0}&age={1}&msg={2}",param_array);
    //====================================================
    //Map存引數
    Map<String,Object> paramMap = new ConcurrentHashMap<String, Object>();
    paramMap.put("name","yangchen");
    paramMap.put("age","21");
    paramMap.put("msg","from param map");
    restTemplate.delete(serviceName+"/getUser?name={name}&age={age}&msg={msg}",paramMap);

    return "success";
}

與GET請求類似,但是restTemplate.delete( )方法沒有返回值。


RestTemplate+Ribbon實現負載均衡

Ribbon

ribbon是客戶端負載均衡

使用Ribbon需要新增依賴(客戶端):
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

我們在啟動類中進行新增:

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class NacosConsumerApplication {

   public static void main(String[] args) {
      SpringApplication.run(NacosConsumerApplication.class, args);
   }

   @LoadBalanced //如果使用了loadBalancerClient進行了代理,則已經做過一次負載均衡,此處的註解不能加
   @Bean
   public RestTemplate restTemplate(){
      return new RestTemplate();
   }
}