1. 程式人生 > >Struts2中的ModelDriven機制及其運用

Struts2中的ModelDriven機制及其運用

所謂ModelDriven,意思是直接把實體類當成頁面資料的收集物件。比如,有實體類User如下:

[html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package cn.com.leadfar.struts2.actions;  
  2. public class User {  
  3.     private int id;  
  4.     private String username;  
  5.     private String password;  
  6.     private int age;  
  7.     private String address;  
  8.     public String getUsername() {  
  9.        return username;  
  10.     }  
  11.     public void setUsername(String username) {  
  12.        this.username = username;  
  13.     }  
  14.     public String getPassword() {  
  15.        return password;  
  16.     }  
  17.     public void setPassword(String password) {  
  18.        this.password = password;  
  19.     }  
  20.     public int getAge() {  
  21.        return age;  
  22.     }  
  23.     public void setAge(int age) {  
  24.        this.age = age;  
  25.     }  
  26.     public String getAddress() {  
  27.        return address;  
  28.     }  
  29.     public void setAddress(String address) {  
  30.        this.address = address;  
  31.     }  
  32.     public int getId() {  
  33.        return id;  
  34.     }  
  35.     public void setId(int id) {  
  36.        this.id = id;  
  37.     }  
  38. }  
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:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicclass UserAction {  
  2.     privateint id;  
  3.     private String username;  
  4.     private String password;  
  5.     privateint age;  
  6.     private String address;   
  7.     public String add(){  
  8.        User user = new User();  
  9.        user.setId(id);  
  10.        user.setUsername(username);  
  11.        user.setPassword(password);  
  12.        user.setAge(age);  
  13.        user.setAddress(address);  
  14.        new UserManager().addUser(user);  
  15.        return“success”;  
  16.     }  
  17.     publicint getId() {  
  18.        return id;  
  19.     }  
  20.     publicvoid setId(int id) {  
  21.        this.id = id;  
  22.     }  
  23.     public String getUsername() {  
  24.        return username;  
  25.     }  
  26.     publicvoid setUsername(String username) {  
  27.        this.username = username;  
  28.     }  
  29.     public String getPassword() {  
  30.        return password;  
  31.     }  
  32.     publicvoid setPassword(String password) {  
  33.        this.password = password;  
  34.     }  
  35.     publicint getAge() {  
  36.        return age;  
  37.     }  
  38.     publicvoid setAge(int age) {  
  39.        this.age = age;  
  40.     }  
  41.     public String getAddress() {  
  42.        return address;  
  43.     }  
  44.     publicvoid setAddress(String address) {  
  45.        this.address = address;  
  46.     }  
  47. }  
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:

[html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <formaction=“test/user.action”method=“post”>
  2.         <inputtype=“hidden”name=“method:add”>
  3.         username:<inputtype=“text”name=“username”><br/>
  4.         password:<inputtype=“text”name=“password”><br/>
  5.         age:<inputtype=“text”name=“age”><br/>
  6.         address:<inputtype=“text”name=“address”><br/>
  7.         <inputtype=“submit”name=“submit”value=“新增使用者”>
  8. </form><br/>
<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:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicclass UserAction {  
  2.     private User user;  
  3.     public String add(){  
  4.        new UserManager().addUser(user);  
  5.        return“success”;  
  6.     }  
  7.     public User getUser() {  
  8.        return user;  
  9.     }  
  10.     publicvoid setUser(User user) {  
  11.        this.user = user;  
  12.     }  
  13. }  
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: [html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <formaction=“test/user.action”method=“post”>
  2.     <inputtype=“hidden”name=“method:add”>
  3.     username:<inputtype=“text”name=“user.username”><br/>
  4.     password:<inputtype=“text”name=“user.password”><br/>
  5.     age:<inputtype=“text”name=“user.age”><br/>
  6.     address:<inputtype=“text”name=“user.address”><br/>
  7.     <inputtype=“submit”name=“submit”value=“新增使用者”>
  8. </form><br/>
<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()。如下所示:[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicclass UserAction implements ModelDriven{  
  2.     private User user;  
  3.     @Override
  4.     public Object getModel() {  
  5.        if(user == null){  
  6.            user = new User();  
  7.        }  
  8.        return user;  
  9.     }  
  10.     public String add(){  
  11.        new UserManager().addUser(user);  
  12.        return“success”;  
  13.     }  
  14.     public User getUser() {  
  15.        return user;  
  16.     }  
  17.     publicvoid setUser(User user) {  
  18.        this.user = user;  
  19.     }  
  20. }  
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的程式碼如下:
[html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <formaction=“test/user.action”method=“post”>
  2.     <inputtype=“hidden”name=“method:add”>
  3.     username:<inputtype=“text”name=“username”><br/>
  4.     password:<inputtype=“text”name=“password”><br/>
  5.     age:<inputtype=“text”name=“age”><br/>
  6.     <inputtype=“submit”name=“submit”value=“新增使用者”>
  7. </form><br/>
<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寫起來都比較簡單。

注意:(1)一個請求在最終到達Action的方法之前,Action物件本身會被壓入ValueStack(實際上就是放到ValueStack的CompoundRoot中),所以Action物件是CompoundRoot中的一個元素(2)這裡的user必須不能為null才會被壓入到棧頂中!!

ModelDriven機制

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

那麼,為什麼user物件會在ValueStack中呢?它是什麼時候被壓入ValueStack的呢?答案是:ModelDrivenInterceptor。ModelDrivenInterceptor是預設的攔截器鏈的一部分,當一個請求經過ModelDrivenInterceptor的時候,在這個攔截器中,會判斷當前要呼叫的Action物件是否實現了ModelDriven介面,如果實現了這個介面,則呼叫getModel()方法,並把返回值(本例是返回user物件)壓入ValueStack。

請看ModelDrivenInterceptor的程式碼:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. @Override
  2. public String intercept(ActionInvocation invocation) throws Exception {    
  3.     //獲取當前正在執行的Action  
  4.     Object action = invocation.getAction();     
  5.     //如果Action實現了ModelDriven介面  
  6.     if (action instanceof ModelDriven) {    
  7.         ModelDriven modelDriven = (ModelDriven) action;    
  8.         ValueStack stack = invocation.getStack();    
  9.         //通過getModel方法獲取model  
  10.          Object model = modelDriven.getModel();    
  11.         //如果model不為null則把model壓入值棧  
  12.         if (model != null) {    
  13.             stack.push(model);    
  14.         }    
  15.         if (refreshModelBeforeResult) {    
  16.         //在執行Result之前是否要更新model物件,預設為false  
  17.             invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));    
  18.         }    
  19.     }    
  20.      return invocation.invoke();//呼叫下一個攔截器  
  21. }    
  22. 從ModelDrivenInterceptor中,即可以看到model物件被壓入ValueStack中!  
@Override  
public String intercept(ActionInvocation invocation) throws Exception {  
           
    //獲取當前正在執行的Action  
    Object action = invocation.getAction();   
  
    //如果Action實現了ModelDriven介面  
    if (action instanceof ModelDriven) {  
        ModelDriven modelDriven = (ModelDriven) action;  
        ValueStack stack = invocation.getStack();  
  
        //通過getModel方法獲取model  
         Object model = modelDriven.getModel();  
     
        //如果model不為null則把model壓入值棧  
        if (model != null) {  
            stack.push(model);  
        }  
  
        if (refreshModelBeforeResult) {  
        //在執行Result之前是否要更新model物件,預設為false  
            invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));  
        }  
    }  
     return invocation.invoke();//呼叫下一個攔截器  
}  
從ModelDrivenInterceptor中,即可以看到model物件被壓入ValueStack中!

其中的refreshModelBeforeResult是為了接下來描述的一個問題而提供的解決方法。

理解常見的陷阱及其解決方法

假設我們要更新一個實體物件,那麼第一步首先是開啟更新介面,請看下述模擬開啟更新介面的程式碼:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicclass UserAction implements ModelDriven{  
  2.     private User user;  
  3.     public Object getModel() {  
  4.        if(user == null){  
  5.            user = new User();//user.setUsername(“這是原來的User物件”);
  6.        }  
  7.        return user;  
  8.     }  
  9.     public String updateInput(){  
  10.        //根據ID,查詢資料庫,得到User物件
  11.        user = new UserManager().findUserById(user.getId());  
  12.        return“update_input”;  
  13.     }  
  14. }  
public class UserAction implements ModelDriven{ 
private User user;
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”;將轉向更新顯示頁面。

更新頁面如下:

[html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <formaction=“test/user.action”method=“post”>
  2.     <inputtype=“hidden”name=“method:update”>
  3.     id:<inputtype=“text”name=“id”value=”<s:property value=”id“/>”><br/>
  4.     username:<inputtype=“text”name=“username”value=”<s:property value=”username“/>”><br/>
  5.     password:<inputtype=“text”name=“password”value=”<s:property value=”password“/>”><br/>
  6.     age:<inputtype=“text”name=“age”value=”<s:property value=”age“/>”><br/>
  7.     address:<inputtype=“text”name=“address”value=”<s:property value=”address“/>”><br/>
  8.     <inputtype=“submit”name=“submit”value=“更新使用者”>
  9. </form><br/>
<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!

再看下一個例子會更加清楚:

MyJsp.jsp:

[html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <body>
  2.   <formaction=“user_test1.action”method=“post”>
  3.     username:<inputtype=“text”name=“name”><br/>
  4.     dogname:<inputtype=“text”name=“dog.name”><br/>
  5.     <inputtype=“submit”>
  6.     <s:debug></s:debug>
  7.   </form><br/>
  8. </body>
<body>
  <form action="user_test1.action" method="post">  
    username:<input type="text" name="name"> <br/>  
    dogname:<input type="text" name="dog.name"> <br/>  
    <input type="submit"> 
    <s:debug></s:debug> 
  </form> <br/>  
</body>
UserAction:
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicclass UserAction extends ActionSupport implements ModelDriven<User> {  
  2.     private User user;  
  3.     @Override
  4.     public User getModel() {  
  5.         // TODO Auto-generated method stub
  6.         if(user == null){  
  7.             user = new User();  
  8.         }  
  9.         return user;  
  10.     }  
  11.     public String test1(){  
  12.         System.out.println(user.getName());  
  13.         System.out.println(user.getDog().getName());  
  14.         List list = new ArrayList();    
  15.         for(int i=0; i<10; i++){    
  16.             User user = new User();    
  17.             user.setName(”User”+i);    
  18.             list.add(user);    
  19.         }    
  20.         ActionContext.getContext().put(”users”, list);          
  21.         User u = new User();    
  22.         u.setName(”趙毅”);    
  23.         ActionContext.getContext().getValueStack().push(u);     
  24.         return“test1”;  
  25.     }  
  26.     public String m(){  
  27.         return“yes”;  
  28.     }  
  29. }  
public class UserAction extends ActionSupport implements ModelDriven<User> {

    private User user;

    @Override
    public User getModel() {
        // TODO Auto-generated method stub
        if(user == null){
            user = new User();
        }
        return user;
    }

    public String test1(){
        System.out.println(user.getName());
        System.out.println(user.getDog().getName());

        List list = new ArrayList();  
        for(int i=0; i<10; i++){  
            User user = new User();  
            user.setName("User"+i);  
            list.add(user);  
        }  

        ActionContext.getContext().put("users", list);        

        User u = new User();  
        u.setName("趙毅");  
        ActionContext.getContext().getValueStack().push(u);   

        return "test1";
    }

    public String m(){
        return "yes";
    }

}
getData.jsp: [html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <body>
  2.        <s:propertyvalue=“{name}”/><br/>
  3.     <s:property

    相關推薦

    strutsModelDriven()介面 Struts2ModelDriven機制及其運用、refreshModelBeforeResult屬性解決的問題

    Struts2中的ModelDriven機制及其運用、refreshModelBeforeResult屬性解決的問題   1.為什麼需要ModelDriven? 所謂ModelDriven,意思是直接把實體類當成頁面資料的收集物件。比如,有實體類User如下:

    Struts2ModelDriven機制及其運用

    所謂ModelDriven,意思是直接把實體類當成頁面資料的收集物件。比如,有實體類User如下: [html] view plain copy print?package cn.com.leadfar.struts2.actions;  public c

    遊戲Buff機制及其實際運用

    首先我想說的是,這是一套機制,並不是單獨的一個系統,所謂機制就是一種從邏輯思想到程式碼實現的小竅門的組合,只有當你把它運用到一個實際專案中去了,它才能幫助你建立一個系統。我不敢說它是最好的,但這套東西幫我完成了一個又一個專案的製作,我覺得現在可以簡單的拿出來和大家分享下思維

    Struts2ModelDriven的使用

    package com.lsc.alan.action; import com.lsc.alan.vo.User; import com.opensymphony.xwork2.ModelDriven; /** * 使用模型驅動來接受使

    Struts2ModelDriven的作用以及遍歷棧頂的list,map

    把當前的類中實體類物件壓入棧頂 public T getModel() { // TODO Auto-generated method stub returnthis.t; } <s:aac

    struts2進階二---OGNL表示式與OGNL表示式在struts2運用

    OGNL(物件檢視導航語言)表示式 (EL表示式就是) OGNL不僅僅可以檢視導航還支援比EL表示式更加豐富的功能 使用: 準備工作1:導包(struts包裡面已經有了) 準備工作2: ognl基本語法: 1:取值 取出root中的屬性值

    Struts2資料封裝機制

    Struts2當中資料封裝的三種機制:屬性驅動、標籤驅動、模型驅動。下面來一一介紹。 一、屬性驅動 1、需要提供對應屬性的set方法進行資料的封裝。 2、表單的哪些屬性需要封裝資料,那麼在對應的Act

    struts2的異常對映處理機制

    首先在struts2中有兩種異常處理機制:區域性異常對映和全域性異常對映。 拿經典的使用者登入功能來說: 一:區域性異常: 1:首先我們的登入介面:表單交由exAction.action 處理。 &

    struts2配置自定義攔截器放行多個方法

    return med ttr limit ring req tac cat invoke 源碼: 自定義的攔截器類: //自定義攔截器類:LoginInterceptor ; package com.java.action.interceptor; import j

    struts2struts2的流接收與流發送

    hive req nal oct true 中文名 tom auto 標示 【前言】在我們的struts2後端中,實現流的接收和發送。就能夠實現向server傳視頻流以及下載圖片。 【流接收】 如今舉一個傳公鑰的樣例。struts2用一個action接收Key,而Key

    struts2的返回類型、struts的標簽庫、struts2完成國際化

    let 頁面 const patch red struts2標簽 property 單選 bmi struts2的返回類型:在jsp-servlet中, 返回的類型主要有 轉發, 重定向; 轉發主要是RequestDispatcher的forward方法來進行操作的req.

    實體、實體集及其運用

    sys val can har 賦值 center 過程 num red 一、實體 實體 在C#中的寫法 在C#中 寫法(1): public class UserInfo { public int UserID { get; se

    struts2訪問servlet API

    auto etl sid ict htm ngx dff .com zhong iOS%20%E7%96%91%E9%9A%BE%E6%9D%82%E7%97%87%E2%80%94%20%E2%80%94%20%20%E6%94%B6%E5%88%B0%E6%8E%A8%

    Eclipse插件的運用

    bug 箭頭 com eclips ips lib debug city ins 1. hotcode2.jar 支持java代碼熱部署,改了本地java代碼不需要重新部署生效,可以節省開發時間,提高開發效率。 安裝方法: 到help -- install new so

    struts2獲取表單數據的方式

    處理 struts2 對象 進行 數據模型 模型驅動 屬性 表單 基本 在最近學習的struts2,struts2獲取表單的方式主要有兩種 一:屬性驅動 屬性驅動主要指的是通過字段進行數據的傳輸,其中包括兩種情況 1:與基本數據類型的屬性對應 2:直接使用域對象 二:模型驅

    Serializable在C#的作用及其優點

    p s mst access pen eat mat zab ref hal 原文發布時間為:2009-10-27 —— 來源於本人的百度文章 [由搬家工具導入]Serializalbe - Enable the object can be Serialized into

    走進Struts2(一) — Struts2的執行流程及其工作原理

    管理 npr clean 核心部分 由於 nco 方式 中間 con Struts2是一套很優秀的Web應用框架,實現優雅、功能強大、使用簡潔。能夠說是Struts2是一款很成熟的MVC架構。 在我們學習Struts2時,最好是先學習它的執行流程、核心概念。從中

    自己定義struts2action類型轉換器

    ansi work row 接受 4.0 open 技術 oos lang DateAction.java中代碼例如以下: package com.itheima.action; import java.util.Date; public class Da

    Cocos2d-XMenu的綜合運用

    cond edi ros log 程序 cal coo 項目 綜合 今天將曾經寫的代碼和項目集成到了一個菜單中,能夠通過菜單切換到曾經做的項目 程序的project文件夾 主要代碼分析: LessonMenu.h中實現創建菜單,遍歷菜單通過菜單切換

    Struts2動態方法調用

    .com log ima struts2 http als ges XML 配置 1 . 查看默認配置,是否為:true 2.如果為false 可以通過struts.xml進行相關的配置: Struts2中動態方法調用