【API知識】RestTemplate的使用

貓毛·波拿巴發表於2019-04-04

前言

  在某種情況下,後臺服務可能需要訪問另一臺伺服器的REST介面。以前估計不少人用的都是HttpRequest類來著,結合Paser解析JSON格式的Body。現在Spring Boot的Web Starter就自帶了RestTemplate,直接用它的就好了。最好不要再往專案裡導新的依賴。這裡做了點整理,分享出來。發

簡單的請求

一、GET請求

案例如下:

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<CustomClass>  responseEntity = restTemplate.getForEntity(url, CustomClass.class);
CustomClass response = responseEntity.getBody();

(1)getForEntity 顧名思義就是傳送GET請求,並得到一個物件

(2)這裡的URL應該是完整的,即應該是這樣的格式:"http://域名:埠/xxx/yyy"

(3)CustomClass是你自己定義的類,tempalte會將請求響應的JSON格式的body解析成CustomClass。

(4)ResponseEntity是請求響應的結果,可以獲取響應碼,以及最重要的響應Body

注意:由於RestTemplate是使用Jackson來進行對映的,而Jackson本質上是用setter/getter來實現的。其中JSON字串轉物件需要setter,物件轉JSON字串需要getter。這裡是字元轉物件,所以你定義的類必須有setter。

二、POST請求

案例如下:

...
restTemplate.postForEntity(url, ParamObject, Response.class);
...

基本操作同上,不過postForEntity的第二個引數是請求物件,底層會將其轉為JSON字元存入請求Body中

傳輸form/data

一、普通的表單請求

//用MultiValueMap儲存表單資料
MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
param.add("param1","1232");
param.add("param2","12312");
//用HttpEntity進行包裝
HttpEntity<MultiValueMap<String,Object>> httpEntity = new HttpEntity<>(param);
//傳送請求
ResponseEntity<Response> responseEntity = restTemplate.postForEntity(url, httpEntity, Response.class);

這就相對於提交了一個普通的表單

二、帶檔案的表單請求

有時候我們需要把本地檔案通過Post請求傳送給另一個應用,可以這麼做。而對方接收的時候就用@RequestParam("file") MultipartFile來接收。

MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
//FileSystemResource是一個包裝類,好統一處理
param.add("file", new FileSystemResource(new File(filePath)));
...

(1)網頁上通過表單上傳檔案,預設識別符號就是"file"

(2)經過FileSystemResource包裝後,RestTemplate會利用File物件的InputStream從磁碟中讀入檔案內容,並寫入HTTP請求body中。

三、帶檔案的表單請求——檔案從客戶端而來(MultipartFile)

//file由客戶端上傳過來,直接轉發,不經過磁碟
@PostMapping("/some-url") 
public SomeResponse function(@RequestParam("file") MultipartFile file, ...) {
    ...
    MultiValueMap<String, Object> param = new LinkedMultiValueMap();
    param.add("file", new MultipartFileResource(file));
    ...
}

MultipartFileResource類似FileSystemResource

四、帶檔案的表單請求——本地沒有檔案,只有檔案的文字內容

可能存在這種情況,即你本地儲存的是文字檔案的內容,(如儲存在資料庫中,用text儲存。因為這樣比較方便管理)而另一個伺服器需要以檔案的形式接收你的文字內容。即它會用一個MultipartFile來接收。這時候首先你從資料庫中把文字內容讀出來,傳統資料庫儲存位置就在磁碟,這已經是不小的開銷了,難道你還要把文字以檔案的形式寫到磁碟再傳輸嗎?這種操作是非常愚蠢的。既然我們已經知道請求本質上傳遞的是位元組陣列,那何不就仿造FileSystemResource寫一個適配類呢?

//該類與FileSystemResouce同父類
public class TextFeignFileResource extends AbstractResource {
    //文字的位元組資訊
    private byte[] bytes;
    //當前讀到的位置
    private int index = 0;
    //檔名
    private String filename;

    //建構函式需要兩個引數,一個是檔名,隨便取
    //另一個就是文字內容,String型別足夠存文字的
    public TextFeignECLFileResource(String filename, String content) {
        this.filename = filename;
        this.bytes = content.getBytes();
    }

    @Override
    public String getDescription() {
        return null;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new InputStream() {
            //注意這裡的返回值int是一個八位的位元組的數值表示
            //並不是讀取到的位元組個數
            @Override
            public int read() throws IOException { 
                if (index >= bytes.length)
                    return -1; //返回-1是標準,表示讀取結束
                return bytes[index++];
            }
        };
    }

    @Override
    public boolean exists() {
        return true;
    }

    @Override
    public boolean isFile() {
        return true;
    }

    @Override
    public boolean isReadable() {
        return true;
    }

    @Override
    public long contentLength() throws IOException {
        return bytes.length;
    }

    @Override
    public String getFilename() {
        return filename;
    }
}

使用方式:

MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
param.add("file", new TextFeignFileResource("test.txt", "hello world"));

注意:這裡之所以能這麼做是因為普通的文字檔案沒有檔案頭等額外的描述資訊

 

相關文章