struts 2の3つの方法で要求パラメータを受け入れる

12824 ワード

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; 

    } 

    

    

} 

 

アクションを書く場合は、Userを追加します.
1つ目の方法は、アクションで必要なすべての属性を直接定義し、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でも同じ属性を定義することです.
 
 
2つ目の方法は、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ページのフォームドメインのネーミングが長すぎることです.
 
第3の方法は、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 /> 
 

 
3つ目の方法は比較的良く、ActionもJSPも簡単に書けます.
 
 
ModelDrivenの背後にあるメカニズムは?
 
ModelDrivenの背後にあるメカニズムはValueStackです.インタフェースは、username/age/addressのような名前で、userオブジェクトに直接割り当てることができます.これは、userオブジェクトがValueStackのrootオブジェクトであることを証明します.
 
では、なぜuserオブジェクトがValueStackにあるのでしょうか.いつバリュースタックに押し込まれたのですか?答えは:ModelDrivenInterceptor(Interceptorの概念については、後続の章の説明を参照してください).ModelDrivenInterceptorはデフォルトのブロッキングチェーンの一部であり、ある要求がModelDrivenInterceptorを通過すると、このブロッキングでは、現在呼び出すActionオブジェクトがModelDrivenインタフェースを実装しているかどうかを判断し、このインタフェースが実装されている場合はgetModel()メソッドを呼び出し、戻り値(この例ではuserオブジェクトを返す)をValue Stackに押し込む.
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から、モデルオブジェクトが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とValue Stackは同じuserオブジェクトを指さなくなります!ValueStackでは古いuserオブジェクト、UserActionでは新しいuserオブジェクト!私たちはJSPで、直接username/addressなどを通じて直接アクセスします.もちろんValueStackの古いuserオブジェクトにアクセスするので、それらの属性はすべて空です(id属性を除く)!
 
上記の問題を理解することが重要です.問題を理解すれば、問題の解決方法はたくさんあります.
たとえば、新しいオブジェクトのプロパティを古いオブジェクトにコピーすることができます.たとえば、古いオブジェクトをValueStackから削除してから、新しいオブジェクトをValueStackに押し込むなど...
 
最新のstruts 2バージョンでは、ModelDrivenInterceptorによって構成パラメータが提供されています.refreshModelBeforeResultです.これをtrueと定義すれば、上記の問題は解決されます.struts 2の解決策は、古いモデルオブジェクトをValueStackから削除してから、新しいモデルオブジェクトをValueStackに押し込むことです.