- 这是学习过程中的一些记录,可能有出错的地方,仅供参考
值栈的简介
在Servlet中,servlet在与前端页面之间的数据传输是通过域对象来做中转的,那么在Struts2中也有他自己做定义的一个数据中转站,这个中转站就是值栈ValueStack。
- 值栈的生命周期
值栈是Struts2的一个接口,当有页面请求时Struts2就会为我们创建好一个值栈的实现类OgnlValueStack对象,同时Struts2也会创建一个ActionContext对象和Action对象,然后将值栈封装在ActionCOntext对象中,值栈的生命周期是与Action息息相关的,Action存在则值栈存在,Action消亡则值栈也消亡。
- 值栈的内部结构
总体来看,值栈的数据结构就是一个栈,底层实现是list,在值栈中主要看两个存贮数据的区域,一个是root区,一个是context区。
root区底层又是用ArrayList实现的,而context区是用Map实现的。
- root区
当有请求访问时,Struts2会创建一个Action实例,还会把action对象放到值栈的root区,注意所有放入值栈的都是放入对象的地址引用。在root区中,当放入的是一个对象,也会把对象内的成员属性也一并放入root区,因此Action对象中定义的成员属性也会被放入root区。
- context区
在context区中存放着request、session、application等对象,注意这个的request、session等都只是map集合的key,而value这是request等key所对应的request对象中的数据。
- 值栈的查看
在Struts2中,我们可以通过使用Struts2的标签库来查看值栈的root区和context区。
注意要导入struts2的标签库。<%@taglib prefix=“s” uri="/struts-tags" %>
在jsp页面写入标签<s:debug></s:debug>,这样我们就可以在浏览器查看到值栈的内部结构。
- root区:
- context区:
- 往值栈的root区存值
package com.wzm.action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;
import com.wzm.entity.User;
public class ActionDemo6 extends ActionSupport{
/*
* 向值栈的root区存储数据有两种方式,
* 一种是属性存值,因为struts2会吧action对象存在值栈的root区,
* 因此action对象里边的成员属性也会一并存在root区,
* 注意是存在值栈root区的Property Name+Property Value
* 另一种方式则是通过ActionContext获取值栈对象ValueStack,然后通过值栈获取root区CompoundRoot对象
* 调用push(user),底层是调用add(0, user)方法就可以往root区存值,
* 注意这里是存在list下标为0的区域,相当存在root区的栈顶,同时如果是对象,会把对象内的属性存在Property Name+Property Value
*/
//在action中直接定义一个成员属性,struts2会把这个属性存在root区
//注意有个条件就是要有这个属性的getter方法
private User user;
public User getUser() {
return user;
}
private String jsp;
public String getJsp() {
return jsp;
}
@Override
public String execute() throws Exception {
/*
* 通过获取root区的对象来往栈顶存值,其实不用获取root区对象也能实现功能
* valueStack.push(user);同样是往root区存值,底层调用的还是add(0, user)
*/
//获取actioncontext对象
ActionContext context = ActionContext.getContext();
//获取值栈对象
ValueStack valueStack = context.getValueStack();
//获取root区对象
CompoundRoot root = valueStack.getRoot();
user = new User();
user.setAge(18);
jsp = "/ognl.jsp";
//往root区存值
root.push(user);
return "success";
}
}
- 往值栈的context区存值
package com.wzm.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;
import com.wzm.entity.User;
public class ActionDemo7 extends ActionSupport{
@Override
public String execute() throws Exception {
ActionContext context = ActionContext.getContext();
/*
* 这里是向值栈中的context区存值
* 能够通过el表达式获取到${context区中的key}
* 之前说这个有点类似往request域对象中存值,但是实际上不是,
* 这是在context区中单独再创一个键值对出来,而不是在request中创建键值对
*/
context.put("msg", "context");
//这里获取session,往session存值,也是通过值栈存值
//session的引用存在值栈的context区中
Map<String, Object> session = context.getSession();
session.put("a", "a");
return "success";
}
}
OGNL表达式
OGNL的全称是对象图导航语言(Object-Graph Navigation Language),它是一种功能强大的开源表达式语言,使用这种表达式语言,可以通过某种表达式语法,存取Java对象的任意属性,调用Java对象的方法,同时能够自动实现必要的类型转换。OGNL表达式不是Struts2专属的,Struts2只是对其进行了封装。
- OGNL表达式的基本使用
注:需要导入struts2的标签库
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 要使用OGNL表达式,需要导入struts2的标签库 -->
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 这是debug标签,通过这个可以看到值栈的内部结构 -->
<s:debug></s:debug>
<!-- property是struts2的标签,用来使用ognl表达式获取值 -->
<!-- ognl表达式可以用来直接调用对象方法 -->
<s:property value="'struts2'.length()"/><br>
<!-- ognl表达式可以用来直接调用静态属性,注意格式@全限定名@静态属性 -->
<s:property value="@java.lang.Math@PI"/><br>
<!-- ognl表达式可以用来直接调用静态方法,注意格式@全限定名@静态方法
同时注意struts2默认不让调用静态方法,需要覆盖配置
在struts.xml或者web.xml加都可以
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
-->
<s:property value="@java.lang.Math@random()"/>
<!-- ognl表达式可以用来获取值栈中的值 ,value中使用的值是值栈中root区的Property Name
如果存储的是一个对象,还可以通过对象.属性名来获取对象内的属性值
-->
<s:property value="user.username"/>
</body>
</html>
- Struts2中el表达式
EL表达式原来的搜素顺序:
page Scope——>request Scope——>sessionScope——>application Scope
在struts2中,struts2框架通过使用装饰者模式对request对象进行了包装,并且对getAttribute方法进行了增强,使得el表达式的搜索顺序变为了:
page Scope—>request Scope—>root区—>context区- >sessionScope—>application Scope
因此当我们往context区中存数据时,我们可以使用el表达式得到存储的数据。
- el表达式的三种特殊符号
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 要使用OGNL表达式,需要导入struts2的标签库 -->
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 这是debug标签,通过这个可以看到值栈的内部结构 -->
<s:debug></s:debug>
<!-- ognl表达式的几个特殊符号# % $ -->
<!-- 当在ognl表达式中使用到#,代表是从值栈的context区中获取值
value中使用的值的context区的key
-->
<s:property value="#request"/>
<!-- #还可以用在遍历值栈中得到的集合 -->
<!-- 直接在value中创建一个list集合
遍历出来的每一个值都存在var中,var是存在值栈的context区,因此取值需要加#
每一次都会被覆盖
-->
<s:iterator value="{'aaa','bbb','ccc'}" var="l">
<s:property value="#l"/>
</s:iterator>
<!-- 直接在value中创建一个map集合,注意这里需要使用 # 来表明这是一个map集合
遍历出来的每一个值都存在var中,map遍历出来的是键值对
取值用#var.key或者key,#var.value获取值
-->
<s:iterator value="#{'1':'a','2':'b' }" var="m">
<s:property value='#m.key'/>---》<s:property value='#m.value'/>
</s:iterator>
<!-- %在ognl表达式的使用
在struts2中不是所有的struts2标签都认识ognl表达式,
因此当我们需要在其他struts2标签中使用ognl表达式就需要用到%
-->
<s:textfield name="username" value="%{user.username}"></s:textfield>
<!-- $在ognl表达式中是使用在struts.xml配置文件中的,注意与el表达式区分
通过使用 $ 符号我们可以直接在struts.xml中使用ognl表达式获取值栈的值
往值栈存储key为jsp的值,获取jsp的值“/ognl.jsp”直接跳转页面
<package name="test6" extends="struts-default">
<action name="demo6" class="com.wzm.action.ActionDemo6">
<result>${jsp}</result>
</action>
</package>
-->
</body>
</html>