1. 程式人生 > 實用技巧 >技術點12:檔案的上傳和下載

技術點12:檔案的上傳和下載

檔案的上傳和下載

一、檔案的上傳介紹(*****重點

步驟:

  1、要有一個 form 標籤,method=post 請求   2、form 標籤的 encType 屬性值必須為 multipart/form-data 值   3、在 form 標籤中使用 input type=file 新增上傳的檔案   4、編寫伺服器程式碼(Servlet 程式)接收,處理上傳的資料。   注:encType=multipart/form-data 表示提交的資料,以多段(每一個表單項一個數據段)的形式進行拼接,然後以二進位制流的形式傳送給伺服器 編寫form.jsp頁面:

使用UploadServlet程式接收上傳的資料:

瀏覽器訪問:

控制檯接收到的資料:

1.1、檔案上傳,HTTP 協議的說明

1.2、commons-fileupload.jar 常用 API 介紹說明

  針對於上傳過來的資料,我們要解析獲取資料內容。Apache為我們提供了這樣的jar包,專門用來處理這些上傳的資料。

  commons-fileupload.jar 需要依賴 commons-io.jar 這個包,所以兩個包我們都要引入。

  commons-fileupload.jar 和 commons-io.jar 包中,我們常用的類有哪些?

示例:

public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1 先判斷上傳的資料是否多段資料(只有是多段的資料,才是檔案上傳的)
        if (ServletFileUpload.isMultipartContent(req)){
            //建立FileItemFactory工廠實現類
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
            //建立用於解析上傳資料的工具類ServletFileUpload類
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
            try {
                //解析上傳的資料,得到每一個表單項FileItem構成的集合
                List<FileItem> list = servletFileUpload.parseRequest(req);
                // 迴圈判斷,每一個表單項,是普通型別,還是上傳的檔案
                for (FileItem fileItem : list){
                    if (fileItem.isFormField()){
                        //普通表單項
                        System.out.println("表單項對的name屬性值:" + fileItem.getFieldName());
                        System.out.println("表單項的value屬性值:" + fileItem.getString("UTF-8"));
                    }else{
                        //上傳檔案表單項
                        System.out.println("表單項的name屬性值:" + fileItem.getFieldName());
                        System.out.println("上傳的檔名:" + fileItem.getName());
                        //將檔案寫入磁碟的某個位置
                        fileItem.write(new File("c:\\" + fileItem.getName()));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

效果:

二、檔案下載

2.1、準備下載的資源

2.2、建立Download.java這個Servlet程式用於下載

package com.zixue.web;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * @author Mr Guo * @create 2020-11-13 12:54 */ public class Download extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.獲取要下載的檔名 String downloadFileName = "1.jpg"; //2.讀取要下載的檔案內容(通過ServletContext物件可以獲取) ServletContext servletContext = getServletContext(); //獲取要下載的檔案型別 String mimeType = servletContext.getMimeType("/file/" + downloadFileName); System.out.println("下載的檔案型別:" + mimeType); //4.在回傳前,通過響應頭告訴客戶端返回的資料型別 resp.setContentType(mimeType); //5.還要告訴客戶端收到的資料是用於下載使用(還是使用響應頭) // Content-Disposition 響應頭,表示收到的資料怎麼處理 // attachment 表示附件,表示下載使用 // filename= 表示指定下載的檔名 resp.setHeader("Content-Disposition", "attachment; filename=" + downloadFileName); /** * / 被伺服器解析表示的地址為:http://ip:port/工程名/ 對映到程式碼的web目錄 */ InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFileName); //獲取響應的輸出流 OutputStream outputStream = resp.getOutputStream(); //3.把下載的檔案內容回傳給客戶端 //讀取輸入流中全部的資料,複製給輸出流,輸出給客戶端 IOUtils.copy(resourceAsStream,outputStream); } }

2.3、中文名亂碼問題解決方案

方案一:URLEncoder 解決 IE 和谷歌瀏覽器的附件中文名問題

  如果客戶端瀏覽器是 IE 瀏覽器 或者 是谷歌瀏覽器。我們需要使用 URLEncoder 類先對中文名進行 UTF-8 的編碼操作。   因為 IE 瀏覽器和谷歌瀏覽器收到含有編碼後的字串後會以 UTF-8 字符集進行解碼顯示。
resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中國.jpg", "UTF-8"));

方案二:BASE64 編解碼 解決 火狐瀏覽器的附件中文名問題

BASE64 編解碼操作如下:

效果如下:

如果客戶端瀏覽器是火狐瀏覽器。 那麼我們需要對中文名進行 BASE64 的編碼操作。

因為火狐使用的是 BASE64 的編解碼方式還原響應中的漢字。所以需要使用 BASE64Encoder 類進行編碼操作。

  綜上,我們如何解決不同瀏覽器的相容性問題呢?對於火狐瀏覽器,使用BASE64進行編碼,其它,則使用URLEncoder進行編碼。怎麼區分不同的瀏覽器呢?在請求頭中,有一個User-Agent請求頭,判斷是否包含Firefox進行區分。最終效果如下:

package com.zixue.web;

import org.apache.commons.io.IOUtils;
import sun.misc.BASE64Encoder;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

/**
 * @author Mr Guo
 * @create 2020-11-13 12:54
 */
public class Download extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.獲取要下載的檔名
        String downloadFileName = "1.jpg";
        //2.讀取要下載的檔案內容(通過ServletContext物件可以獲取)
        ServletContext servletContext = getServletContext();
        //獲取要下載的檔案型別
        String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
        System.out.println("下載的檔案型別:" + mimeType);
        //4.在回傳前,通過響應頭告訴客戶端返回的資料型別
        resp.setContentType(mimeType);
        //5.還要告訴客戶端收到的資料是用於下載使用(還是使用響應頭)
        // Content-Disposition 響應頭,表示收到的資料怎麼處理
        // attachment 表示附件,表示下載使用
        // filename= 表示指定下載的檔名
        if (req.getHeader("User-Agent").contains("Firefox")){
            resp.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?"+ new BASE64Encoder().encode("中國.jpg".getBytes("UTF-8")) +"?=");
        }else{
            resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中國.jpg", "UTF-8"));
        }

        /**
         * / 被伺服器解析表示的地址為:http://ip:port/工程名/  對映到程式碼的web目錄
         */
        InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFileName);
        //獲取響應的輸出流
        OutputStream outputStream = resp.getOutputStream();
        //3.把下載的檔案內容回傳給客戶端
        //讀取輸入流中全部的資料,複製給輸出流,輸出給客戶端
        IOUtils.copy(resourceAsStream,outputStream);
    }
}