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),通 ...
随机推荐
- 备战- Java虚拟机
备战- Java虚拟机 试问岭南应不好,却道,此心安处是吾乡. 简介:备战- Java虚拟机 一.运行时数据区域 程序计算器.Java 虚拟机栈.本地方法栈.堆.方法区 在Java 运行环境参考链接: ...
- Apache atlas liunx环境安装部署手册
一. 背景 本文使用一台ubuntu虚拟机安装Apache-atlas,使用集成包unzip apache-atlas-2.1.0.zip进行快速安装部署,该集成包高度集成了hadoop ...
- YARN调度器(Scheduler)详解
理想情况下,我们应用对Yarn资源的请求应该立刻得到满足,但现实情况资源往往是有限的,特别是在一个很繁忙的集群,一个应用资源的请求经常需要等待一段时间才能的到相应的资源.在Yarn中,负责给应用分配资 ...
- PyVista:一款Python的三维可视化软件
技术背景 三维可视化是一项在工业领域中非常重要的技术,而Python中最热门的可视化工具matplotlib和plotly,更加倾向于在数据领域的可视化,用于展现数据的结果.类似的还有百度的pyech ...
- GraphQL 概念入门
GraphQL 概念入门 Restful is Great! But GraphQL is Better. -- My Humble Opinion. GraphQL will do to REST ...
- 【对线面试官】CountDownLatch和CyclicBarrier的区别
<对线面试官>系列目前已经连载31篇啦,这是一个讲人话面试系列 [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 &am ...
- fiddler抓取手机模拟器数据
引自:https://blog.csdn.net/lengdaochuqiao/article/details/88170522 1.下载最新版fiddler ,强烈建议在官网下载:https://w ...
- weex打包android apk采坑之旅(windows)
1. npm install weex-toolkit -g 后weex命令不起作用 ,解决办法把weex.cmd所在的目录添加到环境变量PATH 2.weex命令每次报找不到文件'C:\Progra ...
- Laravel Ignition 2.5.1 代码执行漏洞(CVE-2021-3129)
影响范围 Laravel 框架 < 8.4.3 facade ignition 组件 < 2.5.2 poc git clone https://github.com/simonlee-h ...
- ES6新特征
1.块级作用域 { } 就是块级作用域,还包括if.else.for.while...下都属于块级作用域. let 声明的变量不存在变量的提升,不允许let反复声明同一个变量:块级作用域下let ...