Struts2的传值方式及原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Struts2的传值方式及原理相关的知识,希望对你有一定的参考价值。

1.普通的传值方式

UserActionForCommonParam类

Action类接收三个参数,分别是id,username,content.

  1. package com.struts.action;  
  2.   
  3. public class UserActionForCommonParam {  
  4.     private int id;  
  5.     private String username;  
  6.     private String content;  
  7.   
  8.     public int getId() {  
  9.         return id;  
  10.     }  
  11.   
  12.     public void setId(int id) {  
  13.         this.id = id;  
  14.     }  
  15.   
  16.     public String getUsername() {  
  17.         return username;  
  18.     }  
  19.   
  20.     public void setUsername(String username) {  
  21.         this.username = username;  
  22.     }  
  23.   
  24.     public String getContent() {  
  25.         return content;  
  26.     }  
  27.   
  28.     public void setContent(String content) {  
  29.         this.content = content;  
  30.     }  
  31.       
  32.     // 从前台页面接收到参数后会在这个方法里打印  
  33.     public String addUser() {  
  34.         System.out.println("ID: " + this.getId());  
  35.         System.out.println("Username: " + this.getUsername());  
  36.         System.out.println("Content: " + this.getContent());  
  37.         return "success";  
  38.     }  
  39. }  


对应的struts.xml

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <!DOCTYPE struts PUBLIC  
  4.         "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"  
  5.         "http://struts.apache.org/dtds/struts-2.3.dtd">  
  6.   
  7. <struts>  
  8.     <constant name="struts.enable.DynamicMethodInvocation" value="true"/>  
  9.     <constant name="struts.devMode" value="true"/>  
  10.     <package name="default" namespace="/" extends="struts-default">  
  11.         <action name="UserActionForCommonParam" class="com.struts.action.UserActionForCommonParam" method="addUser">  
  12.             <result name="success">/UserPage.jsp</result>  
  13.         </action>  
  14.     </package>  
  15. </struts>  


前台页面UserPage.jsp

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>  
  2. <%@ taglib prefix="s" uri="/struts-tags" %>  
  3. <html>  
  4. <head>  
  5.     <title>UserPage</title>  
  6. </head>  
  7. <body>  
  8.     <%--下面的Table用于提交参数(id,username,content)--%>  
  9.     <form action="UserActionForCommonParam" method="POST">  
  10.         <table border="1">  
  11.             <tr>  
  12.                 <td>ID:</td>  
  13.                 <td><input type="text" name="id"/></td>  
  14.             </tr>  
  15.             <tr>  
  16.                 <td>Username:</td>  
  17.                 <td><input type="text" name="username"/></td>  
  18.             </tr>  
  19.             <tr>  
  20.                 <td>Content:</td>  
  21.                 <td><input type="text" name="content"/></td>  
  22.             </tr>  
  23.             <tr>  
  24.                 <td colspan="2" align="center">  
  25.                     <input type="submit" value="提交"/>  
  26.                 </td>  
  27.             </tr>  
  28.         </table>  
  29.     </form>  
  30.     <br/>  
  31.     <%--下面的Table用于显示传递回来id,username,content--%>  
  32.     <table border="1">  
  33.         <tr>  
  34.             <td>ID: </td>  
  35.             <td><input type="text" value="${id}"/></td>  
  36.         </tr>  
  37.         <tr>  
  38.             <td>Username: </td>  
  39.             <td><input type="text" value="${username}"/></td>  
  40.         </tr>  
  41.         <tr>  
  42.             <td>Content: </td>  
  43.             <td><input type="text" value="${content}"/></td>  
  44.         </tr>  
  45.     </table>  
  46.     <%--用于查看ValueStack中的传递的值--%>  
  47.     <s:debug/>  
  48. </body>  
  49. </html>  

