上傳文件:
前端:
- 整個過程,就是在使用FormData 添加 上File(這個Blob),并且key要和后臺的名字對應上
- 在點擊上傳按鈕開始上傳之前,使用了URL.createObjectURL(File)創建blobUrl,給了img標簽作圖片預覽
- 上傳完畢后,將input file的value置為空。若將input file置為空,則此時不能再從input file中獲取file了,得等下次再選擇圖片才能獲得file,將它置為空的目的是為了下次選擇同樣的圖片,也能觸發input file的change事件
后端:
- 后臺僅僅就是用MultipartFile聲明接收即可,可以使用@RequestParam注解 或 @RequestPart注解
- 調用MultipartFile#transferTo保存文件
- 可以從MultipartFile#getInputStream中獲取流,比如上傳到OSS。
?前端代碼:
<template><div>選擇文件: <input type="file" ref="fileInputRef" @change="selectFile" multiple> <!-- 使用multiple屬性,可選擇多個文件 --><br/><img v-if="imgUrl" :src="imgUrl" alt="" style="width:54px;height:54px;"><el-button v-if="imgUrl" type="primary" @click="uploadFile">上傳</el-button><hr/></div>
</template><script>
import axiosInstance from '@/utils/request.js'
import axios from 'axios'
export default {name: 'File',data() {return {imgUrl:''}},methods: {selectFile() {let file = this.$refs['fileInputRef'].files[0]console.log(file)// 上傳前, 可以預覽該圖片let blobUrl = URL.createObjectURL(file)this.imgUrl = blobUrl},uploadFile() {// 因為可能選擇多個文件, 所以這里是個數組let file = this.$refs['fileInputRef'].files[0]let formData = new FormData()formData.append('mfile', file) // 必須和后端的參數名相同。(我們看到了, 其實就是把blob文件給了formData的一個key)formData.append("type", 'avatar')// 可以有下面2種方式, 來上傳文件/* axiosInstance.post('http://127.0.0.1:8083/file/uploadFile',formData, {headers: {'a':'b'}}).then(res => {console.log('響應回來: ',res);}) */axiosInstance({ // 這種傳參方式, 在axios的index.d.ts中可以看到url:'http://127.0.0.1:8083/file/uploadFile',method:'post',data: formData, // 直接將FormData作為data傳輸headers: {'a':'b' // 可攜帶自定義響應頭}}).then(res => {console.log('響應回來: ',res);})console.log(this.$refs['fileInputRef'].value); // C:\fakepath\cfa86972-07a1-4527-8b8a-1991715ebbfe.png// 上傳完文件后, 將value置為空, 以避免下次選擇同樣的圖片而不會觸發input file的change事件。// (注意清空value后,將不能再從input file中獲取file,而原先的file仍然能夠使用)this.$refs['fileInputRef'].value = ''}}
}
</script><style></style>
后端代碼:
@PostMapping("uploadFile")
public Object uploadFile(@RequestPart("mfile")MultipartFile multipartFile,@RequestPart("type") String type) throws IOException {System.out.println(multipartFile.getClass());System.out.println(type);// 源文件名String originalFilename = multipartFile.getOriginalFilename();// 內容類型String contentType = multipartFile.getContentType();// 文件是否為空(無內容)boolean empty = multipartFile.isEmpty();// 文件大小long size = multipartFile.getSize();// 文件的字節數據byte[] bytes = multipartFile.getBytes();// 獲取文件的字節輸入流InputStream inputStream = multipartFile.getInputStream();// 將文件保存到指定路徑下multipartFile.transferTo(new File("d:/Projects/practice/test-springboot/src/main/resources/file/" + originalFilename));System.out.println(originalFilename);System.out.println(contentType);System.out.println(empty);System.out.println(size);System.out.println(bytes.length);HashMap<String, Object> data = new HashMap<>();data.put("data", "ok");return data;
}
動態a標簽下載
前端代碼
- 只需要動態創建a標簽,添加到body,然后手動調用js觸發a標簽的click事件,觸發下載
- 下載完成之后,將a標簽移除
- 整個過程a標簽的樣式都是display:none
<template><div><el-button type="success" @click="downloadFile">下載文件</el-button></div>
</template><script>
import axiosInstance from '@/utils/request.js'
import axios from 'axios'
export default {name: 'File',data() {return {}},methods: {downloadFile() {let a = document.createElement('a')a.href = 'http://127.0.0.1:8083/file/downloadFile?filename=頭像a.png'document.body.appendChild(a)a.style.display = 'none'a.click()document.body.removeChild(a)}}
}
</script><style></style>
后端代碼:
@GetMapping("downloadFile")
public void downloadFile(@RequestParam("filename") String filename) throws Exception {// 告知瀏覽器這是一個字節流,瀏覽器處理字節流的默認方式就是下載// 意思是未知的應用程序文件,瀏覽器一般不會自動執行或詢問執行。瀏覽器會像對待,// 設置了HTTP頭Content-Disposition值為attachment的文件一樣來對待這類文件,即瀏覽器會觸發下載行為response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);// ,該響應頭指示回復的內容該以何種形式展示,是以內聯的形式(即網頁或者網頁的一部分),還是以附件的形式下載并保存到本地。response.setHeader(HttpHeaders.CONTENT_DISPOSITION,"attachment;fileName="+ URLEncoder.encode(filename, "UTF-8"));File file = new File("d:/Projects/practice/test-springboot/src/main/resources/file/" + filename);ServletOutputStream ros = response.getOutputStream();FileInputStream fis = new FileInputStream(file);byte[] bytes = new byte[2 * 1024];int len = 0;while ((len = fis.read(bytes)) != -1) {ros.write(bytes, 0, len);}ros.flush();ros.close();fis.close()}
預覽文件:
前端代碼:
<template><div><a href="http://127.0.0.1:8083/file/previewFile?filename=頭像a.png">頭像a.png</a></div>
</template><script>
import axios from 'axios'
export default {name: 'File',data() {return {}},methods: {}
}
</script><style></style>
后端代碼:
@GetMapping("previewFile")public void previewFile(@RequestParam("filename") String filename) throws Exception {// 可使用ServletContext 通過文件名獲取 媒體資源類型response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE);File file = new File("d:/Projects/practice/test-springboot/src/main/resources/file/" + filename);ServletOutputStream ros = response.getOutputStream();// 可參考: StreamUtilsFileInputStream fis = new FileInputStream(file);byte[] bytes = new byte[4 * 1024];int len = 0;while ((len = fis.read(bytes)) != -1) {ros.write(bytes, 0, len);}ros.flush();ros.close();fis.close()
}