Struts2之OGNL与ValueStack
时间:2017-1-12 12:02
——OGNL
1、OGNL表达式是什么
OGNL的全称是Object-Graph Navigation Language的缩写,中文名是对象图导航语言,它是一种功能强大的表达式语言。
比EL表达式功能强大。
Struts2将OGNL表达式语言集成到Struts2框架中,作为它的默认表达式语言。
2、OGNL表达式的功能
1)支持对象方法调用,如:xxx.doSomeMethod()
2)支持类静态的方法调用和值访问。
3)访问OGNL上下文(OGNL Context)和ActionContext:(重点,操作ValueStack)
4)支持赋值操作和表达式串联。
5)操作集合对象。
3、OGNL中“根”与“非根”的区别
root:只能有一个根,用于存储Action相关数据
contextMap:用于存储Web相关数据
4、示例代码
在Java代码中使用ognl表达式。
根中数据不需要使用#获取。
非根中数据需要使用#获取。
OGNL叫做对象图导航语言。
Person.java
----------------------------------------------------------------------------------------------------------------------------
Dog.java
----------------------------------------------------------------------------------------------------------------------------
OgnlDemo1.java
----------------------------------------------------------------------------------------------------------------------------
OgnlDemo2.java
——在Struts2中使用ognl表达式
需要结合Struts2的标签使用:<s:property value="" />
* value:
书写ognl表达式
* default:
默认值
* escapeHtml
是否解析HTML
* escapeJavaScript
是否解析JS
* escapeXml
是否解析XML
注意:在Struts的JSP页面中访问静态成员时,必须设置一个常量值:
struts.ognl.allowStaticMethodAccess=false
示例代码:
——ValueStack
1、ValueStack是什么
从技术角度来讲,ValueStack是一个接口(com.opensymphony.xwork2.util.ValueStack)。
从实用角度来讲,ValueStack是一个容器,用于将数据携带到action数据页面,然后在页面通过ognl表达式来获取。
ValueStack是Struts2提供的一个接口,实现类是OgnlValueStack。
OGNL表达式是从ValueStack中获取数据的。
每个Action实例都有一个ValueStack对象(一个请求对应一个ValueStack对象)
ValueStack中保存当前Action对象和其他常用Web对象,例如request, session, application, parameters(值栈中是有Action引用的)
Struts2框架把ValueStack对象保存在key为“struts.valueStack”的request域中(request中值栈对象是request的一个属性)
一个request一个Action,一个Action一个ValueStack,request - Action - ValueStack是一一对应的。
ValueStack生命周期就是一个request的生命周期。
流程(源码分析):
从第一个请求开始,被StrutsPrepareAndExecuteFilter拦截后执行doFilter()中的execute.executeAction(request, response, mapping);方法,然后一直调用,进入到Dispatcher中的serviceAction()方法,在该方法中通过request获取ValueStack对象:ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);如果是第一次获取,则ValueStack对象为null,然后创建一个新的ValueStack,因为每次请求都是一个新的请求,所以每次请求都会创建一个新的ValueStack。当请求结束后,ValueStack就被释放了,所以ValueStack的生命周期等同于request的生命周期。
然后通过Dispatcher类中的serviceAction()方法中的:request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());来获取一个新的ValueStack对象,并保存到request域中,保存的key为:ServletActionContext.STRUTS_VALUESTACK_KEY,在ServletActionContext中可以查看,该常量的值为:struts.valueStack。
2、ValueStack的内部结构
查看ValueStack接口,可以看到两个方法:
* public abstract Map<String, Object> getContext();
* public abstract CompoundRoot getRoot();
> public class CompoundRoot extends ArrayList
> CompoundRoot类继承了ArrayList,提供了peek() pop() push()方法,相当于栈。
ValueStack接口中声明了root属性(CompoundRoot)、context属性(OgnlContext):
* CompoundRoot就是ArrayList。
* OgnlContext就是Map
值栈由两部分组成:
ObjcetStack:Struts2把Action和相关对象压入ObjectStack中,用一个List保存
保存Action相关信息。
ContextMap:Struts2把各种各样的映射关系(一些Map类型的对象)压入ContextMap中。
比较常见的映射关系就是常见Web对象。
Struts2会把下面这些映射压入ContextMap中:
* parameters:该Map中包含当前请求的请求参数
* request:该Map中包含当前request对象的所有属性
* session:该Map中包含当前session对象的所有属性
* application:该Map中包含当前application对象的所有属性。
* attr:该Map按如下顺序来检索某个属性:request、session、application,相当于全域查找
* 对象引用
通过断点可以发现:
其中root在ContextMap中也有一个映射关系:
ValueStack中包含ContextMap和Root,而在ContextMap中又持有了Root的引用。
可以在断点调试中发现:
OGNL表达式访问root(List)中数据时,不需要使用#访问。
访问(Map)request、session、application、attr、parameters、对象引用时,必须写#。
操作ValueStack时,默认是指操作root元素。
其实ContextMap就是一个OgnlContext,可以查看ValutStack接口的实现类:OgnlValueStack
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticMethodAccess) {
结论:
ValueStack有两个部分,一个是List,一个是Map。
在Struts2中List就是Root,Map就是OgnlContext。
在Struts2中,默认情况下(不加#)从ValueStack中的Root获取数据。
3、ValueStack对象的创建,ValueStack和ActionContext是什么关系?
当请求发出时,会被doFilter()拦截然后调用Dispatcher类中的serviceAction()方法,方法中可以创建ValueStack对象:
// 刚开始会到request域中获取
// 如果获取不到ValueStack对象
// 会到ActionContext中获取
ValueStack和ActionContext的关系:
ActionContext中持有了ValueStack的引用。
4、如何获取ValueStack对象
有两种方式可以获取ValueStack对象:
1)通过request获取
2)通过ActionContext获取
5、向ValueStack中保存数据(主要针对root)
在ValueStack接口中有两个方法:
有两种方式:
* push(Object obj)
* set(String key, Object obj)
1)push(Object obj)
在ValueStack接口的实现类OgnlValueStack中,重写了此方法:
底层调用的是:root.add(0, obj);
所以push方法会将对象压入栈顶。
如果当前位置存在元素,那么当前元素会先后移,然后再在栈顶压入元素。
2)set(String key, Object obj)
在ValueStack接口的实现类OgnlValueStack中,重写了此方法:
public void set(String key, Object o) {
// 将数据封装到一个新的HashMap中
// 将Map集合压入栈顶
底层是将数据封装到HashMap中,再将这个HashMap压入栈顶,保存到List集合中。
示例代码:
stack.set("username", "张三");
输出结果:
[3, 2, 1, com.wyc.action.OgnlDemo2Action@320859ec, com.opensymphony.xwork2.DefaultTextProvider@5c1958e7]
6、在JSP页面中使用<s:debug />标签查看ValueStack中的数据
7、在JSP页面中获取ValueStack数据
获取Root中数据不需要#
获取ContextMap中数据需要#
获取Root中的数据:
1)如果栈顶是一个Map集合,那么获取时可以直接通过Map集合的key来获取value。
<s:property value="username"/>
如果只写属性名,那么即使栈顶不是Map集合,也会从栈顶开始依次往下查找。
2)如果栈顶元素不是Map,不能通过key来获取,可以使用下标来获取元素:
<s:property value="[0] />
从0位置开始向下查找所有数据。
<s:property value="[0].top" />
只查找0位置上的数据。
JSP页面示例代码:
获取OgnlContext中的数据:
1)request数据
request.setAttribute()
2)session数据
session.setAttribute()
3)application数据
application.setAttribute()
4)attr
依次从request, session, application域中查找。
相当于pageContext的全域查找。
5)parameters数据
获取请求参数。
JSP页面代码:
3、获取OgnlContext中的数据
8、ValueStack有什么作用
使用ValueStack最大的作用就是将Action相关的数据以及Web相关的对象,传递到页面上。
简单来讲,在Struts2中通过ValueStack将Action中的数据携带到页面上进行展示。
1)Action向JSP携带的数据都是什么类型的数据?
* 普通文本(字符串)
> fieldError:校验数据错误信息提示(常用于表单校验),this.addFieldError("msg", "字段错误信息")
> actionError:关于逻辑操作时的错误信息(普通错误信息,例如登录失败),this.addActionError("Action全局错误信息")
> message:通用信息,this.addActionMessage("Action普通消息信息")
在JSP中使用Struts2标签显示错误信息:
* <s: fielderror fieldName="msg" />
* <s:actionerror />
* <s:actionmessage />
* 复杂数据
可以使用ValueStack存储:
Action中存储数据:
JSP中获取数据:
<body>
9、关于默认压入到ValueStack中的数据分析
当前的Action会被默认压入ValueStack
1)属性驱动
每次请求访问Action对象,Action对象都会被压入ValueStack,在DefaultActioninvocation的init()方法中:
stack.push(action);
DefaultActioninvocation源码:
......
}
在拦截器被调用之前就压入ValueStack了。
作用:
当Action被压入ValueStack之后,Action如果向传递数据给JSP,只要将数据保存为成员变量,并且提供get()方法就可以了。
当Action中声明了一个getXxx()方法后,ValueStack会将get之后的JavaBean的名称放到ValueStack的key中,然后在页面中可以直接使用JavaBean对象的key值来获取value值。
示例代码:
public class OgnlDemo4Action extends ActionSupport {
JSP代码:
<s:iterator value="users" var="user">
2)模型驱动
ModelDriven接口有一个单独的拦截器
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor" />
在拦截器中,将Model对象压入了ValueStack:stack.push(model);
如果Action实现了ModelDriven接口,ValueStack默认栈顶对象就是Model对象。
因为Action对象在拦截器执行前就已经压入,而Model对象在ModelDrivenInterceptor拦截器执行时才会压入。
ModelDrivenInterceptor源码:
public String intercept(ActionInvocation invocation) throws Exception {
// 将实现了ModelDriven接口的Action中的getModel()方法的返回值也就是内部封装的JavaBean对象压入到了ValueStack
if (action instanceof ModelDriven) {
在同一个请求中,Action中声明的private User user = new User();和getModel()方法中返回的User是相同的,也就是说在JSP页面中通过ValueStack获取到的User对象是同一个对象。但是,如果在execute()方法中对user重新赋值,那么push到ValueStack中的Action所包含的User就是后赋值的user对象,因为这个User对象是通过getXxx()方法获得的。而Model依然是private User user = new User();对象,因为Model是在execute()方法执行之前被压入的,所以在获取值时需要注意,这是两个对象。(new了两次,是两个对象。)
ModelDriven中保存的是初始化时压入的对象。
Action中保存的是execute()方法中赋值的对象。
示例代码:
10、为什么EL表达式可以访问ValueStack中的数据
Action中:
stack.set("username", "张三");
JSP中:
Struts2框架中所使用的request对象,是增强后的request对象,重写了getAttribute()方法。
StrutsPreparedAndExecuteFilter的doFilter()方法中:
request = prepare.wrapRequest(request)
* 对Request对象进行了包装,包装类:StrutsRequestWrapper
* 重写了request的getAttribute()方法
Object attribute = super.getAttribute(key)
if(attribute == null) {
attribute = stack.findValue(key);
}
增强后的request,会首先在request范围查找,如果查找不到,会到ValueStack中查找。
——OGNL表达式的常见使用
1、#
1)#相当于ActionContext.getContext()上下文
<s:property value="#request.name" />
相当于:ActionContext.getContext().getRequest().get("name");
2)不写#默认在ValueStack的Root中进行查找
3)进行投影映射以及过滤操作(结合复杂对象遍历)
映射:
<s:property value="ps" /><br />
1、使用iterator进行遍历<br />
过滤:
4)使用#构造Map集合
经常结合Struts2标签用来生成select、checkbox、radio
示例代码:
1、使用#构造一个Map集合<br/>
2、%
作用是用来设定当前字符串是否要解析为ognl表达式。
3、$
作用是在配置文件中写ognl表达式来获取ValueStack中的数据。
1)struts.xml
<result type="stream">
<param name="contentType">${contentType}</param>
</result>
2)在校验文件中使用
<param min="${min}"></param>
<param min="${max}"></param>
<param min="${maxLength}"></param>
校验文件会引入校验器,校验器会被加载,所以数据也会保存到ValueStack中。
3)在国际化文件中使用
在properties文件中:
username=${#request.username}
在JSP页面:
<%
在properties文件中也可以使用%获取值:
username=%{request.username}
——总结
1、ognl介绍
2、ValueStack介绍
3、什么是ValueStack
4、ValueStack内部结构
5、ValueStack创建以及ActionContext关系
6、如何获取ValueStack
7、如何向ValueStack存储数据(Root)
8、JSP页面中如何获取ValueStack数据
9、关于ValueStack携带数据分析
* 携带数据类型
* 如何在页面上获取复杂数据
* ValueStack默认压入数据
10、如何使用OGNL表达式
* #
* %
Struts2之OGNL与ValueStack的更多相关文章
- 【Struts2】Ognl与ValueStack
一.OGNL 1.1 概述 1.2 OGNL 五大类功能 1.3 演示 二.ValueStack 2.1 概述 2.2 ValueStack结构 2.3 结论 2.3 一些问题 三.OGNL表达式常见 ...
- Struts2【OGNL、valueStack】就是这么简单
什么是OGNL表达式? OGNL是Object Graphic Navigation Language 是操作对象属性的开源表达式. Struts2框架使用OGNL作为默认的表达式语言. 为什么我们学 ...
- struts2.1.6教程四、OGNL与ValueStack(VS)
1.值栈入门 下面我们建立struts2ognl项目来练习ognl的使用. 步骤一.搭建strust2的开发环境 步骤二.建立LoginAction,主要代码如下: package com.asm; ...
- 浅析Struts2中的OGNL和ValueStack
要了解Struts2与OGNL表达式的关系,我们必须先搞清楚以下三个概念: 1. ActionContext它是Action运行的上下文环境,Action的多项设置都存放在次,我们每一次Action ...
- struts2之OGNL和struts2标签库和ValueStack对象
OGNL简介: (1)OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目. struts2框架默认就支持Ognl表达式语言(所以 ...
- Struts2的OGNL表达式语言
一.OGNL的概念 OGNL是Object-Graph Navigation Language的缩写,全称为对象图导航语言,是一种功能强大的表达式语言,它通过简单一致的语法,可以任意存取对象的属性或者 ...
- Struts2之OGNL
一.OGNL是什么? OGNL(Object-Graph Navigation Language)对象图导航语言,是一种表达式语言,它可以 1.遍历对象的结构图 2.存取对象的属性(实例属性和静态属性 ...
- Struts2对Ognl的支持
Struts2对Ognl的支持 一. 写作背景 由于工作性质的变化,最近一直在研究struts2,从 ...
- 【struts2】OGNL
1 OGNL概述 OGNL是对象图导航语言Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL),通 ...
随机推荐
- Day2基本数据类型 字节 和类型转换
Java基础语法 注释 1.单行注释:// 加内容 2.多行注释:/* 多行注释 */ 3.文档注释: /** * * */ 有趣的注释 标识符 关键字 基本数据类型 八大基本数据类型 //整数in ...
- 【LeetCode】66. 加一
66. 加一 知识点:数组: 题目描述 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字. 你可以假设除了整数 0 ...
- 前端开发入门到进阶第一集【使用sublime快速编写Html和Css】
1,安装sublime编辑器,下载地址:http://www.sublimetext.com/3 2,要使用sublime的插件机制必须安装package control:https://packag ...
- 单细胞分析实录(18): 基于CellPhoneDB的细胞通讯分析及可视化 (上篇)
细胞通讯分析可以给我们一些细胞类群之间相互调控/交流的信息,这种细胞之间的调控主要是通过受配体结合,传递信号来实现的.不同的分化.疾病过程,可能存在特异的细胞通讯关系,因此阐明这些通讯关系至关重要. ...
- Java的标准日志
虽然开源社区有很多优秀的日志框架,但我们学习标准的java日志框架是为了更好的理解其他框架啊(近期项目要用ELK) 看自己以前写的Log4J简直不忍直视啊啊啊啊,那时还感觉自我良好 1. 为什么要使用 ...
- java中的集合类学习(三)
JAVA中有许多的集合,常用的有List,Set,Queue,Map. 1.其中List,Set,Queue都是Collection(集合),其每个元素都是单独的一个对象,如List<Strin ...
- 【秒懂音视频开发】26_RTMP服务器搭建
从本节开始,正式开启流媒体相关的内容. 流媒体 基本概念 流媒体(Streaming media),也叫做:流式媒体. 是指将一连串的多媒体数据压缩后,经过互联网分段发送数据,在互联网上即时传输影音以 ...
- LS-DYNA SMP R11.1.0 for Win64安装破解教程
LS-DYNA SMP R11.1.0是一款极其强大的有限元仿真分析工具,可以模拟现实世界的问题.主要用于分析结构的非线性响应等操作,其全自动接触分析和广泛的材料模型使全球用户能够解决复杂的现实问题. ...
- (python函数02)列表生成式
(python函数02)列表生成式 示例代码 num = [i for i in range(1, 10)] print(num) num = [i for i in range(1, 10) ...
- 构建前端第3篇之---使用scss
张艳涛 写于2021-1-20 主要解决俩个问题: 在单个vue文件中 <style rel="stylesheet/scss" lang="scss"& ...