在实践后会发现,如果遇到参数非常多的情况,那么就需要在Action类中写非常多的属性以及对应的get/set方法.所以这种方式不太可取.解决问题的方法必然是封装一个JavaBean.这就用到了Strut2的第二种传值方式--DomainModel

2.DomainModel传值

首先要创建一个存储的JavaBean

User类

把id,username,content封装的到一个User类当中.

  1. package com.struts.model;  
  2.   
  3. public class User {  
  4.     private int id;  
  5.     private String username;  
  6.     private String content;  
  7.   
  8.     public int getId() {  
  9.         return id;  
  10.     }  
  11.   
  12.     public void setId(int id) {  
  13.         this.id = id;  
  14.     }  
  15.   
  16.     public String getUsername() {  
  17.         return username;  
  18.     }  
  19.   
  20.     public void setUsername(String username) {  
  21.         this.username = username;  
  22.     }  
  23.   
  24.     public String getContent() {  
  25.         return content;  
  26.     }  
  27.   
  28.     public void setContent(String content) {  
  29.         this.content = content;  
  30.     }  
  31. }  

UserActionForDomainModel类

  1. package com.struts.action;  
  2.   
  3. import com.opensymphony.xwork2.ActionSupport;  
  4. import com.struts.model.User;  
  5.   
  6. public class UserActionForDomainModel extends ActionSupport{  
  7.     private User user;  
  8.   
  9.     public User getUser() {  
  10.         return user;  
  11.     }  
  12.   
  13.     public void setUser(User user) {  
  14.         this.user = user;  
  15.     }  
  16.   
  17.     public String addUser() {  
  18.         System.out.println("ID: " + user.getId());  
  19.         System.out.println("Username: " + user.getUsername());  
  20.         System.out.println("Content: " + user.getContent());  
  21.         return "success";  
  22.     }  
  23. }  


对应的struts.xml

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <!DOCTYPE struts PUBLIC  
  4.         "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"  
  5.         "http://struts.apache.org/dtds/struts-2.3.dtd">  
  6.   
  7. <struts>  
  8.     <constant name="struts.enable.DynamicMethodInvocation" value="true"/>  
  9.     <constant name="struts.devMode" value="true"/>  
  10.     <package name="default" namespace="/" extends="struts-default">  
  11.         <action name="userForDomainModel" class="com.struts.action.UserActionForDomainModel" method="addUser">  
  12.             <result name="success">/UserPage.jsp</result>  
  13.         </action>  
  14.     </package>  
  15. </struts>  


前台页面UserPage.jsp

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>  
  2. <%@ taglib prefix="s" uri="/struts-tags" %>  
  3. <html>  
  4. <head>  
  5.     <title>UserPage</title>  
  6. </head>  
  7. <body>  
  8.     <%--要特别注意的是DomainModel的传值方式必须要使用对象.参数方式进行赋值以及取值--%>  
  9.     <form action="userForDomainModel" method="POST">  
  10.         <table border="1">  
  11.             <tr>  
  12.                 <td>ID:</td>  
  13.                 <td><input type="text" name="user.id"/></td>  
  14.             </tr>  
  15.             <tr>  
  16.                 <td>Username:</td>  
  17.                 <td><input type="text" name="user.username"/></td>  
  18.             </tr>  
  19.             <tr>  
  20.                 <td>Content:</td>  
  21.                 <td><input type="text" name="user.content"/></td>  
  22.             </tr>  
  23.             <tr>  
  24.                 <td colspan="2" align="center">  
  25.                     <input type="submit" value="提交"/>  
  26.                 </td>  
  27.             </tr>  
  28.         </table>  
  29.     </form>  
  30.     <br/>  
  31.     <%--下面的Table用于显示传递回来id,username,content--%>  
  32.     <table border="1">  
  33.         <tr>  
  34.             <td>ID: </td>  
  35.             <td><input type="text" value="${user.id}"/></td>  
  36.         </tr>  
  37.         <tr>  
  38.             <td>Username: </td>  
  39.             <td><input type="text" value="${user.username}"/></td>  
  40.         </tr>  
  41.         <tr>  
  42.             <td>Content: </td>  
  43.             <td><input type="text" value="${user.content}"/></td>  
  44.         </tr>  
  45.     </table>  
  46.     <%--用于查看ValueStack中的传递的值--%>  
  47.     <s:debug/>  
  48. </body>  
  49. </html>  

