<result> 是 Struts 2 將 Action 邏輯結果映射到視圖的核心配置。本文系統講解分發器、重定向、FreeMarker、JSON、鏈式結果等類型,以及動態參數、全局結果、異常映射等進階用法。
| 類型 | 類名/別名 | 適用場景 | 關鍵參數 |
|---|---|---|---|
| 分發器(默認) | dispatcher / ServletDispatcherResult | 服務端轉發到 JSP/HTML | location、parse=true |
| 重定向 | redirect / ServletRedirectResult | 客戶端跳轉,URL 變化 | location、parse=true、anchor |
| 重定向動作 | redirectAction | 重定向到另一個 Action | actionName、namespace、suppressEmptyParameters |
| 鏈式調用 | chain | 同一請求內調用另一 Action,共享狀態 | actionName、namespace、method |
| FreeMarker | freemarker | 模板引擎渲染 | location(模板路徑) |
| Velocity | velocity | 模板引擎渲染 | location |
| JSON | json (struts2-json-plugin) | REST API 返回數據 | root、includeProperties、excludeProperties |
| Stream | stream | 文件下載、圖片輸出、二進制流 | inputName、contentType、contentLength、bufferSize |
| XSLT | xslt | XML 轉換 | location(XSL 文件)、matchingPattern |
| Tiles | tiles | 頁面佈局框架整合 | location(Tiles 定義名) |
| JFreeChart | jasper | 報表導出 | location(.jrxml)、dataSource、format |
<action name="hello" class="com.example.HelloAction">
<result name="success">/WEB-INF/jsp/hello.jsp</result>
</action>
<action name="download" class="com.example.DownloadAction">
<result name="success" type="stream">
<param name="inputName">inputStream</param>
<param name="contentType">application/octet-stream</param>
<param name="contentDisposition">attachment;filename="${filename}"</param>
<param name="bufferSize">4096</param>
</result>
</action>
<action name="login" class="com.example.LoginAction" method="execute">
<result name="success" type="redirectAction">
<param name="actionName">dashboard</param>
</result>
<result name="input">/login.jsp</result> <!-- 驗證失敗返回表單 -->
<result name="locked">/account_locked.jsp</result>
<result name="error" type="json">
<param name="root">errorMsg</param>
</result>
</action>
parse=true(默認):location 中的 ${...} 會被 OGNL 解析<param name="location">/user/${userId}/profile</param><param name="parse">false</param>(靜態路徑提升性能)<package name="default" extends="struts-default">
<global-results>
<result name="login" type="redirect">/login.jsp</result>
<result name="error">/common/error.jsp</result>
<result name="noPermission">/common/403.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.sql.SQLException" result="error"/>
<exception-mapping exception="com.example.BizException" result="error"/>
</global-exception-mappings>
...
</package>
所有 Action 共享,減少重複配置。
<action name="saveUser" class="com.example.UserAction" method="save">
<result name="success" type="redirectAction">
<param name="actionName">userList</param>
<param name="namespace">/admin</param>
<param name="suppressEmptyParameters">true</param> <!-- 避免攜帶空參數 -->
</result>
<result name="input">/user_form.jsp</result>
</action>
等效於 return "redirectAction:userList?namespace=/admin"(代碼中)。
| 特性 | chain | redirectAction |
|---|---|---|
| 請求 | 同一 HTTP 請求 | 新 HTTP 請求(302) |
| Action 實例 | 新建目標 Action | 新建目標 Action |
| ValueStack | 共享(源 Action 數據可用) | 不共享(新請求新棧) |
| URL | 不變 | 變為目標 Action URL |
| 適用場景 | 多步驟向導、預處理後轉發 | POST-Redirect-GET 模式、跨命名空間 |
<action name="api/users" class="com.example.ApiUserAction">
<result name="success" type="json">
<param name="root">userList</param> <!-- 序列化的根對象 -->
<param name="includeProperties">userList\[.*\](id|username|email),total</param>
<param name="excludeProperties">userList\[.*\].password</param>
<param name="noCache">true</param>
<param name="contentType">application/json;charset=UTF-8</param>
</result>
</action>
// Action
public class ExportAction extends ActionSupport {
private InputStream inputStream;
private String filename;
private long contentLength;
public String execute() {
List<User> users = userService.getAll();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (Workbook wb = new XSSFWorkbook()) {
Sheet sheet = wb.createSheet("Users");
// 填充數據...
wb.write(baos);
}
byte[] bytes = baos.toByteArray();
this.inputStream = new ByteArrayInputStream(bytes);
this.filename = "users_" + LocalDate.now() + ".xlsx";
this.contentLength = bytes.length;
return SUCCESS;
}
// getters...
}
// struts.xml
<action name="exportUsers" class="com.example.ExportAction">
<result name="success" type="stream">
<param name="inputName">inputStream</param>
<param name="contentType">application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</param>
<param name="contentDisposition">attachment;filename="${filename}"</param>
<param name="contentLength">${contentLength}</param>
<param name="bufferSize">8192</param>
</result>
</action>
public class DynamicResultAction extends ActionSupport {
private String viewType; // jsp, json, excel
public String execute() {
if ("mobile".equals(deviceType)) return "mobileView";
if ("api".equals(clientType)) return "jsonView";
return SUCCESS;
}
}
// struts.xml
<action name="dynamic" class="com.example.DynamicResultAction">
<result name="success">/desktop.jsp</result>
<result name="mobileView">/mobile.jsp</result>
<result name="jsonView" type="json">
<param name="root">data</param>
</result>
</action>
| 現象 | 原因 | 解決 |
|---|---|---|
| 重定向後數據丟失 | 用 redirect 而非 chain/redirectAction,或未使用 Flash 機制 | 改用 redirectAction 攜帶參數,或 Session/Flash 存儲 |
| JSON 返回 406 | 缺少 json-plugin 或 Accept 頭不匹配 | 添加依賴,設置 contentType 參數 |
| 文件下載文件名亂碼 | Content-Disposition 編碼問題 | 使用 URLEncoder.encode(filename, "UTF-8") 並設置 filename*=UTF-8''... |
| OGNL 表達式報錯 | 屬性為 null 或類型不匹配 | Action 中初始化默認值,或使用 #attr.defaultValue |
<result> 是 Struts 2 視圖解耦的關鍵。掌握 11 種結果類型、parse 參數解析、全局結果/異常映射、chain 與 redirectAction 區別、JSON/Stream 參數微調,即可應對從傳統 MVC 到 REST API、文件下載、報表導出的所有視圖需求。新項目建議 Spring MVC,但維護老項目時這些配置技巧依然高頻使用。