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

Struts2 文件上傳完整實戰:圖片上傳、類型驗證、多文件與安全配置

     編輯:Java 相關知識

前言

Struts2 內建強大的文件上傳支援,基於 FileUploadInterceptor 自動將表單文件封裝為 File 物件。本文以圖片上傳為例,涵蓋單/多文件、類型大小限制、自定義儲存路徑、安全防護與完整配置實戰。

核心原理:三屬性自動注入

表單 <s:file name="myFile"> 提交時,Struts2 自動注入 Action 三個屬性(setXxx 方法):

屬性類型說明
myFileFile上傳文件臨時存放物件
myFileContentTypeStringMIME 類型,如 image/jpeg
myFileFileNameString原始文件名

完整實戰代碼

1. JSP 上傳頁面

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head><title>圖片上傳</title></head>
<body>
    <s:form action="upload" method="post" enctype="multipart/form-data">
        <s:file name="myFile" label="選擇圖片" accept="image/*"/>
        <s:textfield name="description" label="圖片描述"/>
        <s:submit value="上傳"/>
    </s:form>
</body>
</html>

2. Action 處理類

package com.example.action;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;

import java.io.*;
import java.util.Date;

public class UploadAction extends ActionSupport {
    // 自動注入屬性
    private File myFile;
    private String myFileContentType;
    private String myFileFileName;
    private String description;

    // 回顯用
    private String savedFileName;
    private String message;

    // 配置常數
    private static final long MAX_SIZE = 5 * 1024 * 1024; // 5MB
    private static final String[] ALLOWED_TYPES = {"image/jpeg", "image/png", "image/gif"};
    private static final String UPLOAD_DIR = "uploads";

    @Override
    public String execute() {
        // 1. 基礎校驗
        if (myFile == null) {
            message = "請選擇文件";
            return INPUT;
        }
        if (myFile.length() > MAX_SIZE) {
            message = "文件大小超過 5MB 限制";
            return INPUT;
        }
        if (!isAllowedType(myFileContentType)) {
            message = "僅支援 JPG/PNG/GIF 格式";
            return INPUT;
        }

        // 2. 生成唯一文件名:時間戳 + 隨機數 + 原副檔名
        String ext = getExtension(myFileFileName);
        savedFileName = new Date().getTime() + "_" + 
                       (int)(Math.random() * 10000) + "." + ext;

        // 3. 獲取伺服器絕對儲存路徑
        String realPath = ServletActionContext.getServletContext()
                            .getRealPath("/" + UPLOAD_DIR);
        File destDir = new File(realPath);
        if (!destDir.exists()) destDir.mkdirs();

        // 4. 文件複製(緩衝流,避免大文件記憶體溢出)
        try (InputStream in = new BufferedInputStream(new FileInputStream(myFile));
             OutputStream out = new BufferedOutputStream(
                     new FileOutputStream(new File(destDir, savedFileName)))) {
            
            byte[] buffer = new byte[8192];
            int len;
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
            message = "上傳成功!";
            return SUCCESS;
        } catch (IOException e) {
            message = "上傳失敗:" + e.getMessage();
            e.printStackTrace();
            return ERROR;
        }
    }

    private boolean isAllowedType(String contentType) {
        for (String t : ALLOWED_TYPES) if (t.equalsIgnoreCase(contentType)) return true;
        return false;
    }

    private String getExtension(String fileName) {
        int idx = fileName.lastIndexOf('.');
        return (idx > 0) ? fileName.substring(idx + 1).toLowerCase() : "bin";
    }

    // --- Getter/Setter ---
    public void setMyFile(File myFile) { this.myFile = myFile; }
    public void setMyFileContentType(String myFileContentType) { this.myFileContentType = myFileContentType; }
    public void setMyFileFileName(String myFileFileName) { this.myFileFileName = myFileFileName; }
    public void setDescription(String description) { this.description = description; }
    public String getSavedFileName() { return savedFileName; }
    public String getMessage() { return message; }
    public String getDescription() { return description; }
}

3. 結果頁面

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
    <h3><s:property value="message"/></h3>
    <s:if test="savedFileName != null">
        <div>描述:<s:property value="description"/></div>
        <img src="<s:url value="/uploads/%{savedFileName}"/>" 
             alt="上傳圖片" style="max-width:400px;"/>
    </s:if>
    <a href="upload.jsp">繼續上傳</a>
</body>
</html>

4. struts.xml 配置

<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" 
    "https://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
    <package name="upload" namespace="/" extends="struts-default">
        <action name="upload" class="com.example.action.UploadAction">
            <!-- 文件上傳攔截器堆疊,含大小/類型限制 -->
            <interceptor-ref name="fileUpload">
                <param name="maximumSize">5242880</param> <!-- 5MB -->
                <param name="allowedTypes">image/jpeg,image/png,image/gif</param>
            </interceptor-ref>
            <interceptor-ref name="defaultStack"/>
            
            <result name="success">/result.jsp</result>
            <result name="input">/upload.jsp</result>
            <result name="error">/error.jsp</result>
        </action>
    </package>
</struts>

多文件上傳擴展

JSP

<s:file name="files" label="圖片1"/>
<s:file name="files" label="圖片2"/>
<s:file name="files" label="圖片3"/>

Action

private List files = new ArrayList<>();
private List filesContentType = new ArrayList<>();
private List filesFileName = new ArrayList<>();

public void setFiles(List files) { this.files = files; }
public void setFilesContentType(List filesContentType) { this.filesContentType = filesContentType; }
public void setFilesFileName(List filesFileName) { this.filesFileName = filesFileName; }

@Override
public String execute() {
    for (int i = 0; i < files.size(); i++) {
        File f = files.get(i);
        String type = filesContentType.get(i);
        String name = filesFileName.get(i);
        // 單文件處理邏輯...
    }
    return SUCCESS;
}

安全加固清單

  1. 文件類型二次驗證:MIME 可偽造,需讀取文件頭(Magic Number)驗證真實類型
  2. 儲存路徑隔離:上傳目錄置於 WebRoot 外,或配置 Nginx 禁止腳本執行
  3. 文件名去識別化:禁止使用原始文件名,防止路徑遍歷(../)與覆蓋
  4. 大小限制雙重保險:Struts2 攔截器 + Tomcat maxPostSize + 前端 JS 預檢
  5. 病毒掃描:生產環境整合 ClamAV 等掃描引擎
  6. 權限最小化:上傳目錄僅賦予寫入權限,無執行權限

常見問題排查

現象原因解決
myFile 為 null表單缺少 enctype="multipart/form-data"檢查 <s:form> 屬性
中文文件名亂碼Tomcat 8+ 預設 UTF-8,舊版需 URIEncodingserver.xml 設 URIEncoding="UTF-8"
上傳大文件失敗超過 maximumSize 或 Tomcat post 大小限制調整 struts.xml & server.xml maxPostSize
權限拒絕伺服器目錄無寫入權限chmod 755 uploads 目錄

總結

Struts2 文件上傳核心在於「三屬性約定」與「fileUpload 攔截器堆疊」。生產環境務必實施:類型雙重驗證、路徑隔離、文件名隨機化、大小多層限制、病毒掃描。配合 Nginx 反向代理靜態資源服務,可構建安全高效的上傳服務。

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