在傳統 Java Web 開發中,檔案上傳常使用 Apache Commons FileUpload 手動解析請求流,程式碼繁瑣且易出錯。Struts 2 內建強大的檔案上傳攔截器,配合結果類型 stream,能以極少量程式碼完成單檔、多檔上傳與下載。本文以實戰範例完整說明流程與關鍵設定。
commons-fileupload-1.3.x.jarcommons-io-2.x.jar將上述 JAR 放入 WEB-INF/lib 或由 Maven 管理:
<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>
表單必須設定 method="post" 且 enctype="multipart/form-data"。
<form action="fileUpload.action" method="post" enctype="multipart/form-data">
使用者名稱: <input type="text" name="username" /><br/>
選擇檔案: <input type="file" name="myFile" /><br/>
<input type="submit" value="上傳" />
</form>
Struts 2 慣例:myFile 對應 File myFile、myFileFileName 對應原始檔名、myFileContentType 對應 MIME 類型。
public class FileUploadAction extends ActionSupport {
private String username;
private File myFile;
private String myFileFileName;
private String myFileContentType;
// Getter/Setter 省略...
@Override
public String execute() {
String saveDir = ServletActionContext.getServletContext().getRealPath("/uploads");
File dir = new File(saveDir);
if (!dir.exists()) dir.mkdirs();
File dest = new File(dir, myFileFileName);
try (InputStream is = new FileInputStream(myFile);
OutputStream os = new FileOutputStream(dest)) {
byte[] buffer = new byte[4096];
int len;
while ((len = is.read(buffer)) > 0) os.write(buffer, 0, len);
} catch (IOException e) {
addActionError("上傳失敗:" + e.getMessage());
return ERROR;
}
return SUCCESS;
}
}
<action name="fileUpload" class="com.example.FileUploadAction">
<interceptor-ref name="defaultStack">
<param name="fileUpload.maximumSize">20971520</param> <!-- 20MB -->
<param name="fileUpload.allowedTypes">image/jpeg,image/png,application/pdf</param>
</interceptor-ref>
<result name="success">/uploadSuccess.jsp</result>
<result name="input">/upload.jsp</result> <!-- 驗證失敗返回 -->
</action>
前端同名 name="myFiles" 產生多個 <input type="file">,後端改用 List<File> 接收。
private List<File> myFiles;
private List<String> myFilesFileName;
private List<String> myFilesContentType;
// execute() 中迭代處理
for (int i = 0; i < myFiles.size(); i++) {
File src = myFiles.get(i);
String fileName = myFilesFileName.get(i);
File dest = new File(saveDir, fileName);
Files.copy(src.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
核心在於 result type="stream",Action 僅需提供 InputStream getter。
public class FileDownloadAction extends ActionSupport {
private String fileName; // 前端傳入
public void setFileName(String fileName) {
this.fileName = fileName;
}
public InputStream getInputStream() {
String path = ServletActionContext.getServletContext().getRealPath("/uploads/" + fileName);
return new FileInputStream(new File(path));
}
public String getContentDisposition() {
try {
return "attachment;filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\"";
} catch (UnsupportedEncodingException e) {
return "attachment;filename=\"download\"";
}
}
}
<action name="fileDownload" class="com.example.FileDownloadAction">
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">${contentDisposition}</param>
<param name="bufferSize">4096</param>
</result>
</action>
struts.multipart.saveDir(預設為容器工作目錄),Action 執行前即存在,執行完畢若未移走會被自動刪除。URLEncoder.encode,否則瀏覽器顯示亂碼。struts.xml 或 struts.properties 設定 struts.multipart.maxSize(預設 2MB)。allowedTypes 與副檔名,防止惡意腳本上傳。Struts 2 的檔案上傳/下載機制將底層流處理封裝為慣例大於配置的模型,開發者只需專注業務邏輯。掌握 File、FileName、ContentType 三屬性命名規則與 stream 結果型別,即可輕鬆實作健壯的檔案管理功能。