Struts2的学习过程中,提到了valueStack和OGNL表达式,这两个是Struts2框架下的概念,这里参考老师授课和博客,进行简单记录和整理,后续有其他理解再添加上去。
概念介绍
(1)valueStack
valueStack是值栈,是Struts2中用户共享数据的一种数据结构,其包含两个区域。
Contents区域
一个是Contents为栈结构(先进后出),也有博客称之为Root区域,主要是一个ArrayList,里面一般放置对象,获取这个区域的数据不需要加#。
浏览器发送一个action请求到服务端filter,会在服务端创建一个action对象和valueStack,将请求所带的数据属性,在contents区域保存,默认值为数据类型初始值,如String类型属性为null,int类型为0,保存到contents区域,当action对象执行使用时,将调用拦截器,将请求中的数据取出来,初始化content区域的属性值,再将contents区域所保存的属性值,赋值给action对象的属性。当action请求结束返回字符串给result后,valueStack将销毁,这就是valueStack的生命周期。
Context区域
另外一个是Context为Map结构,里面放置的是web开发常用的对象数据引用,获取里面的数据需要加#对象名.属性名。常见的几种对象数据引用有(可以通过OGNL表达式的debug标签获取具体内容):
1. Request
2. Session
3. Application
4. Parameters
5. attr
JSP访问方式
1. Contents区域使用OGNL表达式,EL表达式
2. Context区域使用#Key的方式访问对应Value
(2)OGNL表达式
OGNL(Object-Graph Navigation Language),对象图导航语言,OGNL被Struts2整合后将变成它的一种标签,可以在JSP中使用,获取Contents区域的数值。此外它还有其他的强大功能,这里不做详细深究,其他可以参考文末博客。
(3)生命周期
当请求进入服务器端的filter,将创建valueStack对象,当请求结束,valueStack对象将被销毁。
案例测试
案例发送一个action请求到服务端,服务端action请求里有若干属性,在具体的执行方法里,采用两种方式获取valueStack,并往其中一个加入一条对象数据。在JSP页面使用OGNL表达式和EL表达式获取数据进行查看。
(1)struts.xml中的配置
<!-- 测试保存数据到valueStack中 --> <package name="test" namespace="/testValueStack" extends="struts-default"> <action name="valueStack" class="testValueStack" method="doValueStack"> <result name="success"> /WEB-INF/msg.jsp </result> </action> </package>
(2)将push到valueStack栈顶的对象所属类,其中包含message属性。
package Entity; /** * 实体类,用于测试valueStack * @author yangchaolin */ public class Person { private int id; private String name; private String message;//action请求也将有一个同名的属性message //创建无参数构造方法 public Person() { super(); } //创建有参数构造方法 public Person(int id, String name, String message) { super(); this.id = id; this.name = name; this.message = message; } ...省略get set方法 }
(3)action请求处理类,其中也包含一个message属性,跟action中的属性同名同类型。另外session中以key为name也放入了一条数据,其中Person对象中也有属性name。
package Controller; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.util.ValueStack; import Entity.Person; /** * 控制器类 * @author yangchaolin */ @Controller @Scope("prototype") public class testValueStack { private String message;//Person实体类也有同名的属性message public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } //具体实现方法 public String doValueStack() { //给属性赋值 message="我是action请求中的message"; //创建person对象 Person p=new Person(1,"我是Person对象中的name","我是Person对象中的message"); //将person对象添加到valueStack中 //action执行的所需的对象保存在ActionContext,如参数,session等 //第一种获取valueStack的方式,根据ActionContext获得 ActionContext ctx=ActionContext.getContext(); ValueStack stack=ctx.getValueStack(); stack.push(p); //第二种获取valueStack的方式,根据request对象获得 HttpServletRequest request=ServletActionContext.getRequest(); //key为struts.valueStack ValueStack stack_compare=(ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); System.out.println("两种获取得到的valueStack相同吗?"+(stack==stack_compare)); //session中也保存一条数据 ctx.getSession().put("name", "我是Session中的name"); return "success"; } }
(4)JSP页面,引入了Struts2的标签库,这样就可以使用OGNL表达式,EL表达式可以直接使用。
<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!-- 引入Struts2中的标签库 --> <%@taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>测试valueStack</title> </head> <body style="font-family:'微软雅黑';font-size:15px;"> <h2>使用OGNL表达式</h2> <s:property value="message"></s:property><br> <!-- 获取同名message --> <s:property value="[1].message"></s:property><br> <s:property value="#session.name"></s:property><br><!-- 通过key获取 --> <h2>使用EL表达式</h2> ${message}<br> ${name} <!-- OGNL和EL表达式获取的都是contents区域中的值 --> <h2>输出valueStack中的数据,使用debug标签</h2> <s:debug></s:debug> </body> </html>
测试结果
(1)OGNL表达式和EL表达式获取值结果
从测试结果可以看出来OGNL和EL表达式都可以从Contents区域获取数据,其中message都是Person对象中的message,而不是action对象中的message,是因为action中的message先存到了栈里面,使用表达式取值时是从栈顶往下扫描的,因此先扫描到了Person对象中的message后不再往下扫描,所以的两个表达式获取的都是Person对象中的。而使用EL表达式获取的也是Person对象中,而不是session中的,说明session中的值需要使用#Key的方式获取。
此外两种获取valueStack的方式表明,两者获取的valueStack是一样的。
(2)debug标签获取Contents和Context中的内容
从结果可以直观的看到数据存储的地方,进而加强对valueStack和OGNL表达式的理解。可以看出session中的name,保存在了Context区域,只能通过#key的方式获取值。而message保存也是先保存了action中的message,后面执行了action中方法后,将Person对象push到栈顶后,才出现第二个message。如果要获取第二个message,需要在JSP中使用[1].message来得到。
结论
(1)valueStack是封装了action请求中数据的一种特殊数据结构,其中包含Contents区域和Context区域。
(2)获取Contents区域需使用OGNL表达式或EL表达式,获取Context区域数据使用#Key方式
(3)valueStack当action请求结束后将消失。
参考博文:https://blog.csdn.net/qq_23853743/article/details/84664867