1. 程式人生 > 實用技巧 >6、SpringCloud之Rest請求模板類

6、SpringCloud之Rest請求模板類

服務消費端去呼叫服務提供者的服務的時候,使用了RestTemplate。RestTemplate通過getForEntity方法發起請求呼叫服務端的資料,並通過@LoadBanlaced註解開啟客戶端負載均衡。

RestTemplate中常見請求方法的使用

GET
POST
PUT
DELETE

通過註解指定通過什麼請求方式進行訪問,如下:

 @Autowired
    private RestTemplate restTemplate;

//  通過@GetMapping註解就能夠指定請求方式
    @GetMapping("/web/hello")
    public String hello(){

//        Eureka + Ribbon的呼叫服務的方式(這種方式不再需要ip地址和埠號了)
        return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello", String.class).getBody();

    }

RestTemplate 的 GET請求

Get請求可以有兩種方式

第一種:getForEntity

該方法返回一個ResponseEntity物件,ResponseEntity是Spring對HTTP請求響應的封裝,包括了幾個重要的元素,比如響應嗎、contentType、contentLength、響應訊息體等;

 @Autowired
    private RestTemplate restTemplate;

//    @RequestMapping("/web/hello")
    @GetMapping("/web/hello")
    public String hello(){

        //這裡泛型之所以是String型別,是因為方法的第二引數指定了返回型別為String
        ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello", String.class);
        int statusCodeValue = responseEntity.getStatusCodeValue();
        HttpStatus statusCode = responseEntity.getStatusCode();
        HttpHeaders headers = responseEntity.getHeaders();
        String body = responseEntity.getBody();

        System.out.println(statusCodeValue);
        System.out.println(statusCode);
        System.out.println(headers);
        System.out.println(body);

//        Eureka + Ribbon的呼叫服務的方式(這種方式不再需要ip地址和埠號了)
        return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello", String.class).getBody();

    }

getForEntity方法第二個引數String.class 表示希望返回的body型別是String型別,如果希望返回一個物件,也是可以的,比如User物件;

給兩個服務提供者端,提供實體類User

package com.example.springcloud.model;

public class User {

    private Integer id;
    private String name;
    private String phone;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
}

並提供返回值為User的Controller方法

    @RequestMapping("/service/user")
    public User user(){
        User user = new User();
        user.setId(12);
        user.setName("小黑");
        user.setPhone("12345678978");

        return user;
    }

此時,由於服務呼叫者呼叫此方法返回資料將資料繫結到實體類User物件上,所以也需要建立User實體類;
當多個工程都需要同一個實體類時,可以選擇構建父工程,用Maven進行模組化管理。

此外,服務呼叫端需要提供一個方法來呼叫服務提供端

      @GetMapping("/web/user")
    public String user(){
        //這裡泛型之所以是String型別,是因為方法的第二引數指定了返回型別為String
        ResponseEntity<User> responseEntity = restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/user", User.class);
        int statusCodeValue = responseEntity.getStatusCodeValue();
        HttpStatus statusCode = responseEntity.getStatusCode();
        HttpHeaders headers = responseEntity.getHeaders();
        User body = responseEntity.getBody();

        System.out.println(statusCodeValue);
        System.out.println(statusCode);
        System.out.println(headers);
        System.out.println(body.getId()+","+body.getName()+","+body.getPhone());

//        Eureka + Ribbon的呼叫服務的方式(這種方式不再需要ip地址和埠號了)
        return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello", String.class).getBody();

    }

完成之後,啟動服務註冊中心工程,服務提供端,以及服務呼叫端進行測試

getForEntity 常用的過載方法

服務提供端 接收請求引數並進行返回

    //通過@RequestParam進行引數繫結
    @RequestMapping("/service/user")
    public User getUser(@RequestParam("id") Integer id,
                         @RequestParam("name") String name,
                         @RequestParam("phone") String phone){
        System.out.println("服務提供者1");

        User user = new User();
        user.setId(id);
        user.setName(name);
        user.setPhone(phone);

        return user;
    }

服務消費端
下面以兩種方式。通過陣列和Map對url請求地址進行引數繫結

    /**
     * getForEntity()以陣列的方式將引數繫結到URL引數中
     * 通過 {下標} 佔位符的方式進行繫結
     * 返回資料的封裝型別為User型別(返回值型別也可以是String)
     * @return
     */
    @GetMapping("/web/ArrayParamGetUser")
    public String getUser(){
        String[] strArray = {"105", "小紅", "12345678989"};

//        Eureka + Ribbon的呼叫服務的方式(這種方式不再需要ip地址和埠號了)
        return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/getUser?id={1}&name={2}&phone={3}", User.class, strArray).getBody().toString();

    }

    /**
     * getForEntity()以陣列的方式將引數繫結到URL引數中
     * 通過 {key} 佔位符的方式進行繫結
     * 返回值型別是String型別
     * @return
     */
    @GetMapping("/web/MapParamgetUser")
    public String getUser2(){
        Map<String, Object> paramMap = new ConcurrentHashMap<>();
        paramMap.put("id",1);
        paramMap.put("name","小誠");
        paramMap.put("phone", "1546879166");

//        Eureka + Ribbon的呼叫服務的方式(這種方式不再需要ip地址和埠號了)
        return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/getUser?id={id}&name={name}&phone={phone}", String.class, paramMap).getBody();

    }

第二種:getForObject()

