1. 程式人生 > >易筋SpringBoot 2.1 | 第四篇:RestTemplate方法詳解(2)

易筋SpringBoot 2.1 | 第四篇:RestTemplate方法詳解(2)

寫作時間:2018-12-27
Spring Boot: 2.1 ,JDK: 1.8, IDE: IntelliJ IDEA,

說明

上一篇SpringBoot 2.1 | 第三篇:RestTemplate請求HTTP(1)簡單運用了RestTemplate,
本篇主要講解RestTemplate的主要請求方法, getForObject, getForEntity, exchange(方法列舉只用了Get)。Method包括GET、POST、PUT、DELETE。引數傳遞,解析等。

在講述使用之前,想要理解SpringMVC的幾個常用註解:

  1. @Controller
    :修飾class,用來建立處理http請求的物件
  2. @RestController:Spring4之後加入的註解,原來在@Controller中返回json需要@ResponseBody來配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,預設返回json格式。
  3. @RequestMapping:配置url對映
  4. @PostMapping: 這個是@RequestMapping+POST方法的簡寫
  5. @RequestHeader: 請求Header引數
  6. @PathVariable: URL路徑引數,比如/user/{id}中的id引數
  7. @RequestParam: URL請求引數,比如/user?id=1中的id引數
  8. @RequestBody: 請求Body引數

工程建立

參照教程【SpringBoot 2.1 | 第一篇:構建第一個SpringBoot工程】新建一個Spring Boot專案,名字叫demoresttemplatemethod, 在目錄src/main/java/resources 下找到配置檔案application.properties,重新命名為application.yml

建立RestTemplateConfig配置類

請求都需要用到restTemplate物件,用@Bean的方式注入,用同一個工廠物件統一管理ClientHttpRequestFactory


新建類:
com.zgpeace.demoresttemplatemethod.configure.RestTemplateConfig

package com.zgpeace.demoresttemplatemethod.configure;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(5000);//ms
        factory.setConnectTimeout(15000);//ms
        return factory;
    }
}

建立Model物件User

結果實體User用於資料傳遞,新建類
com.zgpeace.demoresttemplatemethod.model.User

package com.zgpeace.demoresttemplatemethod.model;

public class User {

    private Integer id;
    private String methodName;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", methodName='" + methodName + '\'' +
                '}';
    }
}

建立Restful被呼叫類

REST,即Representational State Transfer的縮寫,對這個片語的翻譯是表現層狀態轉化。

RESTful是一種軟體設計風格,就是目前最流行的一種網際網路軟體架構。它結構清晰、符合標準、易於理解、擴充套件方便,所以正得到越來越多網站的採用。

這裡為了演示,會將資料儲存到記憶體Map中,實際使用肯定是儲存到資料庫中。

建立Restful被呼叫類:
com.zgpeace.demoresttemplatemethod.web.UserController
呼叫方法包括GETPOSTPUTDELETE, 以及帶引數的例子。
說明:PUT是冪等性方法,也就是請求多次跟一次的效果一樣,就像微信轉賬一樣,一次轉賬弱網情況下可能會重試,但是結果不會因為多次嘗試而不一樣。而POST不是冪等性的方法,也就是多次重試,會有多個結果。

package com.zgpeace.demoresttemplatemethod.web;

import com.zgpeace.demoresttemplatemethod.model.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @RequestMapping(value = "/testGet", method = RequestMethod.GET)
    public User testGet() {
        User user = new User();
        user.setId(1);
        user.setMethodName("get");
        return user;
    }

    @RequestMapping(value = "/testPost", method = RequestMethod.POST)
    public User testPost() {
        User user = new User();
        user.setId(1);
        user.setMethodName("post");
        return user;
    }

    @RequestMapping(value = "/testPostParam", method = RequestMethod.POST)
    public String testPostParam(@RequestParam("id") String id, @RequestParam("methodName") String methodName) {
        System.out.println("Post id: " + id);
        System.out.println("Post methodName: " + methodName);
        return "post id{" + id + "} success";
    }

    @RequestMapping(value = "/testPut", method = RequestMethod.PUT)
    public String testPut(@RequestParam("id") String id, @RequestParam("methodName") String methodName) {
        System.out.println("put id: " + id);
        System.out.println("put methodName: " + methodName);
        return "put id{" + id + "} success";
    }

    @RequestMapping(value = "/testDel", method = RequestMethod.DELETE)
    public String testDel(@RequestParam("id") String id) {
        System.out.println("del id: " + id);
        return "del id{" + id + "} success";
    }

}

