前言
在某種情況下,后台服務可能需要訪問另一台服務器的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"));
注意:這里之所以能這么做是因為普通的文本文件沒有文件頭等額外的描述信息
19-05-16補充
使用Jodd的Http API會更方便一點。