实际上User类不需要显式的实例化,struts会自动帮你实例化,但前提条件是,传值时需要使用对象.参数名的方式进行传递.

除了这种传值方式外,struts2还提供另外一种传值方式.

3.ModelDriven传值

依然要创建User的JavaBean

User类

  1. package com.struts.model;  
  2.   
  3. public class User {  
  4.     private int id;  
  5.     private String username;  
  6.     private String content;  
  7.   
  8.     public int getId() {  
  9.         return id;  
  10.     }  
  11.   
  12.     public void setId(int id) {  
  13.         this.id = id;  
  14.     }  
  15.   
  16.     public String getUsername() {  
  17.         return username;  
  18.     }  
  19.   
  20.     public void setUsername(String username) {  
  21.         this.username = username;  
  22.     }  
  23.   
  24.     public String getContent() {  
  25.         return content;  
  26.     }  
  27.   
  28.     public void setContent(String content) {  
  29.         this.content = content;  
  30.     }  
  31. }  


UserActionForModelDriven类

  1. package com.struts.action;  
  2.   
  3. import com.opensymphony.xwork2.ModelDriven;  
  4. import com.struts.model.User;  
  5.   
  6. public class UserActionForModelDriven implements ModelDriven<User>{  
  7.     private User user;  
  8.   
  9.     public String addUser() {  
  10.         System.out.println("ID: " + user.getId());  
  11.         System.out.println("Username: " + user.getUsername());  
  12.         System.out.println("Content: " + user.getContent());  
  13.         return "success";  
  14.     }  
  15.   
  16.     @Override  
  17.     public User getModel() {  
  18.         if (user == null) {  
  19.             user = new User();  
  20.         }  
  21.         return user;  
  22.     }  
  23. }  

这种方式可以不用在Action类中编写对应的get/set方法,但是需要实例化User类.

前台UserPage.jsp

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>  
  2. <%@ taglib prefix="s" uri="/struts-tags" %>  
  3. <html>  
  4. <head>  
  5.     <title>UserPage</title>  
  6. </head>  
  7. <body>  
  8.     <form action="userForModelDriven" method="POST">  
  9.         <table border="1">  
  10.             <tr>  
  11.                 <td>ID:</td>  
  12.                 <td><input type="text" name="id"/></td>  
  13.             </tr>  
  14.             <tr>  
  15.                 <td>Username:</td>  
  16.                 <td><input type="text" name="username"/></td>  
  17.             </tr>  
  18.             <tr>  
  19.                 <td>Content:</td>  
  20.                 <td><input type="text" name="content"/></td>  
  21.             </tr>  
  22.             <tr>  
  23.                 <td colspan="2" align="center">  
  24.                     <input type="submit" value="提交"/>  
  25.                 </td>  
  26.             </tr>  
  27.         </table>  
  28.     </form>  
  29.     <br/>  
  30.     <%--下面的Table用于显示传递回来id,username,content--%>  
  31.     <table border="1">  
  32.         <tr><span id="transmark"></span>  
  33.             <td>ID: </td>  
  34.             <td><input type="text" value="${id}"/></td>  
  35.         </tr>  
  36.         <tr>  
  37.             <td>Username: </td>  
  38.             <td><input type="text" value="${username}"/></td>  
  39.         </tr>  
  40.         <tr>  
  41.             <td>Content: </td>  
  42.             <td><input type="text" value="${content}"/></td>  
  43.         </tr>  
  44.     </table>  
  45.     <%--用于查看ValueStack中的传递的值--%>  
  46.     <s:debug/>  
  47. </body>  
  48. </html>  

