傳統 ActionForm 需為每個表單撰寫 Java 類別。Struts 1.2.6+ 引入 **動態表單**,以 XML 宣告屬性定義,免寫 Java 類別,大幅減少樣板程式碼。進階用法 LazyValidatorForm 甚至可完全省略屬性宣告。
於 struts-config.xml <form-beans> 區塊:
<form-bean name="dynamicForm" type="org.apache.struts.action.DynaActionForm">
<!-- 簡單屬性 -->
<form-property name="simpleProp" type="java.lang.String" initial="bill" />
<!-- 索引屬性(陣列) -->
<form-property name="indexedProp" type="java.lang.String[]" />
<!-- 映射屬性 -->
<form-property name="mappedProp" type="java.util.HashMap" />
<!-- 巢狀屬性 -->
<form-property name="nestedProp" type="com.bean.MyBean" />
</form-bean>
type 必須為 DynaActionForm 或其子類(如 DynaValidatorForm)。initial 設定簡單屬性預設值。涵蓋所有 Java 基本型別包裝類別與常用時間類別:
java.math.BigDecimal, BigInteger
java.lang.Boolean, Byte, Character, Class, Double, Float, Integer, Long, Short, String
java.sql.Date, Time, Timestamp
在 Action 中取得 DynaActionForm 實例後,使用 getter 方法:
DynaActionForm dForm = (DynaActionForm) form;
// 簡單屬性
String name = (String) dForm.get("name");
// 或型別安全版
String name = dForm.getString("name");
// 索引屬性
String[] hobbies = (String[]) dForm.get("hobbies");
String hobby1 = dForm.get("hobbies", 0); // 指定索引
String[] hobbies = dForm.getStrings("hobbies"); // 型別安全版
// 映射屬性
String value = (String) dForm.get("myMap", "key1");
注意:getString/getStrings 僅適用 String/String[] 類型,其他類型會拋出例外。
<form-bean name="dynamicForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="name" type="java.lang.String" />
<form-property name="age" type="java.lang.Short" />
<form-property name="salary" type="java.lang.Float" />
<form-property name="hobby" type="java.lang.String[]" />
</form-bean>
<action name="dynamicForm" path="/dynamic" scope="request" type="action.DynamicAction" />
package action;
import org.apache.struts.action.*;
import org.apache.struts.action.DynaActionForm;
import javax.servlet.http.*;
import java.io.*;
public class DynamicAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
try {
DynaActionForm dForm = (DynaActionForm) form;
String name = (String) dForm.get("name");
Short age = (Short) dForm.get("age");
Float salary = (Float) dForm.get("salary");
int hobbyCount = ((String[]) dForm.get("hobby")).length;
PrintWriter out = response.getWriter();
out.println("name: " + name + "");
out.println("age: " + age + "");
out.println("salary: " + salary + "");
for (int i = 0; i < hobbyCount; i++) {
out.println("hobby" + (i+1) + ": " + dForm.get("hobby", i) + "");
}
} catch (Exception e) {}
return null;
}
}
<html:form action="dynamic">
姓名:<html:text property="name" /><br>
年齡:<html:text property="age" /><br>
薪資:<html:text property="salary" /><br>
愛好1:<html:text property="hobby" value="" /><br>
愛好2:<html:text property="hobby" value="" /><br>
愛好3:<html:text property="hobby" value="" /><br>
<html:submit value="提交" />
</html:form>
索引屬性在 JSP 中以相同 property 重複出現,Struts 自動依序綁定至陣列。
| 方式 | 說明 |
|---|---|
| 繼承 DynaActionForm 覆寫 validate() | 自訂驗證邏輯,但失去免寫 Java 類別優勢 |
| 使用 DynaValidatorForm + Validator 框架 | **推薦**:XML 宣告驗證規則,無需 Java 程式碼 |
若用 DynaValidatorForm,其 validate() 開頭需呼叫 super.validate() 觸發框架驗證。
繼承 DynaValidatorForm,**完全不需在 XML 宣告屬性**,首次存取時自動以 String 型別動態建立。搭配 Validator 框架,連驗證規則也可在 validator.xml 定義,真正做到「零 Java 類別、零 XML 屬性宣告」。
動態表單將「定義屬性」從 Java 類別移至 XML 配置,DynaActionForm 為基礎,DynaValidatorForm 整合驗證,LazyValidatorForm 達到極致彈性。實務上建議預設使用 DynaValidatorForm,兼顧型別安全與開發效率。