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

Struts 1 文件下載重命名實戰:繼承 DownloadAction 實現動態文件名

     編輯:Java 相關知識

前言

Struts 1 內置 org.apache.struts.actions.DownloadAction 提供了基礎文件下載能力,但默認使用服務端物理文件名。本文演示如何通過繼承 DownloadAction 並重寫關鍵方法,實現下載時動態重命名文件(如:用戶看到「我的報表.pdf」而非「report_20231001_001.pdf」)。

核心思路

  1. 繼承 DownloadAction
  2. 重寫 getStreamInfo():指定文件流來源(MIME 類型、路徑)
  3. 重寫 execute():在父類執行前,通過 response.setHeader("Content-Disposition", ...) 設置自定義下載文件名

完整代碼實現

package com.fenghuo.struts.download;

import java.net.URLEncoder;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DownloadAction;
import com.fenghuo.music.util.FileUtils;

public class DownLoad extends DownloadAction {

    @Override
    protected StreamInfo getStreamInfo(ActionMapping mapping, ActionForm form,
                                       HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 1. 獲取請求參數:資源標識
        String resname = request.getParameter("resname");

        // 2. 返回資源流信息:MIME類型、ServletContext、相對路徑
        return new DownloadAction.ResourceStreamInfo(
            "audio/x-mpeg",                           // MIME 類型
            this.getServlet().getServletContext(),    // ServletContext
            "/resource/music/" + resname              // 相對路徑
        );
    }

    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 1. 獲取參數
        String resname = request.getParameter("resname");

        // 2. 查詢真實文件名(業務邏輯:從 Map/DB 獲取)
        FileUtils fu = new FileUtils(this.getServlet().getServletContext());
        Map<String, String> musmap = fu.getMusmap();
        String realFileName = musmap.get(resname); // 如:周杰倫 - 稻香.mp3

        // 3. 設置 Content-Disposition Header,指定下載文件名
        // URLEncoder 編碼防止中文亂碼
        String encodedName = URLEncoder.encode(realFileName, "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + encodedName);

        // 4. 調用父類 execute 執行實際下載邏輯
        return super.execute(mapping, form, request, response);
    }
}

關鍵技術點解析

1. DownloadAction.ResourceStreamInfo

  • 構造參數:contentType、servletContext、path(相對於 WebApp 根目錄)
  • 框架內部會調用 servletContext.getResourceAsStream(path) 獲取輸入流

2. Content-Disposition Header

attachment; filename="encoded_name.ext"
  • attachment:強制下載彈框,而非瀏覽器直接打開
  • filename:用戶看到的下載文件名,**必須 URL 編碼**
  • 編碼:URLEncoder.encode(name, "UTF-8"),空格會變 +,瀏覽器兼容性良好

3. 執行順序關鍵

必須在 super.execute() 之前設置 Header,因為父類會直接寫入響應體並提交響應,之後無法修改 Header。

配置 struts-config.xml

<action path="/download"
        type="com.fenghuo.struts.download.DownLoad"
        name="downloadForm"
        scope="request">
</action>

前端調用示例

<a href="/app/download.do?resname=report_20231001_001.pdf">下載報表</a>

常見問題與解決

問題原因解決
中文文件名亂碼未 URL 編碼 / 編碼不一致統一用 URLEncoder.encode(name, "UTF-8"),前端頁面編碼 UTF-8
Firefox 仍亂碼瀏覽器對 RFC 5987 支持差異嘗試 filename*=UTF-8''encoded 格式,或用 Content-Disposition: attachment; filename="fallback.txt"; filename*=UTF-8''real.txt
大文件下載中斷無 Content-Length / 連接超時在 getStreamInfo 返回自定義 StreamInfo 實現 getContentLength(),或配置 Tomcat connectionTimeout
權限控制直接暴露文件路徑execute() 中校驗用戶權限,無權返回錯誤 Forward

總結

Struts 1 文件下載重命名核心在於:繼承 DownloadAction → 重寫 getStreamInfo 定位文件 → execute() 前設置 Content-Disposition Header → 父類執行流傳輸。此模式可靈活支持:數據庫存儲文件元數據、權限校驗、動態文件名生成、多語言文件名等企業級場景。

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