页面还是和普通传值一样.

可以去ValueStack当中观察参数的存储,更透彻的理解Struts2的参数传递. : <s:debug/>

1.什么是ValueStack

对于每一个action的调用,Struts在执行相应的动作方法之前会先创建一个名为ValueStack的对象。Value Stack用来保存该动作对象或者对象。由于最终在执行Action类相应的action方法之前,拦截器需要先访问ValueStack。视图也需要访问ValueStack。Struts框架将其保存在一个名为struts.valueStack的请求属性中。

2.获取valueStack的三种方法:

 ValueStack v1 = ActionContext.getContext().getValueStack();
     ValueStack v2 = ServletActionContext.getValueStack(ServletActionContext.getRequest());
        ValueStack v3 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");

打印其HashCode码一模一样。
说明:
1、 值是一样的,说明只有一个对象
2、 因为有一种是从request域中获取的,所以是一次请求

3.ValueStack的内容

valueStack分为对象栈(Object Stack)和Map栈(Context Map).

Struts将把动作和相关对象压入Object Stack,而把各种各样的映射关系压入Context Map。

通常说的ValueStack就是指Object Stack,它是一个真正数据结构意义的栈。Object Stack也常常被称为root(其实是一个ArrayList)。Context Map我们一般称其为context(是一个HashMap)它是整个OGNL其中包括了root

4.OGNL中的两种对象

OGNL中包含两种对象,即_root和_value.
_value即:request, session, application, parameters, attr等命名对象,但这些命名对象都不是根。
_root即:当前请求的Action实例等
“根”对象和普通命令对象的区别在于:
“根”对象(root) 对象栈: 实际上是 CompoundRoot 类型, 是一个使用 ArrayList 定义的栈. 里边保存各种和当前 Action 实例相关的对象(如果这个Action实例包括域对象的话域对象会进root).是一个数据结构意义的栈.

1)访问Context Map里的对象需要在对象名之前添加 #
2)访问Object Stack对象的属性时,可以省略#而直接通过属性名来搜索

技术分享

说明:
从上图中也可以看出valueStack总共分为两个部分:

      对象栈:root (CompoundRoot类)
      Map栈:_values和_root (OgnlContext 类)

5.Struts会把当前访问的Action实例压入值栈栈定

压入时间点为:
由于Struts2最后终将调用Action类中的action方法。但在调用此方法之前:

*先创建一个StrutsActionProxy (ActionProxy默认实现的子类)
*在创建StrutsActionProxy之后,对其进行初始化,把Action对象压入值栈

在调用该方法前该Action被压入栈顶,如果在初始化的过程中,在Action的构造函数中又初始化了其他类,这这个类也会被压入值栈。所以最后栈顶的元素会是这个新初始化的类。

6.ValueStack中对象的存取

Object Stack 的存放: push 或者 add:

将一个对象放入Object Stack的栈顶:

  • 1 ActionContext.getContext().getValueStack().push(object);
  • 2 ActionContext.getContext().getValueStack().getRoot().add(0,object);

Object Stack的提取: peek() 或 pop()

peek()取得的是栈顶元素:

  • 1 Object object = ActionContext.getContext().getValueStack().peek();

Object Stack的元素的弹出:pop:

  • 1 Object object = ActionContext.getContext().getValueStack().pop();

7.动态修改ValueStack中对象的属性

技术分享

说明:
可以利用valueStack.setParameter方法改变对象栈中对象的属性的值。至于匹配哪个。则依次从对象栈的栈顶向下搜索,找到匹配的就修改





















以上是关于Struts2的传值方式及原理的主要内容,如果未能解决你的问题,请参考以下文章

struts2中jsp页面与action之间的传值

JavaWeb:不同页面之间的传值及取值

iOS 浅谈MVC设计模式及Controllers之间的传值方式

jsp js action之间的传值

java的传值方式

E. 对象的传值方式