1. 程式人生 > >Java Web(十一) 文件上傳與下載

Java Web(十一) 文件上傳與下載

處理 uuid 文件下載 patch 鍵值 comm 子項目 extend 信息

文件上傳

上傳的準備工作

  • 表單method必須為post
  • 提供file組件
  • 設置form標簽的enctype屬性為multipart/form-data,如果沒有設置enctype屬性,瀏覽器是無法將文件自身傳遞到服務端的(enctype默認為application/x-www-form-urlencoded)
<form action="fileupload.do" method="post" enctype="multipart/form-data">
    用戶名:<input type="text" name="username"/><br/>
    密碼:<input type="password" name="password"/><br/>
    上傳文件:<input name="file" type="file" /><br/>
    <input type="submit"/>
</form>

上傳時HTTP協議的格式

  1. enctype為application/x-www-form-urlencoded時

    從表單發送數據到服務器,數據是以鍵值對的形式存放在請求體中發送到服務器的。

    使用google瀏覽器的自動抓包(F12),可以查看表單數據在HTTP協議中的格式:

    技術分享圖片

    request.getParameter(name)是以鍵值對的形式獲取值的,所以可以通過該方法得到表單中的數據。可以得到文件名,但是得不到文件!

  2. enctype為multipart/form-data時

    在上傳時,multipart/form-data請求會把表單的數據處理為一條消息,以標簽為單元,用分隔符(boundary)分開。既可以上傳普通表單數據,也可以上傳文件。content-disposition,用來說明字段的一些信息。當上傳的字段是文件時,會有Content-Type來表明文件類型。

    使用google瀏覽器查看上傳時表單數據在HTTP協議的格式:

    技術分享圖片

    表單數據在HTTP協議中不是以鍵值對形式存在的,所以在服務器端是無法通過request.getParameter(name)獲取數據的。

    可以利用分隔符boundary和Content-type屬性自己編寫代碼實現文件上傳。

  3. 在服務器端查看從客戶端傳來的表單數據

    可以使用request.getInputStream()來獲取從客戶端傳來的數據,可以通過下面的代碼把傳來的數據輸出到控制臺:

      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            InputStream is = request.getInputStream();
            int i = is.read();
            while(i != -1) {
                char c = (char)i;
                System.out.print(c);
                i = is.read();
            }
        }

    在沒有設置enctype屬性時,傳到服務器的數據為:

    技術分享圖片

    文件上傳時,傳到服務器的數據為:

    技術分享圖片

    其中的亂碼為二進制數據,也就是要上傳的文件。

FileUpload實現文件上傳

FileUpload 是 Apache commons下面的一個子項目,用來實現Java環境下面的文件上傳功能。

使用FileUpload需要兩個jar包的支持,這裏FileUpload版本為:commons- fileupload-1.2.1,Commons IO版本為:commons-io-1.4。

服務器端代碼為:

@WebServlet(name = "FileServlet",urlPatterns = "/fileupload.do")
public class FileServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //判斷是否支持文件上傳
        boolean isMultipart  = ServletFileUpload.isMultipartContent(request);
        if(!isMultipart) {
            throw new RuntimeException("不支持文件上傳");
        }
        //創建一個磁盤工廠
        DiskFileItemFactory  factory=new DiskFileItemFactory();
        //配置緩存庫
        ServletContext servletContext = this.getServletConfig().getServletContext();
        File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
        factory.setRepository(repository);
        //解析數據
        ServletFileUpload fileUpload=new ServletFileUpload(factory);
        List<FileItem> items = null;
        try {
            items=fileUpload.parseRequest(request);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }

        for(FileItem item : items) {
            if (item.isFormField()) {
                String name = item.getFieldName();
                String value = item.getString();
                System.out.println(name + " " + value);
            } else {
                //取文件名
                String fileName = item.getName();
                fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
                //取文件拓展名
                String exten = fileName.substring(fileName.lastIndexOf("."));
                //新文件名,防止文件重名
                String newFileName = UUID.randomUUID().toString().replace("-", "") + exten;
                //把文件寫入到upload文件夾下
                String path = this.getServletConfig().getServletContext().getRealPath("/");
                String directPath = path + "upload\\" + newFileName;
                File file = new File(directPath);
                OutputStream os = new FileOutputStream(file);
                InputStream is = item.getInputStream();
                byte[] b = new byte[1024];
                int len = 0;
                while ((len = is.read(b)) != -1) {
                    os.write(b, 0, len);
                }
                os.close();
                is.close();
            }
        }
        request.getRequestDispatcher("ok.jsp").forward(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

文件下載

@WebServlet(name = "DownloadServlet", urlPatterns = "/download.do")
public class DownloadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 獲得要下載的文件的名稱
        String filename = request.getParameter("filename");
        // 告訴客戶端該文件不是直接解析,而是以附件形式打開(下載)
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
        // 獲取文件的絕對路徑
        String path = this.getServletContext().getRealPath("download/" + filename);
        // 獲得該文件的輸入流
        InputStream in = new FileInputStream(path);
        // 獲得輸出流--通過response獲得的輸出流 用於向客戶端寫內容
        ServletOutputStream out = response.getOutputStream();
        // 文件拷貝代碼
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len = in.read(buffer)) != -1) {
            out.write(buffer, 0, len);
        }
        in.close();
        out.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

Java Web(十一) 文件上傳與下載