package cn.com.leadfar.struts2.actions;
publicclass user {
privateintid;
private string
username;
password;
privateintage;
address;
public string getusername() {
returnusername;
}
publicvoid setusername(string username) {
this.username = username;
public string getpassword() {
returnpassword;
publicvoid setpassword(string password) {
this.password = password;
publicint getage() {
returnage;
publicvoid setage(int
age) {
this.age = age;
public string getaddress() {
returnaddress;
publicvoid setaddress(string address) {
this.address = address;
publicint getid() {
returnid;
publicvoid setid(int
id) {
this.id = id;
}
假如要寫一個action,用來添加user。
第一種做法是直接在action中定義所有需要的屬性,然後在jsp中直接用屬性名稱來送出資料:
useraction:
publicclass useraction {
public string add(){
user user =
new user();
user.setid(id);
user.setusername(username);
user.setpassword(password);
user.setage(age);
user.setaddress(address);
new usermanager().adduser(user);
return"success";
add_input.jsp:
<form
action="test/user.action"
method="post">
<input type="hidden"
name="method:add">
username:<input
type="text"
name="username"><br/>
password:<input
name="password"><br/>
age:<input
name="age"><br/>
address:<input
name="address"><br/>
<input type="submit"
name="submit"
value="添加使用者">
</form><br/>
上述做法不好之處是:如果實體類的屬性非常多,那麼action中也要定義相同的屬性。
第二種做法是将user對象定義到useraction中,然後在jsp中通過user屬性來給user指派:
private user
user;
public user getuser() {
returnuser;
publicvoid setuser(user user) {
this.user = user;
name="user.username"><br/>
name="user.password"><br/>
name="user.age"><br/>
name="user.address"><br/>
這種做法不好的地方是:jsp頁面上表單域中的命名變得太長
第三種做法是利用modeldriven機制,讓useraction實作一個modeldriven接口,同時實作接口中的方法:getmodel()。如下所示:
publicclass useraction
implements modeldriven{
@override
public object getmodel() {
if(user ==
null){
user =
}
jsp的代碼如下:
可見,第三種做法是比較好的,action和jsp寫起來都比較簡單。
modeldriven背後的機制就是valuestack。界面通過:username/age/address這樣的名稱,就能夠被直接指派給user對象,這證明user對象正是valuestack中的一個root對象!
那麼,為什麼user對象會在valuestack中呢?它是什麼時候被壓入valuestack的呢?答案是:modeldriveninterceptor。modeldriveninterceptor是預設的攔截器鍊的一部分,當一個請求經過modeldriveninterceptor的時候,在這個攔截器中,會判斷目前要調用的action對象是否實作了modeldriven接口,如果實作了這個接口,則調用getmodel()方法,并把傳回值(本例是傳回user對象)壓入valuestack。
請看modeldriveninterceptor的代碼:
publicclass
modeldriveninterceptor extends abstractinterceptor {
protectedbooleanrefreshmodelbeforeresult
= false;
publicvoid setrefreshmodelbeforeresult(boolean
val) {
this.refreshmodelbeforeresult
= val;
public string intercept(actioninvocation invocation)
throws exception {
object action = invocation.getaction();
if (action
instanceof modeldriven) {
modeldriven modeldriven = (modeldriven) action;
valuestack stack = invocation.getstack();
object model = modeldriven.getmodel();
if (model !=
null) {
stack.push(model);
}
if (refreshmodelbeforeresult)
{
invocation.addpreresultlistener(new refreshmodelbeforeresult(modeldriven, model));
}
return invocation.invoke();
從modeldriveninterceptor中,即可以看到model對象被壓入valuestack中!
其中的refreshmodelbeforeresult是為了接下來描述的一個問題而提供的解決方法。
public object
getmodel() {
if(user
== null){
//user.setusername("這是原來的user對象");
public string updateinput(){
//根據id,查詢資料庫,得到user對象
user =
new usermanager().finduserbyid(user.getid());
return"update_input";
上述代碼中,new usermanager().finduserbyid(user.getid());這一行,将從資料庫中查詢相應的記錄,同時轉換為user對象傳回。而return “update_input”;将轉向更新顯示頁面。
更新頁面如下:
name="method:update">
id:<input
name="id"
value="<s:propertyvalue="id"/>"><br/>
name="username"
value="<s:propertyvalue="username"/>"><br/>
name="password"
value="<s:propertyvalue="password"/>"><br/>
name="age"
value="<s:propertyvalue="age"/>"><br/>
name="address"
value="<s:propertyvalue="address"/>"><br/>
value="更新使用者">
上述代碼運作起來之後,你在更新界面上将看不到資料(id屬性有值,其它屬性無顯示)。關鍵的原因是在執行到updateinput之前,user對象(在getmode()方法中建立的對象)被壓到valuestack中,這時候,useraction和valuestack都指向同一個user對象;但緊接着,useraction中的user被一個新的user對象覆寫,這時候,useraction和valuestack不再指向同一個user對象!valuestack中是舊的user對象,而useraction中是新的user對象!我們在jsp中,直接通過username/address等直接通路,當然是要通路valuestack中的舊user對象,是以它們的屬性都是空的(id屬性除外)!
了解上述問題很重要,當你了解了問題,那麼問題的解決方法就可以有很多了:
比如,你可以把新對象的屬性拷貝到舊對象上;比如,你可以先把舊對象從valuestack中移除,然後再把新對象壓入valuestack等……
在最新的struts2版本中,modeldriveninterceptor提供了一個配置參數:refreshmodelbeforeresult,隻要将它定義為true,上述問題就被解決了!struts2的解決方案就是:先把舊的model對象從valuestack中移除,然後再把新的model對象壓入valuestack!