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

Struts2 多文件上傳完整實戰:JSP、Action、攔截器配置與最佳實踐

     編輯:Java 程式設計入門

核心原理:同名表單域自動綁定數組

Struts2 通過 FileUploadInterceptor 處理 multipart/form-data 請求。當多個 <input type="file" name="upload"> 共用同一 name 時,框架自動將其綁定為三個同名數組屬性:

  • File[] upload — 臨時文件對象數組
  • String[] uploadFileName — 原始文件名數組
  • String[] uploadContentType — MIME 類型數組

三個數組長度一致,索引對應同一文件。

完整代碼實現

1. JSP 頁面(upload.jsp)


<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head><title>多文件上傳演示</title></head>
<body>
<h3>選擇多張圖片上傳</h3>
<form action="upload.action" method="post" enctype="multipart/form-data">
    文件標題:<input type="text" name="title" /><br/>
    選擇文件一:<input type="file" name="upload" /><br/>
    選擇文件二:<input type="file" name="upload" /><br/>
    選擇文件三:<input type="file" name="upload" /><br/>
    <input type="submit" value="上傳" />
</form>
</body>
</html>

2. Action 類(UploadAction.java)


package com.example.action;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;

import java.io.File;
import java.io.IOException;

public class UploadAction extends ActionSupport {

    // 表單普通字段
    private String title;

    // 文件上傳三要素數組(名稱必須與 JSP name="upload" 對應)
    private File[] upload;
    private String[] uploadFileName;
    private String[] uploadContentType;

    // 保存路徑(由 struts.xml 注入)
    private String savePath;

    // Getter/Setter 省略...

    @Override
    public String execute() throws Exception {
        if (upload == null || upload.length == 0) {
            addFieldError("upload", "請至少選擇一個文件");
            return INPUT;
        }

        String realPath = ServletActionContext.getServletContext().getRealPath(savePath);
        File destDir = new File(realPath);
        if (!destDir.exists()) destDir.mkdirs();

        for (int i = 0; i < upload.length; i++) {
            File src = upload[i];
            if (src == null || src.length() == 0) continue; // 跳過空文件域

            String fileName = uploadFileName[i];
            // 安全處理:防止路徑遍歷、生成唯一文件名
            String safeName = System.currentTimeMillis() + "_" + fileName.replaceAll("[^\\w\\.-]", "_");
            File dest = new File(destDir, safeName);

            try {
                FileUtils.copyFile(src, dest); // Commons IO 高效複製
                addActionMessage("文件 " + fileName + " 上傳成功,保存為:" + safeName);
            } catch (IOException e) {
                addActionError("文件 " + fileName + " 保存失敗:" + e.getMessage());
            }
        }
        return SUCCESS;
    }
}

3. Struts 配置(struts.xml)


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "https://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
    <constant name="struts.devMode" value="true" />
    <constant name="struts.i18n.encoding" value="UTF-8" />
    <!-- 上傳大小限制:200MB -->
    <constant name="struts.multipart.maxSize" value="209715200" />

    <package name="upload" namespace="/" extends="struts-default">
        <action name="upload" class="com.example.action.UploadAction">
            <!-- 文件上傳攔截器配置 -->
            <interceptor-ref name="fileUpload">
                <param name="allowedTypes">
                    image/jpeg,image/png,image/gif,image/bmp,application/pdf
                </param>
                <param name="maximumSize">209715200</param> <!-- 200MB -->
            </interceptor-ref>
            <!-- 必須包含 defaultStack 以支持驗證、i18n 等核心功能 -->
            <interceptor-ref name="defaultStack" />

            <!-- 注入保存路徑 -->
            <param name="savePath">/uploads</param>

            <result name="success">/success.jsp</result>
            <result name="input">/upload.jsp</result>
            <result name="error">/error.jsp</result>
        </action>
    </package>
</struts>

4. 成功頁面(success.jsp)


<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
<h3>上傳結果</h3>
<p>文件標題:<s:property value="title" /></p>
<s:if test="actionMessages.size() > 0">
    <ul>
        <s:iterator value="actionMessages">
            <li><s:property /></li>
        </s:iterator>
    </ul>
</s:if>
<s:if test="actionErrors.size() > 0">
    <ul style="color:red">
        <s:iterator value="actionErrors">
            <li><s:property /></li>
        </s:iterator>
    </ul>
</s:if>
<p><a href="upload.jsp">繼續上傳</a></p>
</body>
</html>

進階配置與優化

1. 使用 List 替代數組(更靈活)


// Action 屬性改為 List
private List<File> upload = new ArrayList<>();
private List<String> uploadFileName = new ArrayList<>();
private List<String> uploadContentType = new ArrayList<>();
// Struts2 自動實例化並填充,用法與數組一致

2. 文件類型白名單最佳實踐


<param name="allowedTypes">
    image/jpeg,image/png,image/gif,image/bmp,
    application/pdf,application/msword,
    application/vnd.openxmlformats-officedocument.wordprocessingml.document
</param>

建議:同時驗證 uploadContentType 和文件擴展名,防止偽裝 MIME 類型。

3. 大文件/斷點續傳架構建議

  • 前端採用 Plupload / WebUploader / Resumable.js 進行分片上傳
  • 後端提供 /upload/chunk 接口接收分片,臨時目錄暫存
  • 合併接口 /upload/merge 按序合併分片,校驗 MD5
  • Struts2 原生不支援分片,建議獨立 Servlet 或 Spring MVC 端點處理

4. 安全加固清單

  1. 路徑遍歷防護:fileName = fileName.substring(fileName.lastIndexOf("/") + 1)
  2. 文件名去重:UUID / 時間戳 + 原名 / 雜湊值
  3. 病毒掃描:集成 ClamAV 或雲端安全 API
  4. 權限控制:上傳目錄設置不可執行權限(chmod -R -x /uploads)
  5. 臨時文件清理:配置 struts.multipart.saveDir 指定專用臨時目錄,定時清理

常見問題排查

現象原因解決
upload 為 nullform 缺少 enctype="multipart/form-data"檢查 JSP form 標籤屬性
上傳大文件報 400/500超過 struts.multipart.maxSize 或 Tomcat maxPostSize調大兩處配置,Tomcat server.xml: maxPostSize="-1"
文件名亂碼Tomcat 8+ 預設 ISO-8859-1 解析 URIserver.xml Connector 加 URIEncoding="UTF-8"
allowedTypes 不生效MIME 大小寫不匹配(如 Image/JPEG)統一轉小寫比對,或擴充白名單

總結

Struts2 多文件上傳核心在於 同名 file 域 → 三個同名數組/List 自動綁定。配合 fileUpload 攔截器的類型、大小限制,以及 defaultStack 保障的核心功能,即可構建健壯的上傳功能。生產環境務必加上安全加固、異常處理、日誌審計,大文件場景請轉向分片上傳架構。

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