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

Struts 1 多文件上傳實戰:FormFile 數組、大小限制與編碼處理完整指南

     編輯:Java 相關知識

Struts 1 文件上傳核心機制

Struts 1 通過 org.apache.struts.upload.FormFile 封裝上傳文件,配合 MultipartRequestHandler 解析 multipart/form-data 請求。關鍵點:

  • ActionForm 中聲明 FormFile 屬性 (單個或數組)
  • JSP 使用 <html:file> 標籤,form 必須 enctype="multipart/form-data"
  • struts-config.xml 配置 controller 最大文件大小

完整實現方案

1. ActionForm:支持多文件屬性

package com.example.struts.form;

import org.apache.struts.action.ActionForm;
import org.apache.struts.upload.FormFile;

public class UploadForm extends ActionForm {
    // 單文件屬性
    private FormFile theFile;
    
    // 多文件:聲明多個屬性 (Struts 1 不直接支持 FormFile[])
    private FormFile theFile2;
    private FormFile theFile3;
    // 可擴展更多...
    
    // Getter/Setter
    public FormFile getTheFile() { return theFile; }
    public void setTheFile(FormFile theFile) { this.theFile = theFile; }
    
    public FormFile getTheFile2() { return theFile2; }
    public void setTheFile2(FormFile theFile2) { this.theFile2 = theFile2; }
    
    public FormFile getTheFile3() { return theFile3; }
    public void setTheFile3(FormFile theFile3) { this.theFile3 = theFile3; }
    
    // 校驗:文件大小超限檢查
    @Override
    public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
        ActionErrors errors = new ActionErrors();
        Boolean maxExceeded = (Boolean) request.getAttribute(
            MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED
        );
        if (Boolean.TRUE.equals(maxExceeded)) {
            errors.add("maxLengthExceeded", new ActionMessage("error.maxLengthExceeded"));
        }
        return errors;
    }
    
    // 重置表單 (重要:防止文件對象殘留)
    @Override
    public void reset(ActionMapping mapping, HttpServletRequest request) {
        this.theFile = null;
        this.theFile2 = null;
        this.theFile3 = null;
    }
}

2. JSP 頁面:多文件輸入

<%@ taglib uri="/tags/struts-html" prefix="html" %>
<html:html>
<head><title>多文件上傳</title></head>
<body>
    <html:form action="/uploadAction" enctype="multipart/form-data">
        <p>文件 1: <html:file property="theFile"/></p>
        <p>文件 2: <html:file property="theFile2"/></p>
        <p>文件 3: <html:file property="theFile3"/></p>
        <html:submit value="上傳"/>
        <html:cancel/>
    </html:form>
    
    <!-- 錯誤顯示 -->
    <html:errors/>
</body>
</html:html>

3. Action:流式保存與異常處理

package com.example.struts.action;

import org.apache.struts.action.*;
import org.apache.struts.upload.FormFile;
import com.example.struts.form.UploadForm;

import javax.servlet.http.*;
import java.io.*;

public class UploadAction extends Action {
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response) 
            throws Exception {
        
        // 編碼處理
        String encoding = request.getCharacterEncoding();
        if (encoding != null && encoding.equalsIgnoreCase("UTF-8")) {
            response.setContentType("text/html; charset=UTF-8");
        }
        
        UploadForm uploadForm = (UploadForm) form;
        
        // 統一處理多個文件
        FormFile[] files = {
            uploadForm.getTheFile(),
            uploadForm.getTheFile2(),
            uploadForm.getTheFile3()
        };
        
        String uploadDir = getServlet().getServletContext().getRealPath("/uploads");
        File dir = new File(uploadDir);
        if (!dir.exists()) dir.mkdirs();
        
        for (int i = 0; i < files.length; i++) {
            FormFile file = files[i];
            if (file == null || file.getFileSize() == 0) continue; // 跳過空文件
            
            String fileName = file.getFileName();
            if (fileName == null) continue;
            
            // 安全:防止路徑遍歷攻擊
            fileName = new File(fileName).getName();
            
            File destFile = new File(dir, fileName);
            
            try (InputStream in = file.getInputStream();
                 OutputStream out = new FileOutputStream(destFile)) {
                
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
                
                // 可選:記錄上傳信息
                request.setAttribute("uploadedFile" + (i+1), destFile.getAbsolutePath());
                
            } catch (IOException e) {
                log.error("文件上傳失敗: " + fileName, e);
                ActionErrors errors = new ActionErrors();
                errors.add("uploadError", new ActionMessage("error.upload.failed", fileName));
                saveErrors(request, errors);
                return mapping.findForward("failure");
            }
        }
        
        return mapping.findForward("success");
    }
}