建立使用RestTemplate呼叫Rest介面的Controller

呼叫的方法包括:getForObject, getForEntity, exchange(方法列舉只用了Get,Method包括GET、POST、PUT、DELETE).
新建類com.zgpeace.demoresttemplatemethod.web.UserRequestController

package com.zgpeace.demoresttemplatemethod.web;

import com.zgpeace.demoresttemplatemethod.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.net.URISyntaxException;

@RestController
public class UserRequestController {

    @Autowired
    private RestTemplate restTemplate;

    private static String PROTOCOL = "http";
    private static String HOST = "localhost";
    private static String PORT = "8080";
    private static String PRE_URL = PROTOCOL + "://" + HOST + ":" + PORT + "/";

    private static String GET_URL = PRE_URL + "testGet";
    private static String POST_URL = PRE_URL + "testPost";
    private static String POST_PARAM_URL = PRE_URL +  "testPostParam";
    private static String PUT_URL = PRE_URL + "testPut";
    private static String DEL_URL = PRE_URL +  "testDel";

    @GetMapping("/requestTestGet")
    public String requestTestGet() throws URISyntaxException {
        // 1. getForObject()
        User user1 = restTemplate.getForObject(GET_URL, User.class);
        System.out.println("get user1: " + user1);

        // 2. getForEntity()
        ResponseEntity<User> responseEntity1 = restTemplate.getForEntity(GET_URL, User.class);
        HttpStatus statusCode = responseEntity1.getStatusCode();
        HttpHeaders header = responseEntity1.getHeaders();
        User user2 = responseEntity1.getBody();
        System.out.println("get user2: " + user2);
        System.out.println("get statusCode: " + statusCode);
        System.out.println("get header: " + header);

        // 3. exchange()
        RequestEntity requestEntity = RequestEntity.get(new URI(GET_URL)).build();
        ResponseEntity<User> responseEntity2 = restTemplate.exchange(requestEntity, User.class);
        User user3 = responseEntity2.getBody();
        System.out.println("get user3: " + user3);

        return "requestTestGet";
    }

    @GetMapping("/requestTestPost")
    public String requestTestPost() throws URISyntaxException {
        HttpHeaders headers = new HttpHeaders();
        String data = new String();
        HttpEntity<String> formEntity = new HttpEntity<String>(data, headers);

        // 1. postForObject()
        User user1 = restTemplate.postForObject(POST_URL, formEntity, User.class);
        System.out.println("post user1: " + user1);

        // 2. postForEntity()
        ResponseEntity<User> responseEntity1 = restTemplate.postForEntity(POST_URL, formEntity, User.class);
        HttpStatus statusCode = responseEntity1.getStatusCode();
        HttpHeaders header = responseEntity1.getHeaders();
        User user2 = responseEntity1.getBody();
        System.out.println("post user2: " + user2);
        System.out.println("post statusCode: " + statusCode);
        System.out.println("post header: " + header);

        // 3. exchange()
        RequestEntity requestEntity = RequestEntity.post(new URI(POST_URL)).body(formEntity);
        ResponseEntity<User> responseEntity2 = restTemplate.exchange(requestEntity, User.class);
        User user3 = responseEntity2.getBody();
        System.out.println("post user3: " + user3);

        return "requestTestPost";
    }

    @GetMapping("/requestTestPostParam")
    public String requestTestPostParam() {
        HttpHeaders headers = new HttpHeaders();
        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.add("id", "100");
        map.add("methodName", "requestTestPostParam");
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);

        String data = restTemplate.postForObject(POST_PARAM_URL, request, String.class);
        System.out.println("requestTestPostParam data: " + data);
        System.out.println("requestTestPostParam success");

