来自:
http://blog.csdn.net/P_Doraemon/article/details/54024032?locationNum=6&fps=1
所谓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;
- }
- }
- 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;
- }
- }
- 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;
- }
- }
- <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/>
- <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;
- }
- }
- 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;
- }
- }
- <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/>
- <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/>
第三种做法是利用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;
- }
- }
- 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;
- }
- }
- <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/>
- <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的代码:
- @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中!
- @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是为了接下来描述的一个问题而提供的解决方法。
理解常见的陷阱及其解决方法
假设我们要更新一个实体对象,那么第一步首先是打开更新界面,请看下述模拟打开更新界面的代码:
- 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”;
- }
- }
- public class UserAction implements ModelDriven{ <br>
- 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”;将转向更新显示页面。
更新页面如下:
- <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/>
- <form action="test/user.action" method="post"> <br>
- <input type="hidden" name="method:update"> <br>
- id:<input type="text" name="id" value="<s:property value="id"/>"> <br/> <br>
- username:<input type="text" name="username" value="<s:property value="username"/>"> <br/> <br>
- password:<input type="text" name="password" value="<s:property value="password"/>"> <br/> <br>
- age:<input type="text" name="age" value="<s:property value="age"/>"> <br/> <br>
- address:<input type="text" name="address" value="<s:property value="address"/>"> <br/> <br>
- <input type="submit" name="submit" value="更新用户"> <br>
- </form> <br/>
理解上述问题很重要,当你理解了问题,那么问题的解决方法就可以有很多了:
比如,你可以把新对象的属性拷贝到旧对象上;比如,你可以先把旧对象从ValueStack中移除,然后再把新对象压入ValueStack等……
在最新的struts2版本中,ModelDrivenInterceptor提供了一个配置参数:refreshModelBeforeResult,只要将它定义为true,上述问题就被解决了!struts2的解决方案就是:先把旧的model对象从ValueStack中移除,然后再把新的model对象压入ValueStack!
再看下一个例子会更加清楚:
MyJsp.jsp:
- <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>
- <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>
- 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”;
- }
- }
- 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";
- }
- }
- <body>
- <s:property value=“{name}”/><br/>
- <s:property value=“{dog.name}”/><br/>
- <s:iterator value=“#users”>
- <s:property value=“name”/>
- <s:property value=“#root[2].name”/><br/>
- </s:iterator>
- <s:property value=“name”/><br/>
- <s:property value=“#root[0].name”/><br/>
- <s:property value=“#root[1].name”/><br/>
- <s:property value=“#root[2].name”/><br/>
- <s:property value=“#root[0]”/><br/>
- <s:property value=“#root[1]”/><br/>
- <s:property value=“#root[2]”/><br/>
- <s:property value=“#root[3]”/><br/>
- <s:property value=“m()”/><br/>
- <s:property value=“model.name”/><br/>
- <s:property value=“model.dog.name”/><br/>
- <s:debug></s:debug>
- </body>
- <body>
- <s:property value="{name}"/><br/>
- <s:property value="{dog.name}"/><br/>
- <s:iterator value="#users">
- <s:property value="name"/>
- <s:property value="#root[2].name"/><br/>
- </s:iterator>
- <s:property value="name"/><br/>
- <s:property value="#root[0].name"/><br/>
- <s:property value="#root[1].name"/><br/>
- <s:property value="#root[2].name"/><br/>
- <s:property value="#root[0]"/><br/>
- <s:property value="#root[1]"/><br/>
- <s:property value="#root[2]"/><br/>
- <s:property value="#root[3]"/><br/>
- <s:property value="m()"/><br/>
- <s:property value="model.name"/><br/>
- <s:property value="model.dog.name"/><br/>
- <s:debug></s:debug>
- </body>