Struts 2 通過約定優於配置 + 註解驅動,徹底擺脫冗長的 struts.xml。本文系統梳理 Action 映射、結果視圖、攔截器鏈、驗證規則、類型轉換五大註解體系。
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-convention-plugin</artifactId>
<version>2.5.30</version>
</dependency>
<!-- 核心依賴自動傳遞:xwork, ognl, freemarker, javassist 等 -->
| 註解 | 作用 | 關鍵屬性 |
|---|---|---|
| @Namespace | 定義命名空間 | value="/admin" |
| @Action | 映射 URL 到方法 | value="login", results={@Result...} |
| @Actions | 同一類多個 Action | value={@Action(...), @Action(...)} |
| @Result | 定義單個結果視圖 | name="success", location="/jsp/home.jsp", type="dispatcher" |
| @Results | 定義多個結果集合 | value={@Result(...), @Result(...)} |
| @ResultPath | 結果視圖根路徑 | value="/WEB-INF/content" |
@Namespace("/user")
@ResultPath("/WEB-INF/jsp")
@Results({
@Result(name="success", location="profile.jsp"),
@Result(name="input", location="login.jsp"),
@Result(name="json", type="json", params={"root", "user"})
})
public class UserAction extends ActionSupport {
private User user;
@Action(value="login",
results={@Result(name="success", type="redirectAction", location="profile")})
public String login() {
if (userService.authenticate(user.getUsername(), user.getPassword())) {
return SUCCESS;
}
return INPUT;
}
@Action("profile")
public String profile() { return SUCCESS; }
@Action(value="api/user", results=@Result(name="success", type="json"))
public String apiUser() { return SUCCESS; }
// Getter/Setter 省略
}
public class SecureAction extends ActionSupport {
@Before
public void checkAuth() throws AuthenticationException {
if (!SecurityUtils.isLoggedIn()) throw new AuthenticationException();
}
@After
public void auditLog() { AuditLogger.log(ActionContext.getContext()); }
@BeforeResult
public void prepareViewData() { /* 裝配頁面數據 */ }
@Action("secure")
public String execute() { return SUCCESS; }
}
執行順序:@Before -> Action 方法 -> @BeforeResult -> 結果視圖渲染 -> @After
| 註解 | 驗證規則 | 關鍵屬性 |
|---|---|---|
| @RequiredStringValidator | 非空字符串 | trim=true, message="用戶名必填" |
| @RequiredFieldValidator | 非空對象 | fieldName="user", message="用戶對象必填" |
| @IntRangeFieldValidator | 整數範圍 | min="18", max="100", message="年齡18-100" |
| @DoubleRangeFieldValidator | 浮點數範圍 | minInclusive="0.01", maxInclusive="9999.99" |
| @DateRangeFieldValidator | 日期範圍 | min="2000-01-01", max="2024-12-31" |
| @EmailValidator | 郵箱格式 | message="郵箱格式錯誤" |
| @UrlValidator | URL 格式 | |
| @RegexFieldValidator | 正則表達式 | expression="^1[3-9]\\d{9}$", message="手機號錯誤" |
| @StringLengthFieldValidator | 字符串長度 | minLength="6", maxLength="20", trim=true |
| @ExpressionValidator | OGNL 表達式 | expression="password == confirmPassword" |
| @Validations | 分組多規則 | requiredStrings={@RequiredStringValidator(...)} |
| @CustomValidator | 自定義驗證器 | type="myValidator", fieldName="field" |
public class RegisterAction extends ActionSupport {
private String username, password, email, phone;
@Validations(
requiredStrings = {
@RequiredStringValidator(fieldName="username", message="用戶名必填", trim=true),
@RequiredStringValidator(fieldName="password", message="密碼必填")
},
stringLengthFields = {
@StringLengthFieldValidator(fieldName="username", minLength="3", maxLength="16")
},
regexFields = {
@RegexFieldValidator(fieldName="email", expression="^[\\w.-]+@[\\w.-]+\\.\\w+$", message="郵箱格式錯誤"),
@RegexFieldValidator(fieldName="phone", expression="^1[3-9]\\d{9}$", message="手機號格式錯誤")
}
)
@Action(value="register", results={
@Result(name="success", location="welcome.jsp"),
@Result(name="input", location="register.jsp")
})
public String register() {
userService.register(username, password, email, phone);
return SUCCESS;
}
}
@Conversion // 類級別啟用類型轉換
public class OrderAction extends ActionSupport {
@CreateIfNull(value=true) // 自動實例化集合
@Element(value=OrderItem.class) // 集合泛型類型
private List items;
@Key(value=Long.class) // Map Key 類型
@KeyProperty(value="id") // Map Key 來源屬性
private Map productMap;
@TypeConversion(rule=ConversionRule.COLLECTION, converter="com.my.DateConverter")
public void setCreateTime(Date time) { this.createTime = time; }
}
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
<init-param>
<param-name>struts.devMode</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>struts.convention.action.packages</param-name>
<param-value>com.myapp.action</param-value>
</init-param>
</filter>