少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          ModelDriven

           

          為什么需要ModelDriven

           

          所謂ModelDriven ,意思是直接把實體類當成頁面數據的收集對象。比如,有實體類User 如下:

           

          package cn.com.leadfar.struts2.actions;

           

          public class User {

              private int id ;

              private String username ;

              private String password ;

              private int age ;

              private String address ;

              public String getUsername() {

                 return username ;

              }

              public void setUsername(String username) {

                 this . username = username;

              }

              public String getPassword() {

                 return password ;

              }

              public void setPassword(String password) {

                 this . password = password;

              }

              public int getAge() {

                 return age ;

              }

              public void setAge( int age) {

                 this . age = age;

              }

              public String getAddress() {

                 return address ;

              }

              public void setAddress(String address) {

                 this . address = address;

              }

              public int getId() {

                 return id ;

              }

              public void setId( int id) {

                 this . id = id;

              }

             

             

          }

           

           

          假如要寫一個Action ,用來添加User 。

          第一種做法是直接在Action 中定義所有需要的屬性,然后在JSP 中直接用屬性名稱來提交數據:

          UserAction:

           

          public class UserAction {

              private int id ;

              private String username ;

              private String password ;

              private int age ;

              private String address ;

           

              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" ;

              }

             

              public int getId() {

                 return id ;

              }

              public void setId( int id) {

                 this . id = id;

              }

              public String getUsername() {

                 return username ;

              }

              public void setUsername(String username) {

                 this . username = username;

              }

              public String getPassword() {

                 return password ;

              }

              public void setPassword(String password) {

                 this . password = password;

              }

              public int getAge() {

                 return age ;

              }

              public void setAge( int age) {

                 this . age = age;

              }

              public String getAddress() {

                 return address ;

              }

              public void setAddress(String address) {

                 this . address = address;

              }

             

          }

           

          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 type = "text" name = "password" > < br />

                  age: < input type = "text" name = "age" > < br />

                  address: < input type = "text" name = "address" > < br />

                  < input type = "submit" name = "submit" value = " 添加用戶 " >

               </ form > < br />

          上述做法不好之處是:如果實體類的屬性非常多,那么Action 中也要定義相同的屬性。

           

           

          第二種做法是將User 對象定義到UserAction 中,然后在JSP 中通過user 屬性來給user 賦值:

          UserAction:

           

          public class UserAction {

             

              private User user ;

             

              public String add(){

           

                 new UserManager().addUser( user );

                

                 return "success" ;

              }

           

              public User getUser() {

                 return user ;

              }

           

              public void setUser(User user) {

                 this . user = user;

              }

             

             

          }

           

          add_input.jsp:

           

               < form action = "test/user.action" method = "post" >

                  < input type = "hidden" name = "method:add" >

                  username: < input type = "text" name = "user.username" > < br />

                  password: < input type = "text" name = "user.password" > < br />

                  age: < input type = "text" name = "user.age" > < br />

                  address: < input type = "text" name = "user.address" > < br />

                  < input type = "submit" name = "submit" value = " 添加用戶 " >

               </ form > < br />

          這種做法不好的地方是:JSP 頁面上表單域中的命名變得太長

           

          第三種做法是利用ModelDriven 機制,讓UserAction 實現一個ModelDriven 接口,同時實現接口中的方法:getModel() 。如下所示:

           

          public class UserAction implements ModelDriven{

             

              private User user ;

             

              @Override

              public Object getModel() {

                 if ( user == null ){

                     user new User();

                 }

                 return user ;

              }

           

              public String add(){

           

                 new UserManager().addUser( user );

                

                 return "success" ;

              }

           

              public User getUser() {

                 return user ;

              }

           

              public void setUser(User user) {

                 this . user = user;

              }

          }

          JSP 的代碼如下:

           

               < form action = "test/user.action" method = "post" >

                  < input type = "hidden" name = "method:add" >

                  username: < input type = "text" name = "username" > < br />

                  password: < input type = "text" name = "password" > < br />

                  age: < input type = "text" name = "age" > < br />

                  < input type = "submit" name = "submit" value = " 添加用戶 " >

               </ form > < br />

           

          可見,第三種做法是比較好的,Action 和JSP 寫起來都比較簡單。

           

           

          ModelDriven 背后的機制?

           

          ModelDriven 背后的機制就是ValueStack 。界面通過:username/age/address 這樣的名稱,就能夠被直接賦值給user 對象,這證明user 對象正是ValueStack 中的一個root 對象!

           

          那么,為什么user 對象會在ValueStack 中呢?它是什么時候被壓入ValueStack 的呢?答案是:ModelDrivenInterceptor (關于Interceptor 的概念,請參考后續章節的說明)。ModelDrivenInterceptor 是缺省的攔截器鏈的一部分,當一個請求經過ModelDrivenInterceptor 的時候,在這個攔截器中,會判斷當前要調用的Action 對象是否實現了ModelDriven 接口,如果實現了這個接口,則調用getModel() 方法,并把返回值(本例是返回user 對象)壓入ValueStack 。

          請看ModelDrivenInterceptor 的代碼:

           

          public class ModelDrivenInterceptor extends AbstractInterceptor {

           

              protected boolean refreshModelBeforeResult false ;

           

              public void setRefreshModelBeforeResult( boolean val) {

                  this . refreshModelBeforeResult = val;

              }

           

              @Override

              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 class UserAction implements ModelDriven{

             

              private User user ;

             

              @Override

              public Object getModel () {

                 if ( user == null ){

                     user new User();

                     //user.setUsername(" 這是原來的 User 對象 ");

                 }

                 return user ;

              }

             

              public String updateInput(){

                

                 // 根據 ID ,查詢數據庫,得到 User 對象

                 user new UserManager().findUserById( user .getId());

                

                

                 return "update_input" ;

              }

           

          上述代碼中,new UserManager().findUserById(user.getId()); 這一行,將從數據庫中查詢相應的記錄,同時轉換為User 對象返回。而return  update_input  ;將轉向更新顯示頁面。

           

          更新頁面如下:

           

               < form action = "test/user.action" method = "post" >

                  < input type = "hidden" name = "method:update" >

                  id: < input type = "text" name = "id" value = "< s:property value = "id" /> "> < br />

                  username: < input type = "text" name = "username" value = "< s:property value ="username" /> "> < br />

                  password: < input type = "text" name = "password" value = "< s:property value ="password" /> "> < br />

                  age: < input type = "text" name = "age" value = "< s:property value = "age" /> "> < br/>

                  address: < input type = "text" name = "address" value = "< s:property value = "address"/> "> < br />

                  < input type = "submit" name = "submit" value = " 更新用戶 " >

               </ form > < br />

           

           

          上述代碼運行起來之后,你在更新界面上將看不到數據(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 !







          引用地址:
          http://blog.csdn.net/zheng2008hua/article/details/6285737

          posted on 2011-12-15 12:44 abin 閱讀(1216) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 江陵县| 武陟县| 九龙坡区| 侯马市| 河北省| 千阳县| 胶州市| 中超| 泰和县| 城市| 连城县| 洛扎县| 鄂伦春自治旗| 法库县| 宜阳县| 宾川县| 呼图壁县| 太仓市| 上蔡县| 肥城市| 金沙县| 雷州市| 高密市| 大洼县| 盘锦市| 灯塔市| 昌吉市| 藁城市| 宁强县| 灌阳县| 文成县| 六盘水市| 白银市| 广州市| 武川县| 上林县| 和静县| 周口市| 凤翔县| 吉木乃县| 河津市|