前言
- 文件上傳下載應用場景很多吟宦。比如:我們在修改頭像的時候公黑,需要上傳頭像哆致;我們在后臺修改商品信息的時候绕德,也需要上傳商品圖片。作為Java開發(fā)者摊阀,文件上傳與文件下載功能已經(jīng)是必會的技能耻蛇。
- 這次使用SpringBoot實現(xiàn)單文件上傳,多文件上傳以及文件下載胞此,重點介紹
MultipartFile
工具類臣咖。
文件上傳到哪里合適?
我們在實現(xiàn)文件上傳功能的時候漱牵,也需要結合實際場景來決定文件的上傳位置夺蛇,一般來說有三種采納方案:
- 將文件上傳到工程目錄下:在一些文件存儲量很小的工程中,有一些上傳文件放置在工程本身的目錄下酣胀,但是隨著文件上傳的量越來越大刁赦,工程本身所在的文件夾容量會越來越大,不僅打包和部署的效率會降低闻镶,工程的啟動和運行也會變慢截型,所以一般不會采用這做法。
- 將文件上傳到工程所在服務器:將文件專門上傳到Web應用工程所在容器(如Tomcat)位于的服務器中儒溉,單獨開辟一個盤符或文件夾用于存儲上傳的圖片,這種做法讓上傳 文件與工程本身分離发钝,工程的打包和啟動效率不受到任何影響顿涣。但是如果以后出現(xiàn)了海量圖片,Web應用工程所在的服務器的效率會降低酝豪,這樣也會間接地降低應用的執(zhí)行效率涛碑,所以在上傳圖片量不大的情況下,可以采用該做法孵淘。
- 搭建文件服務器:一般大型的互聯(lián)網(wǎng)項目蒲障,都會為自己的文件上傳單獨架設一個文件服務器(有集群的應用,可能會有多臺文件服務器),也有獨立處理文件上傳揉阎、文件訪問的服務器庄撮。這種方案就是太燒錢。
上面分析了三種方案的特點和優(yōu)缺點毙籽。第一種一般不采取洞斯,第二種可能會采取,最常用的就是第三種方案坑赡。
MultipartFile工具類
- MultipartFile是SpringMVC提供簡化上傳操作的工具類烙如。
- 在不使用框架之前,都是使用原生的HttpServletRequest來接收上傳的數(shù)據(jù)毅否,文件是以二進制流傳遞到后端的亚铁,然后需要我們自己轉換為File類,非常麻煩螟加。使用了MultipartFile工具類之后徘溢,我們對文件上傳的操作就簡便許多了。
- 以下是MultipartFile工具類全部的接口方法仰迁。
方法名 | 返回值 | 作用 |
---|---|---|
getContentType() | String | 在取文件MIME類型 |
getlnputStream() | InputStream | 獲取文件流 |
getName() | String | 獲取 form 表單中文件組件的名字 |
getOriginalFilename() | String | 獲取上傳文件件的原名 |
getSize() | long | 獲取文件的大小甸昏,單位為byte |
isEmpty() | boolean | 是否為空 |
transferTo(File dest) | void | 將數(shù)據(jù)保存到一個目標文件中 |
單文件上傳
- 文件上傳的表單和普通表單有一點不同之處,就是需要添加
enctype="multipart/form-data"
這個屬性徐许,暗指該表單存在文件上傳施蜜。<!--單文件上傳--> <form action="/uploadFile" method="post" enctype="multipart/form-data"> <p>文件:<input type="file" name="file"/></p> <p><input type="submit" value="上傳"/></p> </form>
@RestController @Slf4j public class FileController { @PostMapping("upload") public String upload(MultipartFile file){ try { if (file.isEmpty()){ return "文件為空"; } //獲取文件名 String fileName = file.getOriginalFilename(); log.info("上傳的文件名:"+fileName); //獲取文件后綴名 String suffixName = fileName.substring(fileName.lastIndexOf(".")); log.info("文件后綴名:"+suffixName); //設置文件存儲路徑 String filePath = "f:/upload/"; String path = filePath+fileName; File dest = new File(path); //檢測是否存在該目錄 if (!dest.getParentFile().exists()){ dest.getParentFile().mkdirs(); } //寫入文件 file.transferTo(dest); return "上傳成功!"; } catch (IOException e) { e.printStackTrace(); } return "上傳失敗"; } }
多文件上傳
- 文件上傳的表單和普通表單有一點不同之處雌隅,就是需要添加
enctype="multipart/form-data"
這個屬性翻默,暗指該表單存在文件上傳。<!--多文件上傳--> <form action="batchUpload" method="post" enctype="multipart/form-data"> <p>文件1:<input type="file" name="file"/></p> <p>文件2:<input type="file" name="file"/></p> <p><input type="submit" value="批量上傳"/></p> </form>
@RestController @Slf4j public class FileController { /** * 多文件上傳流程 * 1.前端上傳多個文件 * 2.后臺使用請求對象(MultipartHttpServletRequest)接收整個請求流 * 3.獲取MultipartFile集合 * 4.定義緩沖字節(jié)輸出流 * 5.遍歷MultipartFile集合 * 6.獲取每一個MultipartFile對象 * 7.定義上傳路徑 * 8.判斷上傳文件是否為空(也就是沒有上傳) * 9.如果不為空恰起,則通過緩沖字節(jié)輸出流寫入到上傳路徑 */ @PostMapping("batchUpload") public String batchUpload(MultipartHttpServletRequest request){ List<MultipartFile> files = request.getFiles("file"); MultipartFile file = null; BufferedOutputStream stream = null; for (int i = 0; i < files.size(); i++) { file = files.get(i); String filePath = "f:/upload/"; if (!file.isEmpty()){ try { byte[] bytes = file.getBytes(); stream = new BufferedOutputStream(new FileOutputStream(new File(filePath+file.getOriginalFilename()))); stream.write(bytes); stream.close(); } catch (IOException e) { stream = null; return "第"+i+"個文件上傳失斝扌怠:"+e.getMessage(); } }else { return "第"+i+"個文件上傳失敗因為文件為空"; } } return "上傳成功"; } }
文件下載
- 下載文件就是程序讀取文件流,然后響應到客戶端(輸出流操作)检盼。
<!--文件下載--> <a href="download">文件下載</a>
@RestController @Slf4j public class FileController { @GetMapping("/download") public String downloadFile(HttpServletRequest request, HttpServletResponse response) { String fileName = "boss.jpg";// 文件名 if (fileName != null) { //設置文件路徑 File file = new File("f:/upload/boss.jpg"); //File file = new File(realPath , fileName); if (file.exists()) { response.setContentType("application/force-download");// 設置強制下載不打開 response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 設置文件名 byte[] buffer = new byte[1024]; FileInputStream fis = null; BufferedInputStream bis = null; try { fis = new FileInputStream(file); bis = new BufferedInputStream(fis); OutputStream os = response.getOutputStream(); int i = bis.read(buffer); while (i != -1) { os.write(buffer, 0, i); i = bis.read(buffer); } return "下載成功"; } catch (Exception e) { e.printStackTrace(); } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } } return "下載失敗"; } }