        return "requestTestPostParam";
    }

    @GetMapping("requestTestPut")
    public String requestTestPut() {
        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.add("id", "101");
        map.add("methodName", "requestTestPut");
        restTemplate.put(PUT_URL, map);
        System.out.println("requestTestPut success");

        return "requestTestPut";
    }

    @GetMapping("requestTestDel")
    public String requestTestDel() {
        HttpHeaders headers = new HttpHeaders();
        //  請勿輕易改變此提交方式,大部分的情況下,提交方式都是表單提交
       headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //  封裝引數,千萬不要替換為Map與HashMap,否則引數無法傳遞
        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.add("id", "101");
        map.add("methodName", "requestTestDel");
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(map, headers);
        // 方法一
        ResponseEntity<String> resp = restTemplate.exchange(DEL_URL , HttpMethod.DELETE, requestEntity, String.class, 227);
        System.out.println("requestTestDel response: " + resp.getBody());

        // 方法二
//        restTemplate.delete(DEL_URL + "?id={id}", 102);
        System.out.println("requestTestDel success");

        return "requestTestDel";
    }

}

方法解說:

  1. HttpEntity的結構
    HttpEntity是對HTTP請求的封裝,包含兩部分,header與body,header用於設定請求頭,而body則用於設定請求體,所以其的構造器如下:
//  value為請求體
//  header為請求頭
HttpEntity<String> requestEntity = new HttpEntity<String>(value, headers);
  1. 後端處理前端提交的資料時,既可以使用Form解析,也可以使用JSON解析Payload字串。

Form解析可以直接從Request物件中獲取請求引數,這樣物件轉換與處理相對容易,但在大片JSON資料需要提交時,可能會出現大量的資料拆分與處理工作,另外針對集合型別的處理,也是其比較孱弱的地方。

而Payload的優勢是一次可以提交大量JSON字串,但無法從Request從獲取引數,也會受限於JSON解析的深度(尤其是有多層物件級聯的情況,最底層的物件幾乎無法轉換為具體型別)。

 HttpHeaders headers = new HttpHeaders();
  //  form表單提交
 headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
  //  payload提交
 headers.setContentType(MediaType.APPLICATION_JSON);
  1. 用exchange方法提交
    exchange可以執行所有HTTP的方法(GET、POST、PUT、DELETE、HEAD).
    HttpEntity封裝引數的時候必須用MultiValueMap,千萬不要替換為Map與HashMap,否則引數無法傳遞。
 //  封裝引數,MultiValueMap千萬不要替換為Map與HashMap,否則引數無法傳遞
        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.add("id", "101");
        map.add("methodName", "requestTestDel");
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(map, headers);

執行結果,控制檯列印資訊:

requestTestGet執行輸出

get user1: User{id=1, methodName='get'}
get user2: User{id=1, methodName='get'}
get statusCode: 200 OK
get header: {Content-Type=[application/json;charset=UTF-8], Transfer-Encoding=[chunked], Date=[Thu, 27 Dec 2018 10:28:22 GMT]}
get user3: User{id=1, methodName='get'}

requestTestPost執行輸出

post user1: User{id=1, methodName='post'}
post user2: User{id=1, methodName='post'}
post statusCode: 200 OK
post header: {Content-Type=[application/json;charset=UTF-8], Transfer-Encoding=[chunked], Date=[Thu, 27 Dec 2018 10:29:50 GMT]}
post user3: User{id=1, methodName='post'}

requestTestPostParam執行輸出

PostParam id: 100
PostParam methodName: requestTestPostParam
requestTestPostParam data: post id{100} success
requestTestPostParam success

requestTestPut執行輸出

put id: 101
put methodName: requestTestPut
requestTestPut success

requestTestDel執行輸出

requestTestDel before
del id: 101
requestTestDel response: del id{101} success
requestTestDel success

總結

恭喜你! 已經完成RestTemplate中的常用方法用法。

程式碼下載:
https://github.com/zgpeace/Spring-Boot2.1/tree/master/demoresttemplatemethod

參考:
https://my.oschina.net/sdlvzg/blog/1800395
https://blog.csdn.net/yiifaa/article/details/77939282
https://blog.csdn.net/yiifaa/article/details/73468001
https://www.xncoding.com/2017/07/05/spring/sb-restful.html