Struts 2 透過攔截器機制內建檔案上傳、參數封裝、驗證等功能。本文系統整理:單檔/多檔上傳配置、自定義權限攔截器、手動驗證與 XML 驗證兩種模式,並釐清常見坑點。
public String scope() {
ActionContext ctx = ActionContext.getContext();
ctx.getApplication().put("app", "應用範圍"); // ServletContext
ctx.getSession().put("ses", "Session 範圍"); // HttpSession
ctx.put("req", "Request 範圍"); // HttpServletRequest
return "scope";
}
JSP 取值:${applicationScope.app}、${sessionScope.ses}、${requestScope.req}。
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext servletContext = ServletActionContext.getServletContext();
HttpSession session = request.getSession();
public class MyAction implements ServletRequestAware, ServletResponseAware, ServletContextAware {
private HttpServletRequest request;
private HttpServletResponse response;
private ServletContext servletContext;
@Override public void setServletRequest(HttpServletRequest request) { this.request = request; }
@Override public void setServletResponse(HttpServletResponse response) { this.response = response; }
@Override public void setServletContext(ServletContext context) { this.servletContext = context; }
}
推薦方式 2,利於單元測試(可注入 Mock 物件)。
<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>
<form action="${pageContext.request.contextPath}/upload.action" method="post" enctype="multipart/form-data">
<input type="file" name="uploadImage" />
<input type="submit" value="上傳" />
</form>
private File uploadImage; // 檔案內容(臨時檔)
private String uploadImageContentType; // MIME 類型
private String uploadImageFileName; // 原始檔名
// getter/setter 省略
屬性名稱 = 表單 name + ContentType/FileName。
public String upload() {
String saveDir = ServletActionContext.getServletContext().getRealPath("/images");
File dir = new File(saveDir);
if (!dir.exists()) dir.mkdirs();
File dest = new File(dir, uploadImageFileName);
FileUtils.copyFile(uploadImage, dest); // commons-io
return "success";
}
表單同名 name="uploadImages" 多個 <input type="file">,Action 改用陣列:
private File[] uploadImages;
private String[] uploadImagesContentType;
private String[] uploadImagesFileName;
public String upload() {
String saveDir = ServletActionContext.getServletContext().getRealPath("/images");
File dir = new File(saveDir);
if (!dir.exists()) dir.mkdirs();
for (int i = 0; i < uploadImages.length; i++) {
FileUtils.copyFile(uploadImages[i], new File(dir, uploadImagesFileName[i]));
}
return "success";
}
public class PermissionInterceptor implements Interceptor {
@Override public void init() {}
@Override public void destroy() {}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
HttpSession session = ServletActionContext.getRequest().getSession();
if (session.getAttribute("user") != null) {
return invocation.invoke(); // 通過
}
return "logon"; // 重導登入
}
}
<package name="demo" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="permission" class="com.demo.PermissionInterceptor" />
<interceptor-stack name="permissionStack">
<interceptor-ref name="defaultStack" /> <!-- 必須包含,否則失去檔案上傳、驗證等功能 -->
<interceptor-ref name="permission" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="permissionStack" /> <!-- 整包預設 -->
<action name="upload" class="com.demo.UploadAction">
<result>/success.jsp</result>
<result name="input">/upload.jsp</result> <!-- 驗證失敗導向 -->
</action>
</package>
關鍵:自定義攔截器必須引用 defaultStack,否則檔案上傳、參數封裝、驗證等核心功能失效。
validate():驗證所有 execute() 同簽名方法。validateXxx():僅驗證 xxx() 方法(Xxx 首字母大寫)。public void validate() {
if (mobile == null || mobile.trim().isEmpty()) {
addFieldError("mobile", "手機號不可為空");
} else if (!mobile.matches("^1[358]\\d{9}$")) {
addFieldError("mobile", "手機號格式錯誤");
}
}
public void validateAdd() { // 僅驗證 add() 方法
if (username == null || username.trim().isEmpty()) {
addFieldError("username", "用戶名不可為空");
}
}
驗證失敗自動導向 name="input" 的 Result,JSP 用 <s:fielderror/> 顯示。
檔案置於 Action 同包,命名 UserAction-validation.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.3//EN"
"https://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd">
<validators>
<field name="username">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>用戶名不可為空</message>
</field-validator>
</field>
<field name="email">
<field-validator type="email">
<message>Email 格式錯誤</message>
</field-validator>
</field>
</validators>
常用驗證器:requiredstring、int、double、date、email、url、regex、stringlength。
conversionError 攔截器收集。validateXxx()(若存在)。validate()。fieldErrors 不為空 → 導向 input Result;否則執行 Action 方法。struts.multipart.maxSize(預設 2MB),需在 struts.xml 或 struts.properties 調大。finally 或攔截器中清理。<message key="error.username.required"/> 配合資源檔。defaultStack 內順序固定,自定義攔截器置於最後執行業務邏輯前。