在 struts.xml 中,package 元素的 namespace 屬性用於區隔不同模組的 Action 路徑,避免衝突。
<package name="mengya" extends="struts-default" namespace="/mymengya">
<action name="register" class="com.mengya.action.RegisterAction">
<result name="success">/show.jsp</result>
<result name="input">/index.jsp</result>
<result name="invalid.token">/index.jsp</result>
<interceptor-ref name="token"/>
<interceptor-ref name="defaultStack"/>
</action>
</package>
namespace="/mymengya" 必須以 / 開頭。action 屬性需包含完整路徑:/mymengya/register.action。實作 com.opensymphony.xwork2.ModelDriven 介面,讓 Action 直接暴露領域模型屬性,JSP 可直接用屬性名綁定,無需 model.property 前綴。
public class RegisterBean {
private String username;
private String password;
// getter/setter 略
}
public class RegisterAction extends ActionSupport implements ModelDriven<RegisterBean> {
private RegisterBean loginBean = new RegisterBean(); // 必須實例化
@Override
public RegisterBean getModel() {
return loginBean;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
<s:form action="/mymengya/register.action" method="post" theme="simple">
<s:textfield name="username" /> <s:fielderror name="username" />
<s:password name="password" /> <s:fielderror name="password" />
<s:submit value="註冊" />
</s:form>
表單欄位 name 直接對應 RegisterBean 的屬性名。
Struts 2 內建 token 攔截器實現「同步器令牌模式」。
<s:form action="/mymengya/register.action" method="post" theme="simple">
<s:token name="register" /> <!-- 生成隱藏欄位 token=register -->
...
</s:form>
<action name="register" class="com.mengya.action.RegisterAction">
<interceptor-ref name="token"/>
<interceptor-ref name="defaultStack"/>
<result name="invalid.token">/index.jsp</result>
...
</action>
<s:token> 生成唯一令牌,同時存入 Session 與表單隱藏欄位。invalid.token 結果。在 Struts 2 國際化資源檔(如 struts.properties 或 global.properties)加入:
struts.messages.invalid.token = 表單不允許重複提交
defaultStack 使用需注意攔截器順序(token 在 defaultStack 之前)。