Servlet文件的上傳與下載詳解
文件的上傳和下載
1. 文件上傳細節(jié)
要有一個 form 標簽,method-post請求 (因為get有長度限制)
form標簽的屬性 encType
值必須為 multipart/form-data
表示提交的數(shù)據(jù)以多端(每一個表單項一個數(shù)據(jù)段)的形式進行拼接,然后以二進制流的形式發(fā)送給服務器
在 form 標簽中使用 input type="file"
添加上傳的文件
編寫服務器代碼 (Servlet接收),接受處理上傳的數(shù)據(jù)
文件上傳http請求信息:
請求頭:Content-Type: multipart/form-data; boundary=------WebKitFormBoundaryCd3g75eOt35olUs7
解析:
Content-Type
表示提交的數(shù)據(jù)類型multipart/form-data
表示以流的形式分段提交服務器boundary
表示每段數(shù)據(jù)的分隔符,值:----WebKitFormBoundarylXiF4fEzpo9c8L4p
是瀏覽器每次隨機生成的,它就是每段數(shù)據(jù)的分界符。在每段里面 第一行是對表單項的描述,然后有個空行,下面是提交的值。
請求體:
------WebKitFormBoundaryCd3g75eOt35olUs7
Content-Disposition: form-data; name="username"zhu
------WebKitFormBoundaryCd3g75eOt35olUs7
Content-Disposition: form-data; name="photo"; filename="head.jpg"
Content-Type: image/jpeg文件的信息(很長這里省略了)
------WebKitFormBoundaryCd3g75eOt35olUs7--
因為客戶端是以按流的方式提交是,所以我們要按流的方式獲取,不能這樣: req.getParameter("username");
正確用法:
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("上傳成功"); ServletInputStream inputStream = req.getInputStream(); // 先得到 字節(jié)輸入流 byte[] buffer = new byte[1024]; // 緩沖區(qū) int readCount = 0; while ((readCount = inputStream.read(buffer)) != -1) { // 打印出來的就是上面全部的請求體 System.out.println(new String(buffer, 0, readCount)); } }
2. 文件上傳
這種文件上傳(常用)有很多第三方提供好的API我們使用進行了,可以幫我們對收到的數(shù)據(jù)進行解析。
例如:commons-fileupload-1.2.1.jar
(依賴于 commons-io-1.4.jar
)
- 導入兩個jar包
- 解析
關(guān)鍵的類:
ServletFileUpload
類:用于解析上傳的數(shù)據(jù)FileItem
類:每一個表單項
//ServletFileUpload中的方法 // 判斷當前上傳的數(shù)據(jù)是否是多端的格式,不是解析不了 public boolean ServletFileUpload.isMultipartContent(HttpServletRequest req) // 解析上傳的數(shù)據(jù),F(xiàn)ileItem表示每一個表單項 public List<FileItem> parseRequest(HttpServletRequest req) //FileItem中方法 // 判斷當前這個表單項是普通的表單項還是文件上傳的類型,true表示普通的 public boolean isFormField() // 獲取表單項name屬性值 public String getFieldName() // 獲取當前表單項的值 public String getString() // 可傳入字符集,防止亂碼,一開始req.setCharacterEncoding("UTF-8");也行 // 獲取上傳的文件名 public String getName() // 將上傳的文件寫道 參數(shù)file所指向的磁盤位置 public void write(File file)
Servlet上傳文件示例:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); // 防止亂碼 resp.setContentType("text/html; charset=utf-8"); String savePath = getServletContext().getRealPath("/WEB-INF/uploadFile"); //保存的路徑 // 首先判斷上傳的數(shù)據(jù)是否是多段的數(shù)據(jù) if (ServletFileUpload.isMultipartContent(req)) { FileItemFactory fileItemFactory = new DiskFileItemFactory(); // 創(chuàng)建FileItemFactory工廠的實現(xiàn)類, // 創(chuàng)建用于解析上傳數(shù)據(jù)的工具類 ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory); try { List<FileItem> list = servletFileUpload.parseRequest(req); // 解析,得到每一個表單項 for (FileItem fileItem : list) { if (fileItem.isFormField()) { // 普通表單項 System.out.print("表單項的name屬性值:" + fileItem.getFieldName()); System.out.println(" 表單項的value:" + fileItem.getString("UTF-8")); } else { // 文件類型 System.out.print("文件的name屬性值:" + fileItem.getFieldName()); System.out.println(" 上傳的文件名:" + fileItem.getName()); // 一般會保存到用戶訪問不能直接訪問的目錄下 File.separator是系統(tǒng)默認路徑分隔符,win下是 / // (下面這是保存到了部署的真是目錄下,保存到了服務器中) // 可以用UUID保證文件名的唯一性,防止文件覆蓋。 // 防止單個目錄文件過多影響讀寫速度,還可以使用目錄生成算法分散儲存 fileItem.write(new File(savePath + File.separator + fileItem.getName())); //fileItem.delete(); //關(guān)閉資源 } } } catch (Exception e) { e.printStackTrace(); } } }
3. 文件下載
客戶端 ->(發(fā)送請求告訴服務器我要下載什么文件) -> 服務器
服務器干的內(nèi)容:
- 獲取要下載的文件名
- 讀取要下載的文件內(nèi)容
- 通過響應頭告訴客戶端返回的數(shù)據(jù)類型是什么 (和要下載的類型一致)
- 告訴的客戶端收到的數(shù)據(jù)是用于下載使用(還是用響應頭設(shè)置)
- 把下載的的文件內(nèi)容回傳給客戶端下載
這個也能用 commons-io-1.4.jar
的IOUtils 類:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); // 防止亂碼 resp.setCharacterEncoding("UTF-8"); //1.獲取要下載的文件名路徑名,并通過ServletContext讀取讀取文件 String downloadFileName = "head.jpg"; // 我們這里寫死了 ServletContext servletContext = getServletContext(); String savePath = servletContext.getRealPath("/WEB-INF/upload"); //以前上傳文件保存的目錄 String downloadPath = savePath + File.separator + downloadFileName; //2.告訴客戶端返回的類型 String downloadType = servletContext.getMimeType(downloadPath); //獲取要下載文件的類型 (這個是image/jpeg) resp.setContentType(downloadType); // (和要下載的類型一樣) //3.告訴客戶端收到的數(shù)據(jù)是用于下載的,不是直接顯示在頁面的 // Content-Disposition表示收到的數(shù)據(jù)怎么處理,attachment表示附件下載使用,filename表示下載文件的名字 // filename名可以不和本地的名字一樣,當有中文時會亂碼,因為http協(xié)議設(shè)置的的時候不支持中文,需要進行url編碼 /resp.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName); resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downloadFileName, "UTF-8")); InputStream resourceAsStream = servletContext.getResourceAsStream(downloadPath); // getResourceAsStream() 傳入文件路徑,讀取文件!!!!!!!!!!!!! // 4.commons-io-1.4.jar中有IOUtils我們可以直接用,不用自己read() write()了 ServletOutputStream outputStream = resp.getOutputStream(); // 獲取響應的輸出流 IOUtils.copy(resourceAsStream, outputStream); // 讀取輸入流的信息復制給輸出流,輸出給客戶端,傳入一個輸入流和輸出流 (字節(jié)字符流都行) }
到此這篇關(guān)于Servlet文件的上傳與下載詳解的文章就介紹到這了,更多相關(guān)Servlet上傳下載文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解hibernate雙向多對多關(guān)聯(lián)映射XML與注解版
本篇文章主要介紹了詳解hibernate雙向多對多關(guān)聯(lián)映射XML與注解版,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05解決spring中redistemplate不能用通配符keys查出相應Key的問題
這篇文章主要介紹了解決spring中redistemplate不能用通配符keys查出相應Key的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11自從在 IDEA 中用了熱部署神器 JRebel 之后,開發(fā)效率提升了 10(真棒)
在javaweb開發(fā)過程中,使用熱部署神器 JRebel可以使class類還是更新spring配置文件都能立馬見到效率,本文給大家介紹JRebel的兩種安裝方法,小編建議使用第二種方法,具體安裝步驟跟隨小編一起看看吧2021-06-06Java replaceAll()方法報錯Illegal group reference的解決辦法
這篇文章主要給大家介紹了關(guān)于Java replaceAll()方法報錯Illegal group reference的解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09java:程序包org.springframework.boot不存在的完美解決方法
最近項目中運行的時候提示了"java: 程序包org.springframework.boot不存在",下面這篇文章主要給大家介紹了關(guān)于java:程序包org.springframework.boot不存在的完美解決方法,需要的朋友可以參考下2023-05-05