前因後果(不想看的可以直接看分界線之間的內容):
做一個項目, 前端類似這種按鈕:
Html代碼:
<form action="http://172.22.25.235:8004/storage/uploadFile/" method="post" enctype="multipart/form-data">
<p> 選擇文件: <input type="file" name="file"/></p>
<p><input type="submit" value="提交"/></p>
</form>
即,將你選中的文件 發送到指定 網址。 這個文件是可以直接就上傳成功的。
但我的任務 就要我來插一腳:
因爲我要得到這個文件的 名稱、日期 、啥啥啥的各種屬性,所以 上傳的時候 需要先到後端讓我 記錄各種數據,(也就是說將這個文件的這種屬性記錄並保存到數據庫中以後好根據這些數據 再下載這個文件)
,再上傳,這一腳 插得 我真的學到好多東西。
所以 ,這個按鈕HTML 就變成了 即 接口變成了 localhost://xxxx/fileupload 這個“中間商”了
<form action="fileUpload" method="post" enctype="multipart/form-data">
<p> 選擇文件: <input type="file" name="fileName"/></p>
<p><input type="submit" value="提交"/></p>
</form>
然後 後端 再將文件 發送到 開始那個網址的 接口 http://172.22.25.235:8004/storage/uploadFile/+fileName
正文: 直接上代碼
@RequestMapping("fileUpload")
@ResponseBody
//還要加個返回 responseBody
//因爲multipartfile 不能得到他的路徑,所以需要生成臨時文件再 轉換 Object類型 再上傳
public String fileUpload(@RequestParam("fileName") MultipartFile file) throws IOException {
if (file.isEmpty()) {
return "false";
}
String fileName = file.getOriginalFilename();//name
String tempFilePath = System.getProperty("java.io.tmpdir") + file.getOriginalFilename();
File tempFile = new File(tempFilePath);
file.transferTo(tempFile);//生成臨時文件
// 獲取文件屬性(還要額外形參這裏就不給出了) 一系列的存表 操作
String url = "http://172.22.25.235:8004/storage/uploadFile/";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("Accept",MediaType.APPLICATION_JSON.toString());
headers.setContentType(MediaType.parseMediaType("multipart/form-data;charset=UTF-8"));
MultiValueMap<String,Object> param = new LinkedMultiValueMap<>();
//MultipartFile 直接轉 fileSystemResource 是不行的
FileSystemResource resource = new FileSystemResource(tempFilePath);//把臨時文件變成filesystemresource
param.add("file",resource);
HttpEntity<MultiValueMap<String,Object>> formEntity = new HttpEntity<>(param,headers);
ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url,formEntity, JSONObject.class);
JSONObject jsonObject =responseEntity.getBody();
System.out.println(jsonObject.get("data"));
// ResponseEntity<String> responseEntity = restTemplate.postForEntity(url,formEntity, String.class);
// String body = responseEntity.getBody();
tempFile.delete();//刪除臨時文件文件
return jsonObject.toString();
}
坑點:
1: MultipartFile 是 前端 <input type="file" ....> 按鈕發送的固定類型, 所以後端 接收時 只能用這個類型接收,
但是 用 restTemplate 發送 post 請求時,需要用Map 來封裝 請求體(http基礎不好,我這麼叫它) 如上面的 formEntity ,並且請求體裏面的 “file” 屬性 要是 FileSystemResource 類型的 ,而不能是 MultipartFile 類型,這就涉及到第二個坑點
2:MultipartFile 直接轉化爲 FileSystemResource 類型 是行不通的,因爲 FileSystemResource 需要根據文件路勁 來構造,
但multipartFile 對象 沒有路徑屬性,(也就是說從前端選擇文件後,點擊發送按鈕之後,這個文件就只有內容了,沒有了他的地址了) 那怎麼辦? 這個時候就是知識點了—— java 是有臨時文件路徑的 (windows 一般是在c/user/xxx/AppData/temp 裏面 linux 是/tmp 文件夾) 獲取方法:System.getProperty("java.io.tmpdir") 返回的是臨時目錄的路徑
可能聰明的童靴已經想到了,我們可以在這個臨時目錄裏生成一個臨時文件 ,內容就是 那個MultipartFile 的內容的複製,然後這個臨時文件的路徑是知道的,那麼 multipartfile 也就得到了,restTemplate.postForEntity 就能發送成功了
最後 postForEntity 函數的第二個參數 的設置也要 添加一些編碼啥的設置 纔行,如上面的 FormEntity 的設置,如果不設置的話很可能不成功,我看別的博客直接 String string = rest.postForObject(url, param, String.class); 這樣不是整個請求體,缺少必要的編碼設置之類的應該成功不了的
哦,對了,我上面 是想直接得到 json 類型的返回值,好取出其中的“data”屬性,其實ResponseEntity<xxx>可以設置你想要的返回類型的 如 可以填 String 多餘不說了,一切都在代碼中……
最後附上結果 點擊發送按鈕並返回:
後臺:
到時候就利用這串 東西 去下載 對應文件