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),通 ...
随机推荐
- Day5 Scanner对象学习.
Scanner对象 Java.until.Scanner 我们可以通过Scanner类来获取用户的输入. 基本语法: Scanner s = new Scanner (System . in) ; 通 ...
- springMVC-2-MVC初步了解
Spring MVC的特点 轻量级,简单易学 高效 , 基于请求响应的MVC框架 与Spring兼容性好,无缝结合 约定优于配置 功能强大:RESTful.数据验证.格式化.本地化.主题等 简洁灵活 ...
- 国产深度学习框架mindspore-1.3.0 gpu版本无法进行源码编译
官网地址: https://www.mindspore.cn/install 所有依赖环境 进行sudo make install 安装,最终报错: 错误记录信息: cat /tmp/mind ...
- Java 加载、操作和保存WPS文字文档
本文通过Java程序代码来展示如何来加载.操作及保存WPS格式的文字文档. 一.基本步骤:加载时,通过流加载WPS文字文档,完成相关文字操作后,再将结果文档保存到流,将流写入WPS文档,闭关闭流. 二 ...
- ajax原理及应用(十六)
前言 AJAX即"Asynchronous Javascript And XML",是指一种创建交互式网页应用的网页开发技术.AJAX 是一种用于创建快速动态网页的技术.它可以令开 ...
- FactoryBean简介以及Mybatis-Spring应用
一.BeanFactory和FactoryBean区别? BeanFactory是工厂类,提供了获取和检索Bean的接口.它代表着Spring的IoC容器,负责Bean实例化以及管理Bean之间的依赖 ...
- maven之---资源过滤 在java/main/resourse/*.xml ,*.properties引用maven属性${db.username}
本文主要来源maven实战14.3 为了应对环境的变化,首先使用Maven属性将这个会发生变化的部分提取出来.在上一节的数据库配置中,连接数据库使用的驱动类,URL,用户名和密码都可能发生变化,因此使 ...
- div 模拟alert弹出框
--------------信息展示弹出框---------------- <style> .over{background-color: rgba(0, 0, 0, 0.7);displ ...
- Samba 远程命令执行漏洞(CVE-2017-7494)
该漏洞影响Samba 3.5.0之后的所有版本,在4.6.4/4.5.10/4.4.14修复了这个漏洞 use exploit/linux/samba/is_known_pipename set rh ...
- 🔥 LeetCode 热题 HOT 100(41-50)
102. 二叉树的层序遍历 思路:使用队列. /** * Definition for a binary tree node. * public class TreeNode { * int val; ...