struts 2の3つの方法で要求パラメータを受け入れる
12824 ワード
ModelDriven
なぜModelDrivenが必要なのか
ModelDrivenとは,実体クラスを直接ページデータの収集対象とすることを意味する.たとえば、エンティティークラスUserは次のようになります.
アクションを書く場合は、Userを追加します.
1つ目の方法は、アクションで必要なすべての属性を直接定義し、JSPで直接属性名でデータをコミットすることです.
上記のやり方が悪いのは、エンティティクラスの属性が非常に多い場合、Actionでも同じ属性を定義することです.
2つ目の方法は、UserオブジェクトをUserActionに定義し、JSPでuserプロパティを使用してuserに値を割り当てることです.
このやり方が悪いのは、JSPページのフォームドメインのネーミングが長すぎることです.
第3の方法は、ModelDrivenメカニズムを利用して、UserActionにModelDrivenインタフェースを実現させ、同時にインタフェースの方法:getModel()を実現させることである.次のようになります.
JSPのコードは以下の通りです.
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のコードを参照してください:
ModelDrivenInterceptorから、モデルオブジェクトがValueStackに押し込まれていることがわかります!
その中のrefreshModelBeforeResultは、後述する問題の解決策である.
一般的なトラップとその解決方法を理解する
エンティティオブジェクトを更新する場合、最初のステップはまず更新インタフェースを開きます.次のシミュレーションで更新インタフェースを開くコードを参照してください.
上記コードのうち、new UserManager()である.findUserById(user.getId()); この行は、対応するレコードをデータベースから照会し、Userオブジェクトに変換して返します.そしてreturn"update_input";表示ページの更新に移ります.
更新ページは次のとおりです.
上記のコードが実行されると、更新インタフェースにデータが表示されません(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に押し込むことです.
なぜ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に押し込むことです.