4. struts-config.xml 完整配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC 
    "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
    "https://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>
    <!-- 文件上傳全局設置 -->
    <controller maxFileSize="10M" 
                tempDir="/tmp/struts-upload"
                nocache="true"/>
    
    <form-beans>
        <form-bean name="uploadForm" type="com.example.struts.form.UploadForm"/>
    </form-beans>
    
    <action-mappings>
        <action path="/uploadAction"
                type="com.example.struts.action.UploadAction"
                name="uploadForm"
                scope="request"
                input="/upload.jsp">
            <forward name="success" path="/uploadSuccess.jsp"/>
            <forward name="failure" path="/upload.jsp"/>
        </action>
    </action-mappings>
    
    <message-resources parameter="ApplicationResources"/>
</struts-config>

5. 國際化消息資源

# ApplicationResources.properties
error.maxLengthExceeded=上傳文件總大小超過限制 (最大 10MB)
error.upload.failed=文件 {0} 上傳失敗,請重試
upload.success=文件上傳成功

進階主題與最佳實踐

文件大小限制:三層防護

層級配置位置作用範圍
Web 容器 web.xml / server.xml 全局 HTTP 請求體大小
Struts Controller struts-config.xml <controller maxFileSize="10M"> Struts 解析前攔截
業務代碼 Action 中檢查 file.getFileSize() 單文件精確控制

編碼陷阱與解決

// 問題:文件名包含中文,Tomcat 8+ 默認 ISO-8859-1 解碼導致亂碼
// 解決:Tomcat server.xml Connector 設置 URIEncoding
<Connector port="8080" URIEncoding="UTF-8" />

// 或代碼層面修正 (僅對文件名有效)
String fileName = new String(file.getFileName().getBytes("ISO-8859-1"), "UTF-8");

安全加固清單

  1. 文件類型驗證:檢查 Content-Type、文件頭魔數、擴展名白名單
  2. 路徑遍歷防護:new File(fileName).getName() 只取文件名
  3. 存儲隔離:上傳目錄置於 Web 根目錄外,或配置 Nginx 禁止腳本執行
  4. 文件名隨機化:UUID + 原擴展名,避免覆蓋、推測
  5. 病毒掃描:集成 ClamAV 或雲端安全 API

大文件/斷點續傳方案

  • Struts 1 不支持原生分片上傳
  • 前端用 Plupload/WebUploader 分片,後端自定義 Action 合併
  • 或遷移至 Servlet 3.0+ @MultipartConfig + Spring MVC 原生支持

遷移建議:Struts 1 → Spring MVC

// Spring MVC 現代寫法
@PostMapping("/upload")
public String upload(@RequestParam("files") MultipartFile[] files, RedirectAttributes attr) {
    for (MultipartFile file : files) {
        if (!file.isEmpty()) {
            Path dest = Paths.get(uploadDir, UUID.randomUUID() + "_" + file.getOriginalFilename());
            Files.copy(file.getInputStream(), dest);
        }
    }
    attr.addFlashAttribute("message", "上傳成功");
    return "redirect:/upload";
}

核心優勢:原生數組支持、自動綁定、靈活配置、無需 FormBean、RESTful 風格、測試友好。

總結

Struts 1 多文件上傳通過多個 FormFile 屬性實現,核心流程:JSP html:file → FormBean 接收 → Action 流式保存 → 配置 maxFileSize 限制。雖然 Struts 1 已停止維護,但理解其 MultipartRequestHandler 解析機制、FormFile 封裝設計、Controller 全局配置,對維護老系統、遷移新架構極有參考價值。

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