首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現多文件上傳與重名衝突解決方案

     編輯:Java 相關知識

概述

本文提供一套完整的「前端動態添加/刪除文件輸入框 + 後端多文件接收 + UUID 重命名防衝突」的實現方案。技術棧:JSP + JavaScript + Servlet + Apache Commons FileUpload/IO。

一、前端頁面:動態文件列表

通過 JavaScript 操作 DOM,實現「添加一行」、「刪除當前行」、「提交前驗證」。

<form name="uploadForm" action="Up3Servlet" method="post" enctype="multipart/form-data">
    <table id="fileTable" border="1">
        <tr>
            <td>文件:</td>
            <td>
                <input type="file" name="file">
                <button type="button" onclick="deleteRow(this)">刪除</button>
            </td>
        </tr>
    </table>
    <br/>
    <input type="button" value="上傳" onclick="submitForm()">
    <input type="button" value="添加" onclick="addRow()">
</form>

<script>
function addRow() {
    var table = document.getElementById("fileTable");
    var row = table.insertRow();
    var cell1 = row.insertCell();
    cell1.innerHTML = "文件:";
    var cell2 = row.insertCell();
    cell2.innerHTML = '<input type="file" name="file"><button type="button" onclick="deleteRow(this)">刪除</button>';
}

function deleteRow(btn) {
    var row = btn.parentNode.parentNode;
    document.getElementById("fileTable").deleteRow(row.rowIndex);
}

function submitForm() {
    var files = document.getElementsByName("file");
    if (files.length === 0) { alert("無文件可上傳"); return; }
    for (var i = 0; i < files.length; i++) {
        if (files[i].value === "") { alert("第 " + (i+1) + " 個文件不能為空"); return; }
    }
    document.forms['uploadForm'].submit();
}
</script>

二、後端 Servlet:多文件接收與 UUID 重命名

核心邏輯:遍歷 FileItem 列表 -> 過濾圖片類型 -> 截取擴展名 -> 生成 UUID 新文件名 -> 保存 -> 記錄新名轉發頁面展示。

package cn.example.servlet;

import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.util.UUID;

public class UpImgServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        // 1. 獲取項目真實部署路徑下的 up 目錄
        String saveDir = getServletContext().getRealPath("/up");
        // 2. 配置工廠:10KB 內存閾值,臨時目錄 d:/a
        DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 10, new File("d:/a"));
        ServletFileUpload upload = new ServletFileUpload(factory);

        try {
            List<FileItem> items = upload.parseRequest(req);
            List<String> savedNames = new ArrayList<>();

            for (FileItem item : items) {
                // 僅處理圖片類型
                String contentType = item.getContentType();
                if (contentType != null && contentType.startsWith("image/")) {
                    String originalName = item.getName();
                    // 兼容不同瀏覽器路徑格式,取純文件名
                    originalName = originalName.substring(originalName.lastIndexOf("\\") + 1);
                    String ext = originalName.substring(originalName.lastIndexOf(".")); // 含點,如 .jpg

                    // 生成無連字符 UUID 作為新文件名
                    String uuid = UUID.randomUUID().toString().replace("-", "");
                    String newName = uuid + ext;

                    // 保存文件
                    FileUtils.copyInputStreamToFile(item.getInputStream(), new File(saveDir, newName));
                    savedNames.add(newName);
                }
                // 釋放臨時文件資源
                item.delete();
            }

            req.setAttribute("uploadedImages", savedNames);
            req.getRequestDispatcher("/jsps/showImages.jsp").forward(req, resp);
        } catch (Exception e) {
            throw new ServletException("上傳處理失敗", e);
        }
    }
}

三、關鍵技術點深度解析

1. 文件名衝突解決:UUID vs 時間戳 vs 原名+隨機數

方案優點缺點推薦場景
UUID (本文採用)極低衝突概率、無序、無業務含義、跨系統唯一文件名不可讀、長度較長(32字符)通用文件存儲、高併發
時間戳+隨機數可讀性較好、排序友好高併發極小概率衝突、需同步鎖低併發、需保留時間信息
原名+MD5/Hash去重、可驗證內容一致性計算開銷大、同名不同內容仍衝突網盤去重、靜態資源緩存

2. 安全性加固建議(生產必須)

  • 文件類型雙重校驗:前端 accept 屬性 + 後端 MIME 類型 + 文件頭魔數檢測(如 FF D8 FF 為 JPEG)。
  • 大小限制:upload.setSizeMax(10 * 1024 * 1024) (10MB) + factory.setSizeThreshold。
  • 存儲目錄隔離:上傳目錄**不可**在 Web 應用根目錄下,防止腳本直接訪問執行。建議存放在應用服務器外部路徑或對象存儲 (OSS/S3)。
  • 執行權限移除:存儲分區掛載 noexec,Web 服務器禁用該目錄腳本解析。
  • 文件名過濾:嚴格正則 ^[a-f0-9]{32}\.(jpg|png|gif)$ 校驗生成名。

3. 大文件/斷點續傳擴展

單文件超大(>100MB)或需斷點續傳時,需引入 分片上傳 方案:前端切片 -> 後端合併 -> 數據庫記錄分片狀態。推薦成熟庫:Plupload、WebUploader、Uppy 或 Spring Boot 整合 Resumable.js。

四、結果展示頁面

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>
<html>
<body>
    <h3>上傳成功,共 ${fn:length(uploadedImages)} 張圖片</h3>
    <c:forEach items="${uploadedImages}" var="img">
        <div style="display:inline-block; margin:10px; text-align:center;">
            <img src="${pageContext.request.contextPath}/up/${img}" width="150" height="150" /><br/>
            <small>${img}</small>
        </div>
    </c:forEach>
</body>
</html>

五、總結

本方案實現了從前端動態交互到後端安全存儲的完整閉環。核心亮點在於 **UUID 重命名徹底解決重名**、**Commons FileUpload 靈活處理多部件請求**、**前端原生 JS 輕量實現動態列表**。生產環境務必補全安全校驗、存儲隔離、異常監控等環節,並根據業務量級評估是否引入分片上傳或對象存儲服務。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved