Struts 1 通過 org.apache.struts.upload.FormFile 封裝上傳文件,配合 MultipartRequestHandler 解析 multipart/form-data 請求。關鍵點:
FormFile 屬性 (單個或數組)<html:file> 標籤,form 必須 enctype="multipart/form-data"controller 最大文件大小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;
}
}
<%@ 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>
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");
}
}
<?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>
# 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");
new File(fileName).getName() 只取文件名@MultipartConfig + 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 全局配置,對維護老系統、遷移新架構極有參考價值。