共同點
getForObject()方法是getForEntity()方法的封裝;
getForEntity方法過載的,getForObject方法也有,使用方式也類似;

不同點
getForEntity方法可以拿到返回的資料,同時也可以拿到頭部資訊狀態碼等;
getForObject方法只能用於獲取返回的body資訊;

    /**
     * getForEntity()以Map的方式將引數繫結到URL引數中
     * @return
     */
    @GetMapping("/web/getUserByGetForObject")
    public String getUserByGetForObject(){

        Map<String, Object> paramMap = new ConcurrentHashMap<>();
        paramMap.put("id",1);
        paramMap.put("name","小誠");
        paramMap.put("phone", "1546879166");
        //用請求模板類RestTemplate的getForObject方法,傳入一個Map物件通過{key}佔位符繫結url請求引數,返回值型別為String型別
        String body = restTemplate.getForObject("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/getUser?id={id}&name={name}&phone={phone}", String.class, paramMap);
        System.out.println(body);

        String[] strArray = {"105", "小紅", "12345678989"};
        //用請求模板類RestTemplate的getForObject方法,傳入一個Map物件通過{index}佔位符繫結url請求引數,返回值型別為User物件型別
        User user2 = restTemplate.getForObject("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/getUser?id={id}&name={name}&phone={phone}", User.class, strArray);
        System.out.println(user2);
        
        
        return restTemplate.getForObject("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello", String.class);
    }

RestTemplate 的 POST 請求

POST 與 Get 請求 非常類似

restTemplate.postForObject()
restTemplate.postForEntity()
restTemplate.postForLocation()

服務提供者新增支援Post請求的方法

//  @RequestMapping(value="/service/addUser", method = RequestMethod.POST)
    @PostMapping("/service/addUser")
    public User addUser(@RequestParam("id") Integer id,
                        @RequestParam("name") String name,
                        @RequestParam("phone") String phone){
        System.out.println("服務提供者1");

        User user = new User();
        user.setId(id);
        user.setName(name);
        user.setPhone(phone);

        //將user物件插入資料庫(暫時省略)
        return user;
    }

服務消費者新增呼叫Post請求的方法

    /**
     * 消費者呼叫 -addUser方法
     * @return
     */
    @RequestMapping("/web/addUser")
    public String addUser(){
        //注意post請求傳遞引數只能用MultiValueMap
        MultiValueMap<String, Object> dataMap = new LinkedMultiValueMap();
        dataMap.add("id",1);
        dataMap.add("name","小誠");
        dataMap.add("phone", "1546879166");


        ResponseEntity<User> responseEntity = restTemplate.postForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/addUser", dataMap, User.class);
        System.out.println(responseEntity.getStatusCodeValue());
        System.out.println(responseEntity.getStatusCode());
        System.out.println(responseEntity.getHeaders());
        System.out.println(responseEntity.getBody());


        User user = restTemplate.postForObject("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/addUser", dataMap, User.class);
        System.out.println(user);

        return "請求成功";
    }

RestTemplate 的 PUT 請求

服務提供者新增支援Put請求的方法

//    @RequestMapping(value="/service/updateUser", method = RequestMethod.PUT)
    @PutMapping("/service/updateUser")
    public User updateUser(@RequestParam("id") Integer id,
                        @RequestParam("name") String name,
                        @RequestParam("phone") String phone){

        User user = new User();
        user.setId(id);
        user.setName(name);
        user.setPhone(phone);

        System.out.println("服務提供者1");
        System.out.println(user);

        //將user物件插入資料庫(暫時省略)
        return user;
    }

服務消費者新增呼叫Put請求的方法

    /**
     * 消費者呼叫 -updateUser方法
     * @return
     */
    @RequestMapping("/web/updateUser")
    public String updateUser(){

        MultiValueMap<String, Object> dataMap = new LinkedMultiValueMap();
        dataMap.add("id",1);
        dataMap.add("name","小誠");
        dataMap.add("phone", "1546879166");

        //put請求沒有返回值
        restTemplate.put("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/updateUser",dataMap);

        return "請求成功";
    }

RestTemplate 的 DELETE 請求

服務提供者新增支援Put請求的方法

//    @RequestMapping(value="/service/addUser", method = RequestMethod.PUT)
    @DeleteMapping("/service/deleteUser")
    public User deleteUser(@RequestParam("id") Integer id,
                           @RequestParam("name") String name,
                           @RequestParam("phone") String phone){

        User user = new User();
        user.setId(id);
        user.setName(name);
        user.setPhone(phone);

        System.out.println("服務提供者2");
        System.out.println(user);

        //將user物件插入資料庫(暫時省略)
        return user;
    }

服務消費者新增呼叫Delete請求的方法

    /**
     * 消費者呼叫 -deleteUser方法
     * @return
     */
    @RequestMapping("/web/deleteUser")
    public String deleteUser(){
        String[] strArray = {"105", "小紅", "12345678989"};

        restTemplate.delete("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/deleteUser?id={0}&name={1}&phone={2}", strArray);

        Map<String, Object> paramMap = new ConcurrentHashMap<>();
        paramMap.put("id",1);
        paramMap.put("name","小誠");
        paramMap.put("phone", "1546879166");

        restTemplate.delete("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/deleteUser?id={id}&name={name}&phone={phone}", paramMap);


        return "請求成功";
    }

總結:
Get 和 Delete 寫法相似
Post 和 Put 寫法相似