本文提供一套完整的「前端動態添加/刪除文件輸入框 + 後端多文件接收 + 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>
核心邏輯:遍歷 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);
}
}
}
| 方案 | 優點 | 缺點 | 推薦場景 |
|---|---|---|---|
| UUID (本文採用) | 極低衝突概率、無序、無業務含義、跨系統唯一 | 文件名不可讀、長度較長(32字符) | 通用文件存儲、高併發 |
| 時間戳+隨機數 | 可讀性較好、排序友好 | 高併發極小概率衝突、需同步鎖 | 低併發、需保留時間信息 |
| 原名+MD5/Hash | 去重、可驗證內容一致性 | 計算開銷大、同名不同內容仍衝突 | 網盤去重、靜態資源緩存 |
FF D8 FF 為 JPEG)。upload.setSizeMax(10 * 1024 * 1024) (10MB) + factory.setSizeThreshold。noexec,Web 服務器禁用該目錄腳本解析。^[a-f0-9]{32}\.(jpg|png|gif)$ 校驗生成名。單文件超大(>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 輕量實現動態列表**。生產環境務必補全安全校驗、存儲隔離、異常監控等環節,並根據業務量級評估是否引入分片上傳或對象存儲服務。