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

Java 檔案上傳下載三大方案完整對比:原生 Servlet、JSP 手工解析、Struts 2

     編輯:Java 相關知識

方案一:原生 Servlet + Part API(Servlet 3.0+,推薦)

現代標準做法,無第三方依賴,支援 @MultipartConfig 註解配置。

1. Servlet 類

@WebServlet("/upload")
@MultipartConfig(
    location = "/tmp/uploads",      // 暫存目錄
    maxFileSize = 2_097_152,        // 2MB
    maxRequestSize = 4_194_304,     // 4MB
    fileSizeThreshold = 1024 * 1024 // 1MB 寫入磁碟
)
public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        Part filePart = req.getPart("file"); // 取得上傳檔案 Part
        String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // 防路徑遍歷
        String savedPath = "/var/www/uploads/" + UUID.randomUUID() + "_" + fileName;
        filePart.write(savedPath); // 直接寫入目的地
        resp.getWriter().write("上傳成功:" + savedPath);
    }
}

2. 前端表單

<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file" accept="image/*" />
    <button type="submit">上傳</button>
</form>

方案二:JSP 手工解析 multipart/request(不推薦生產使用)

早期 Servlet 2.5 時代無標準 API,需手工解析 ServletInputStream 的 boundary 格式。代碼冗長、易出錯、難維護,僅供教學理解 multipart 協議結構。現代專案請勿使用。

方案三:Struts 2 內建檔案上傳攔截器

1. 依賴

<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency>
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>

2. Action 類

public class UploadAction extends ActionSupport {
    private File uploadImage;              // 檔案內容
    private String uploadImageContentType; // MIME 類型
    private String uploadImageFileName;    // 原始檔名
    private String savePath;               // 存儲目錄(struts.xml 注入)

    // getter/setter 省略

    @Override
    public String execute() {
        File dest = new File(savePath, uploadImageFileName);
        FileUtils.copyFile(uploadImage, dest); // commons-io
        return SUCCESS;
    }
}

命名約定:表單 <input name="uploadImage"> 對應 Action 三屬性 uploadImage、uploadImageContentType、uploadImageFileName。

3. struts.xml 設定與攔截器參數

<action name="upload" class="com.example.UploadAction">
    <param name="savePath">/var/www/uploads</param>
    <!-- 使用 fileUpload 攔截器限制類型與大小 -->
    <interceptor-ref name="defaultStack">
        <param name="fileUpload.allowedTypes">image/jpeg,image/png,image/gif</param>
        <param name="fileUpload.maximumSize">2097152</param> <!-- 2MB -->
    </interceptor-ref>
    <result name="input">/upload.jsp</result> <!-- 驗證失敗返回 -->
    <result name="success">/success.jsp</result>
</action>

4. 國際化錯誤訊息

在 struts.properties 或 messages.properties 覆寫:

struts.messages.error.file.too.large=檔案大小超過限制(最大 {1} 位元組)
struts.messages.error.content.type.not.allowed=不允許的檔案類型:{1}

JSP 顯示:<s:fielderror />。

檔案下載:通用 Response 處理

@GetMapping("/download/{fileName}")
public void download(@PathVariable String fileName, HttpServletResponse resp) throws IOException {
    Path path = Paths.get("/var/www/uploads", fileName).normalize(); // 防路徑遍歷
    if (!Files.exists(path)) { resp.sendError(404); return; }

    resp.setContentType(Files.probeContentType(path));
    resp.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\"");
    resp.setContentLengthLong(Files.size(path));
    Files.copy(path, resp.getOutputStream());
}

Struts 2 下載(Stream Result)

<action name="download" class="com.example.FileDownloadAction">
    <param name="inputPath">/var/www/uploads/demo.txt</param>
    <result name="success" type="stream">
        <param name="contentType">application/octet-stream</param>
        <param name="inputName">inputStream</param> <!-- 對應 getInputStream() -->
        <param name="contentDisposition">attachment;filename="demo.txt"</param>
        <param name="bufferSize">4096</param>
    </result>
</action>

Action 需提供 public InputStream getInputStream() 回傳檔案流。

方案選型建議

方案優點缺點適用場景
Servlet 3.0 Part API零依賴、標準化、效能好、程式碼簡潔需 Servlet 3.0+ 容器現代 Spring Boot、微服務、所有新專案
Struts 2整合驗證、國際化、攔截器豐富依賴 commons-fileupload、配置較繁瑣既有 Struts 2 專案維護
JSP 手工解析理解協議原理極易出錯、無維護性教學、考古

安全與最佳實踐

  1. 檔名處理:永不信任客戶端檔名,使用 UUID + 原始副檔名,防路徑遍歷(Paths.get(...).normalize())。
  2. 類型驗證:除副檔名外,需檢查 Content-Type 甚至檔案魔數(Magic Bytes)。
  3. 大小限制:在容器層(@MultipartConfig)與業務層雙重限制。
  4. 儲存隔離:上傳目錄不可直接對外靜態服務,或嚴格設定 Nginx/Apache 僅允許安全副檔名。
  5. 異步處理:大檔上傳建議回傳 202 Accepted,背景處理並通知前端。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved