值栈详解(ValueStack)
来源:互联网 发布:js判断字符串不等于 编辑:程序博客网 时间:2024/04/28 12:23
什么是值栈
之前web阶段,在servlet里面进行操作,把数据放到域对象里面,在页面中使用el表达式获取到。域对象在一定范围内,存值和取值。
在struts2里面提供了本身的一种存储机制,类似于域对象,是值栈,可以存值和取值。
- 在action里面把数据放到值栈里面,在页面中获取到值栈的数据。
注意:对于存值,你可以使用servlet中的三种域对象,使用这三种域对象都可以在jsp页面中获取到。同时你使用struts2里面的存储机制同样能够实现上面的效果,但是并不是一定要你使用struts2里面的存储方法。目的要让你知道struts2也能够办到同样存值取值的操作。只是你说会struts2 但是你不会值栈,这是说不过去的!!!
servlet和action的区别:
Servlet:
默认在第一次访问的时候创建,只创建一次,是一个单例对象!!
Action:
一样是访问的时候创建对象,每次访问action的时候都会创建新的action对象,创建多次,是一个多实例对象!!
值栈的存储位置:
- 每次访问action的时候都会创建action对象。
- 在每个action对象里面都会有一个值栈对象。(注意:每个action对象只有一个)
获取值栈
获取值栈对象有多种方式!
- 常用的方式:使用ActionContext对象里面的方法(getValueStack())获取值栈对象。
目的验证在同一个action值栈只有一个:
public class pr_action{ public String execute(){ ActionContext context=ActionContext.getContext(); ValueStack vs1=context.getValueStack(); ValueStack vs2=context.getValueStack(); System.out.println(vs1==vs2); }}
输出结果:
true
值栈内部结构
栈:先进后出!
最上面是栈顶的元素,向栈里面放数据的操作叫做压栈。
所以,你没有猜错,值栈也是用的这种数据结构!但是值栈分为两个部分,root和context,root就是栈的数据结构,同时context也是
root专业叫做ObjectStack(对象栈)
context专业叫做ContextMap(Map栈),Map类型的栈。(在我们访问里面的对象的时候,会通过出栈的方式取东西,效率比较低,一般我们不会用)
值栈分为两个部分:
- 第一个部分 root ,平常我们用的值栈就是操作root里面的内容,很少去操作context。结构是List集合。
可以通过ctrl+shift+t搜索类,来查看它的父类。
很惊奇你会发现root对象类型继承了ArrayList这个类
- 第二部分 context ,结构是Map集合
下面来讲讲context这个对象:
context里面存储的都是些固定的值,有以下几个:
key————value
request—>最底层是request(HttpServletRequest),但是在这里的request是RequestMap类型的。如果你在HttpServletRequest类型中赋了值,那么在RequestMap中照样能够读取到。
session—>HttpSession对象引用
application—>ServletContext对象引用
parameters—>传递相关的参数
attr—>使用attr操作,能够获取域对象里面的值,获取域范围最小里面的值。
要想查看到值栈的结构可以用调试(debug)的方法!
通过struts2的标签<s:debug></s:debug>
,我们可以很清楚的看到值栈确实分为两个部分,一个root,一个context,上面我们已经讲解了context的存储内容
,下面我们就来讲讲root的存储内容:
我们已经了解到root是一个栈的存储结构。下面是root默认存储的内容:
action对象引用
DefaultTextProvider
也就是说在root的栈顶还存储着action的引用,为什么会这个存储呢??
其实它只是为了能够在值栈里面取出action,能够在action里面取出值栈,仅此而已!
向值栈里面放数据
向值栈里面放数据时,其实存储的位置是在root域里面
向值栈放数据有多种方式,往往我们只用其中一种
- 第一种 获取值栈对象,调用值栈对象里面的 set 方法
ValueStack stack=ActionContext.getContext().getValueStack();stack.set("username","FireLang");
在用set方法添加值栈数据之后,会在root栈顶多一个HashMap对象
- 第二种 获取值栈对象,调用值栈对象里面的 push 方法
调用push之后,就会在root栈顶放入一个String类型的对象!
- 第三种 在action定义变量,生成变量的get方法(主要)
public class pr_action{private String name;public String getName(){ return name;}public String execute(){ name="FireLang"; return "success";}}
在用第三种方法之后,struts2并不会在值栈root的栈顶放入新的对象,它的存储路径还是存储在action里面,所以这就起到了资源的合理应用,当想要获取name属性的时候,就会在值栈里面调用action的getName方法。这也就是为什么会在值栈里面存储action的原因了。
向值栈中放对象
实现步骤:
第一步:定义对象变量
第二步:生成变量的get方法
第三步:在执行的方法里面向对象中设置值
向值栈中放List对象
第一步:定义List集合变量
第二步:生成变量的get方法
第三步:在执行的方法里面向List集合设置值
action的代码:
public class Pr_fangList { private List<User> lu; public String execute(){ lu=new ArrayList<User>(); User u1=new User(); u1.setName("胡艺宝"); u1.setPassword("123"); lu.add(u1); User u2=new User(); u2.setName("胡家源"); u2.setPassword("456"); lu.add(u2); System.out.println(lu); return "success"; } public List<User> getLu() { return lu; }}
jsp中代码:
<!-- 文章截止到目前还没有说到el表达式为什么能够取到值栈里面的数据,在文章后续会解释的 -->${lu[0].name }${lu[0].password }<br><hr><br>${lu[1].name }${lu[1].password }<s:debug></s:debug>
为什么EL表达式能够获取值栈里面的数据
从值栈的root里面取数据
使用struts2的标签+ognl表达式获取值栈数据
<s:property value="ognl表达式"/>
获取字符串
步骤:
服务端代码:
//服务端代码是为了让字段被存入ValueStack中//字段的前提条件是必须设置get方法public class Pr_getString { private String name; public String getName() { return name; } public String execute(){ name="胡艺宝"; return "success"; }}
客户端jsp代码:
<s:property value="name"/><!-- 这里的name是ognl表达式。表示获取action中的name字段值,必须要写get方法,因为字段读或者写的功能按照规定,都必须通过读或者写方法来给变量赋值 -->
获取对象
aciton中的代码:
//再次强调必须要get方法。public class Pr_getUserObj { private User us; public User getUs() { return us; } public String execute(){ us=new User(); us.setName("胡艺宝"); us.setPassword("FireLang"); return "success"; }}
jsp中的代码:
<s:property value="us.name" /><br><!-- value中的值是ognl表达式 --><s:property value="us.password" /><!-- 获取到us对象后,再获取us中的name属性和password属性,再次强调获取字段基本上都是按照规定通过get和set方法进行操作! -->
获取List集合
通过ognl+struts标签获取List集合共有三种方式
服务端代码:
public class Pr_getList { private List<User> usl=null; public List<User> getUsl() { return usl; } public String execute(){ usl=new ArrayList<User>(); User tempUser=new User("胡艺宝", "123465"); usl.add(tempUser); return "success"; }}
第一种:
客户端代码:
//这种代码非常不好,在很多时候你永远不可能知道服务端传来的List里面到底有多少参数。<s:property value="usl[0].name"/><s:property value="usl[0].password"/>
第二种方式:
类似jstl中的foreach标签
<s:iterator value="usl"> <s:property value="name"/> <s:property value="password"/> <br><hr><br></s:iterator>
第三种方式:
/*第三种方式较第二种方式多加了一个var,根本区别就是iterator把遍历出来的值放进了值栈的第二部分空间context,contex因为是Map结构的所以要加上一个键作为取值方式,也就是var的值作为context的键,其实这种方式算是一种优化,不用在root中去拿值了。而第二种方式还会到root里面去拿值。速度没有在context中的快*/<s:iterator value="usl" var="singleus"> <s:property value="#singleus.name"/> <s:property value="#singleus.password"/></s:iterator>
set方法和push方法的取值(会用)
set方法的取值
//服务端代码:public class Pr_getUserSet { private User us; public String execute(){ us=new User("胡艺宝","789"); ActionContext.getContext().getValueStack().set("us", us); ActionContext.getContext().getValueStack().set("lang", "FireLang");; return "success"; }}
<!-- 客户端代码: --><!-- 直接从root域里面取值 --><s:property value="us"/><br><br><s:property value="lang"/>
//运行结果:User [name=胡艺宝, password=789]FireLang
push方法取值
//服务器端代码://这里要注意的是push方法是直接把数据存放在root中的。不像set一样可以通过key来取值。//push的取值方法有点特殊,是通过直接把栈顶元素取出来的。public class Pr_getUserSet { private User us; public String execute(){ us=new User("胡艺宝","789"); ActionContext.getContext().getValueStack().push(us); ActionContext.getContext().getValueStack().push("FireLang"); return "success"; }}
<!-- 客户端jsp代码 --><s:property value="[0].top"/>//取第一个<s:property value="[1].top"/>//取第二个,这里的top是root的域实体对象名称,也就是List对象的名称
运行结果:FireLang User [name=胡艺宝, password=789]
增强一个类常用的方式:装饰者模式,动态代理,继承
用EL表达式取值:
el取值能够获取到action里面的值,具体原理就是,它重写的request,进行了request域的增强,里面进行了以下操作:
el取值时,如果request域里面能够找到目标值,那么就把值返回到页面。如果在request域里面不能够取到目标值,那么就通过值栈获取。
ActionContext.getContext().getValueStack().findValue(“key”);如果查找到值就返回数据。这里的request是通过HttpServletRequestWrapper重写过。
所以在el表达式获取Action里面存取的值的时候效率没有通过Struts标签来的快。推荐用struts标签和ongl来获取Action里面的数据。
el在获取Action里面的值时,action里面的字段也必须提供get方法。否则无法获取到值。
//服务端代码:public class Pr_getList { private List<User> usl=null; public List<User> getUsl() { return usl; } public String execute(){ usl=new ArrayList<User>(); User tempUser=new User("胡艺宝", "123465"); usl.add(tempUser); return "success"; }}
<!-- 客户端jsp代码: --><!-- 在使用jstl标签以前要先导入jstl标签库,这里使用的jstl标签库是1.2版本 --><c:forEach items="${usl }" var="temp"> ${temp.name }<br> ${temp.password }</c:forEach>
//这个是增强request的源码:ActionContext ctx = ActionContext.getContext(); Object attribute = super.getAttribute(key); if (ctx != null && attribute == null) { boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE)); // note: we don't let # come through or else a request for // #attr.foo or #request.foo could cause an endless loop if (!alreadyIn && !key.contains("#")) { try { // If not found, then try the ValueStack ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE); ValueStack stack = ctx.getValueStack(); if (stack != null) { attribute = stack.findValue(key);//这就是el能够获取到值栈里面的关键 } } finally { ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE); } } } return attribute;
ognl两个符号的使用#号和%的使用
使用#来获取context中的数据
//服务端的代码:public class Pr_getRequestByContext { private User us; public User getUs() { return us; } public String execute(){ us=new User("胡艺宝", "123456789"); ((RequestMap)ActionContext.getContext().getValueStack().getContext().get("request")).put("user", us);//把数据保存到context的request中//其中你也可以通过ActionContext.getContext().get("request")获取到的效果和上面的一样。 System.out.println(ServletActionContext.getRequest().getAttribute("user"));//验证是否能够在HttpServletRequest中获取到user,事实证明能够获取到。猜测RequestMap的最底层依赖了HttpServletRequest return "success"; }}
<!-- 这个是jsp客户端的代码 --><s:property value="#request.user"/>
运行后能够成功获取user数据
%号的使用
场景:在struts2表单标签里面使用ognl表达式,如果直接在struts2表单标签里面使用ognl表达式会不识别,只有使用%号之后才会识别。
//服务端代码就用上面那个
<!-- 客户端jsp代码,成功运行输出后的代码: --><s:textfield name="username" value="%{#request.user.name}"></s:textfield>
OK!!!完成!!
- 值栈详解(ValueStack)
- Struts2中的ValueStack值栈对象详解
- 关于值栈(ValueStack)
- struts2之值栈ValueStack
- Struts2中的值栈--ValueStack
- struts2中的值栈ValueStack
- Ognl,Context,ValueStack详解
- struts2-ValueStack详解
- struts ValueStack 详解
- Struts2中的ValueStack详解
- Ognl表达式 值栈对象ValueStack
- Struts2的值栈理解---ValueStack
- **struts2中的值栈对象ValueStack**
- Strus2中关于ValueStack详解
- struts ValueStack 取值
- valuestack存储值过程
- 值栈(ValueStack)
- valuestack
- 第七届蓝桥杯有奖猜谜
- 关系型数据库工作原理-数据库整体框架(翻译自Coding-Geek文章)
- 使用mybatis执行oracle存储过程
- QLPreviewController 预览文件
- 基于okHttpUtils网络请求的基类抽取
- 值栈详解(ValueStack)
- ettercap,shank和bettercap利用BeEF进行中间人攻击(1)
- 215. Kth Largest Element in an Array
- TCP和UDP的区别
- 小白的windows cpu 下caffe学习笔记(1)mnist测试
- java this的关键字
- 玲珑OJ 1097
- 例子讲解Vue.js的slot分发
- CodeForces