ModelDriven:模型驅動,對所有action的模型對象進行批處理.
我們在開發中, 在action中一般是用實體對象,然后給實體對象get,set方法。
RegAction{
User user ;
//get/set
}
然后在jsp頁面中給action中的user屬性綁定值是通過如下方式
<s:textfield name="user.name" />
<s:textfield name="user.age" />
<s:textfield name="user.birthday" />
這樣都要加上user.因為在值棧中action進入值棧的時候,值棧中存儲的值就是以user.name這種形式存在的,所以ognl搜索值棧的時候,也要按這個名字來搜索。
這樣就 比較麻煩,于是就引入了模型驅動。
引入模型驅動后在jsp頁面綁定屬性值的時候就可以不用加上user. ?如:
<s:textfield name="name" />
<s:textfield name="age" />
<s:textfield name="birthday" />
原理是什么:ognl在搜索name值的時候,會把模型驅動user壓入棧頂。ognl在值棧掃描的時候,會從上往下找,這樣就會搜到user中的name,等等
?是模型攔截器把模型壓入棧頂的。
?
<html><head><title>reg.jsp</title></head><body><s:actionerror/><s:form namespace="/md" action="MdAction_reg" method="post" theme="xhtml" validate="true"><s:textfield name="name" label="UserName" /><s:textfield name="age" label="UserAge" /><s:submit /></s:form></body> </html>
?
user類
public class User {private Integer id ;private String name ;private Integer age ;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String toString() {return "User("+id+","+name + ","+ age + ")";} }
?
/*** MdAction:某型驅動*/ public class MdAction extends ActionSupport implements ModelDriven<User>,Preparable {
private String name;
由于使用了模型驅動,user處于棧頂,
user中也有name,那么jsp頁面綁定的name是user中name,并不是這里的name,所以該name值為null,
同理在修改功能傳id的時候,如果user中有id屬性,而在action中也定義了一個id來接收該參數,這樣id也接收不到值
,因為使用了模型驅動后,模型驅動攔截器會把id的值傳給user中的id,而不是action中的id屬性,為了解決這個問題,需要把action中接收參數id的屬性定義為別的名稱。
比如uid,同時修改jsp中的傳參為uid,這樣就解決了這個問題。這是在使用模型驅動的時候需要注意的地方。
private User user = new User();屬性user,模型驅動棧頂的對象
public String reg() {return "success";}@SkipValidationpublic String toRegView() {System.out.println("toRegView");return "regView";} public User getModel() {return user;}public String getName() {return name;}public void setName(String name) {this.name = name;}
?
? ? ? public User getModel() {
? ? ? ? ? return user;//這里返回的就是action中的屬性user,如果在action中的其他方法里,使用了User user=new User(),那么這個user對象就不是模型驅動的的對象,
也就是不處在棧頂。即使把當前new出的user賦值給屬性user也不行,因為在值棧中是通過引用來實現,即值棧中是對象的地址。
? ? ? }
? ? ? public String Edit()
?{
User u = new User();
u.setId(uid);
u.setName("jerry");
u.setAge(30);
user = u ;注意,這里的user并不是棧頂的user,引用已經指向了新對象u
如果要把u對象放到棧頂,可以手動的push
ServletActionContext.getContext().getValueStack().push(u) ;//把u對象放到棧頂,那么執行修改時回顯的就是該對象的數據。
}
}
?
上面的方法是手動把u對象壓入棧頂,還有一種方法可以解決這個問題。
?模型驅動攔截器的高級應用:
struts在調用模型驅動攔截器的之前會調用prepare攔截器,prepare攔截器中會調用一個prepare方法,該方法在模型驅動攔截器之前調用,也就是在模型驅動
攔截器中的getModel方法之前執行,getModel方法返回的就是棧頂的對象,那么可以在prepare中把getModel方法中要返回到棧頂的對象給換掉,也就是重新引用。
這樣就不用手動的push到棧頂了。
?
/*** MdAction:某型驅動*/ public class MdAction extends ActionSupport implements ModelDriven<User>,Preparable {private static final long serialVersionUID = -6933309304624396640L;private String name;private Integer uid ;private User user = new User();//模型驅動的getModel方法返回到棧頂的對象。userprivate List<User> userList ;public String reg() {return "success";}@SkipValidationpublic String toRegView() {System.out.println("toRegView");return "regView";}/*** 查詢所有用戶*/public String findAllUsers(){userList = new ArrayList<User>();User u = null ;for(int i= 0 ; i < 10 ; i ++){u = new User();u.setId(1 + i);u.setName("tom" + i);u.setAge(20 + i);userList.add(u);}return "userListView";}public String edit(){return "editView" ;}// public User getModel() {return user;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<User> getUserList() {return userList;}public void setUserList(List<User> userList) {this.userList = userList;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}/*** 該方法在getModel之前運行,在modelDriven攔截器之前先運行*/public void prepareEdit() throws Exception { 該命名規則說明在執行Edit的時候才會執行該方法。// User u = new User();u.setId(uid);u.setName("jerry");u.setAge(30); user = u ;把user對象換掉,換成新new出的對象。}public void prepare() throws Exception {} }
?
但是由于使用的是默認攔截器棧,prepare攔截器在params攔截器之前執行,這樣在編輯的時候,就無法獲取到id值,因為此時還沒有經過參數params爛機器的處理。
所以這種方法不能使用默認的攔截器棧,struts-default.xml提供了一個攔截器棧paramsPrepareParamsStack,所以要引入該攔截器棧。
<struts><package name="MdPkg" namespace="/md" extends="struts-default"><action name="MdAction_*" class="struts2.modeldriven.MdAction" method="{1}"><result name="success">/md/reg.jsp</result><result name="regView">/md/reg.jsp</result><result name="editView">/md/edit.jsp</result><result name="userListView">/md/userList.jsp</result><interceptor-ref name="paramsPrepareParamsStack" /> 不能引入默認攔截器棧,要在prepare攔截器之前執行params攔截器</action></package> </struts>
?
?
模型驅動的應用:
假設在開發中有很多實體對象,比如用戶類User,訂單類Order,部門類Department等等
對應的有很多Action,如UserAction,OrderAction,DepartmentAction等等。
UserAction{
User user;
}
OrderAction{
Order order;
}
如果在開發中需要開發一個處理模型的攔截器
ProcessModelInterceptor{
if(action instanceof(UserAction){
Object o=getUser();//得到該實體類的對象
}
? ? ? else?if(action instanceof(OrderAction){
Order o=getOrder();//得到該實體類的對象
}
? ? ? ....
? ? 這樣如果有很多的類幾十甚至上百個實體類,都要這么去判斷,將是十分的麻煩。引入了模型驅動后就解決了這個問題。
}
?
引入模型驅動后的做法:模型驅動的好處是對所以的action模型對象進行批處理
ProcessModelInterceptor{
if(action instanceof(ModelDriven){//判斷action是否實現了模型驅動接口
Object o=((ModelDriven)action).getModel();//得到action的模型對象
然后用反射獲取action中的信息
}
}
?