用 commons-fileupload 實現文件上傳


文件上傳系統

1. 主要需求

  • 在用戶註冊頁面,輸入用戶名,可以選擇要上傳的文件;
  • 點擊提交按鈕,可以將用戶輸入的內容和選擇的文件保存到服務器上。

2. 技術分析

a. 客戶端將文件轉爲文本

i. 要求

  • 表單提交方式必須爲 post,即 action="post"。因爲 get 方式的地址欄會有大小的限制。
  • 表單的 enctype 屬性值必須爲 multipart/form-data 多組件表單數據,即 enctype="multipart/form-data"
  • 必須在表單中提供文件上傳項,即 <input type="file" name="pic">

ii. 多組件表單數據

  • Chrome 無法查看多組件文件上傳信息:
    在這裏插入圖片描述
  • 推薦使用 FireFox 查看:
    在這裏插入圖片描述
  • 在消息頭(請求頭)中獲得黃金分割線:
    在這裏插入圖片描述
  • enctype="multipart/form-data" 的作用:將請求體通過黃金分割線分割爲單項內容:
    在這裏插入圖片描述
  • 文件上傳項中會將上傳內容轉爲文本輸出。

b. 服務器將文本轉爲字節流

i. 獲取瀏覽器上傳的數據

在這裏插入圖片描述

  • 如果直接通過 Request 對象,效率就會變得非常低,所以可以借用第三方技術來實現:

ii. 處理 IO 流的 3 種方式

  1. 使用 Apache 提供工具類 commons-fileupload。(這裏用到的方式)
  2. 使用 Servlet3.0 版本。(通過註解實現)
  3. 使用 SpringMVC 框架。(底層使用了 commons-fileupload)

3. 代碼實現

a. 導入文件上傳相關 Jar 包

在這裏插入圖片描述

相關 Jar 包已上傳至 CSDN:文件上傳相關 Jar 包

b. index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>${NAME}</title>
  <script src="${pageContext.request.contextPath}/js/jquery-3.2.1.js"></script>
</head>
<body>
<h3>文件上傳</h3>
<form action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
    用戶名:<input type="text" name="username" id="username"><br>
    上傳圖片:<input type="file" name="pic"><br>
    <input type = "submit" value="提交表單">
</form>
</body>
</html>

c. 指定服務器保存文件路徑

在這裏插入圖片描述

d. UploadServlet 接收文件並保存

i. 步驟分析

  1. 創建磁盤文件項工廠;
  2. 創建核心解析對象(依賴工廠對象);
  3. 解析 Request 對象,返回上傳項 List 集合;
  4. 遍歷 List,獲取每一個上傳項;
  5. 判斷:
    • 普通上傳項:保存 name 和 value;
    • 文件上傳項:保存文件名和文本字節輸入流到服務器端。

ii. UploadServlet

package com.company;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            // 1.創建磁盤文件項工廠
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 2.創建上傳解析器對象(依賴工廠對象)
            ServletFileUpload fileUpload = new ServletFileUpload(factory);
            // 3.解析Request請求,返回上傳項List集合
            List<FileItem> fileItems = fileUpload.parseRequest(request);
            // 4.遍歷List
            for (FileItem fileItem : fileItems) {
                // 5.判斷是文件項還是普通項
                if (fileItem.isFormField()) {// 普通上傳項
                    // 獲取name屬性名
                    String name = fileItem.getFieldName();
                    // 獲取value屬性值
                    String value = fileItem.getString();
                    System.out.println("普通上傳項:" + name + "=" + value);
                } else {// 文件上傳項
                    // a.獲取文件名 Regino.txt
                    String fileName = fileItem.getName();
                    // b.獲取文件字節輸入流
                    InputStream in = fileItem.getInputStream();
                    // c.獲取文件擴展名
                    String extName = FileUtil.extName(fileName);
                    // d.生成隨機文件名,解決服務器端保存的文件出現文件名重複問題
                    fileName = IdUtil.simpleUUID() + "." + extName; // UUID 全球唯一

                    // 此文件名會保存數據庫一份,給用戶查詢使用...

                    // 獲取upload目錄在服務器真實路徑
                    String realPath = request.getServletContext().getRealPath("/upload/");

                    // 判斷此目錄是否存在,解決IDEA沒有上傳空的upload文件夾導致找不到輸出目錄的問題
                    File dirFile = new File(realPath);
                    if (!dirFile.exists()) {
                        dirFile.mkdirs(); // 如果不存在自己創建
                    }

                    // 設置文件字節輸出流
                    FileOutputStream out = new FileOutputStream(realPath + fileName);

                    // 流的拷貝
                    IoUtil.copy(in, out);

                    // 關流
                    out.close();
                    in.close();

                    response.getWriter().write("success");
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
    }
}

e. 測試

  • 上傳文件,提交表單:
    在這裏插入圖片描述

  • 頁面顯示:
    在這裏插入圖片描述

  • 控制檯顯示:
    在這裏插入圖片描述

  • 上傳文件已保存:
    在這裏插入圖片描述

原文鏈接:https://qwert.blog.csdn.net/article/details/105781749

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章