JavaWeb 之 OGNL 表达式、Struts2 值栈与OGNL 特殊符号
OGNL 表达式 & Struts2 值栈 & OGNL 特殊符号
OGNL表达式
OGNL表达式概述(了解)
OGNL 是
Object Graphic Navigation Language
(对象图导航语言)的缩写所谓对象图,即以任意一个对象为根,通过 OGNL 可以访问与这个对象关联的其它对象
通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。
Struts2 框架使用
OGNL
作为默认的表达式语言OGNL
是一种比EL
强大很多倍的语言xwork
提供OGNL
表达式ognl-3.0.5.jar
OGNL 提供五大类功能
支持对象方法调用
支持类静态的方法调用和值访问
访问 OGNL 上下文(OGNLcontext)和 ActionContext
支持赋值操作和表达式串联
操作集合对象测试的代码
1 | // 访问对象的方法 |
自己测试的代码:
1 | package com.renkaigis; |
在 Struts2 框架中使用 OGNL 表达式
1). Struts2 引入了 OGNL
表达式,主要是在 JSP
页面中获取值栈中的值
2). 具体在 Struts2 中怎么使用呢?如下步骤
需要先在 JSP 页面中引入
Struts2
的标签库
1 | <%@ taglib prefix="s" uri="/struts-tags" %> |
使用
Struts2
提供的标签中的标签
1 | <s:property value="OGNL表达式"/> |
3). 在 JSP 页面使用 OGNL
表达式
访问对象方法
1 | <s:property value="'hello'.length()"/> |
Struts2 框架的值栈
值栈的概述
值栈就相当于
Struts2
框架的数据的中转站,向值栈存入一些数据。从值栈中获取到数据。ValueStack
是 struts2 提供一个接口,实现类OgnlValueStack
—- 值栈对象 (OGNL
是从值栈中获取数据的 )Action
是多例的,有一个请求,创建Action
实例,创建一个ActionContext
对象,代表的是Action
的上下文对象,还会创建一个ValueStack
对象。每个
Action
实例都有一个ValueStack
对象 (一个请求对应一个ValueStack
对象 )在其中保存当前
Action
对象和其他相关对象Struts 框架把
ValueStack
对象保存在名为“struts.valueStack”
的请求属性中,request
中 (值栈对象是request
一个属性)
1 | // 不常用 |
值栈的内部结构
值栈由两部分组成
值栈由以下两部分组成:
root ———— Struts 把动作和相关对象压入
ObjectStack
中–List
context ———— Struts 把各种各样的映射关系(一些Map
类型的对象) 压入ContextMap
中Struts 会默认把下面这些映射压入
ContextMap
(context)中注意:
request
代表的是Map
集合的key
值,value
的值其实也是一个Map
集合。parameters:该 Map 中包含当前请求的请求参数 ?name=xxx&password=123
request:该 Map 中包含当前request
对象中的所有属性
session:该 Map 中包含当前session
对象中的所有属性
application:该 Map 中包含当前application
对象中的所有属性
attr:该 Map 按如下顺序来检索某个属性:request
,session
,application
ValueStack 中存在
root
属性 (CompoundRoot) 、context
属性 (OgnlContext )CompoundRoot
就是ArrayList
OgnlContext
就是Map
context 对应 Map 引入 root 对象
context 中还存在 request、 session、application、 attr、 parameters 对象引用
操作值栈默认指操作 root 元素
OGNL 获取值
如果从 root
栈中获取值,OGNL 表达式默认情况下不能写 #
号:
1 | <s:property value="表达式"/> |
如果从 context
栈中获取值,OGNL 表达式默认需要加 #
号(访问 request、 session、application、 attr、 parameters 对象数据必须写):
1 | <s:property value="#表达式"/> |
值栈的创建和 ActionContext 对象的关系
值栈对象是
请求时创建
的ActionContext
是绑定到当前的线程上,那么在每个拦截器或者Action
中获取到的ActionContext
是同一个。ActionContext
中存在一个Map
集合,该Map
集合和ValueStack
的context
是同一个地址。ActionContext
中可以获取到ValueStack
的引用,以后再开发,使用ActionContext
来获取到值栈对象
获取值栈对象
- 获得值栈对象,有三种方法:
1 | ValueStack vs1 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack"); |
1 | ValueStack vs2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); |
★重要:
1 | // 获取值栈对象,首先要获取 ActionContext 对象 |
向值栈中保存数据
向值栈保存数据 (主要针对 root
栈)
push 方法
1 | // 向栈顶压入对象 |
push
方法的底层调用root
对象的push
方法(把元素添加到 0 位置)
set 方法
1 | // 向栈顶压入 map 集合,把 key 和 obj 存入到 map 集合中 |
- 源码获取
map
集合(map
有可能是已经存在的,有可能是新创建的),把map
集合压入到栈顶,再把数据存入到map
集合中。
在 jsp 中,通过
<s:debug/>
查看值栈的内容
从值栈中获取值
一些小细节
访问
root
中的数据不需要#
访问context
中的对象数据,要加#
如果向root
中存入对象的话,优先使用push
方法。
如果向root
中存入集合的话,优先要使用set
方法。
在 OgnlContext 中获取数据
1 | request:<s:property value="#request.username"/> |
代码演示
前提 struts.xml
:
1 | <struts> |
注意:jsp 中首先要引入标签库 <%@taglib prefix="s" uri="/struts-tags" %>
,在 jsp 中使用 <s:debug></s:debug>
可以查看值栈的内容。
以下代码演示 压栈和取值
:
push 字符串
Action
代码:
1 | // 获取值栈 |
jsp
代码:
1 | <%--获取栈顶的值--%> |
set 字符串
Action
代码:
1 | vs.set("msg", "小瓜"); |
jsp
代码:
1 | <%--栈顶是 map 集合,通过 key 来获取值--%> |
获取对象(push)
首先需要创建一个 JavaBean:
1 | package com.renkaigis.demo2; |
Action
代码:
1 | // 创建 User 对象 |
jsp
代码:
1 | <%--栈顶放 user 对象--%> |
获取对象(set)
Action
代码:
1 | vs.set("user", user); |
jsp
代码:
1 | <s:property value="[0].top.user.username"/> |
List 集合(push)
Action
代码:
1 | ArrayList<User> ulist = new ArrayList<>(); |
jsp
代码:
1 | <s:property value="[0].top[0].username"/> |
List 集合(set)
Action
代码:
1 | vs.set("ulist", ulist); |
jsp
代码:
1 | <s:property value="ulist[0].username"/> |
从 context 栈中获取值
底层已经封装了 request、session 等对象,操作的就是 map 集合
request
Action
代码:
1 | HttpServletRequest request = ServletActionContext.getRequest(); |
jsp
代码:
1 | <s:property value="#request.msg"/> |
session
Action
代码:
1 | request.getSession().setAttribute("msg", "小卡"); |
jsp
代码:
1 | <s:property value="#session.msg"/> |
parameters
路径传值:
1 | http://localhost:9090/save.action?id=10 |
jsp
代码:
1 | <s:property value="#parameters.id"/> |
attr
attr 从最小域开始找
jsp
代码:
1 | <s:property value="#attr.msg"/> |
EL 表达式也能获取到值栈中的数据
EL 获取值栈的值
获取上面的 ulist:
首先导包:
jstl.jar
、standard.jar
引标签库:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
1 | <%--在 jsp 页面上使用 EL 和 JSTL 标签库来取值--%> |
为什么 EL 也能访问值栈中的数据?
因为 Struts2 底层使用了装饰者模式,对 getAttribute()
方法进行了增强。
StrutsPreparedAndExecuteFilter
的 doFilter
代码中 request = prepare.wrapRequest(request);
对
Request
对象进行了包装StrutsRequestWrapper
增强了request
的getAttribute()
方法
1 | Object attribute = super.getAttribute(s); |
访问
request
范围的数据时,如果数据找不到,会去值栈中找request
对象具备访问值栈数据的能力(查找root
的数据)
OGNL 表达式的特殊符号
# 符号的用法 ★
获得 contextMap 中的数据
1 | <s:property value="#request.name"/> |
# 可以构建一个 map 集合
以构建表单为例:
1 | <h3>编写表单</h3> |
使用 #
构建 map 集合:
1 | <h3>编写表单</h3> |
% 符号的用法
强制字符串解析成 OGNL 表达式
例如:在
request
域中存入值,然后在文本框(<s:textfield>
)中取值,现在到value
上。
1 | <s:textfield value="%{#request.msg}"/> |
{ } 中的值用 ‘’ 引起来,此时不再是 ognl 表达式,而是普通的字符串
1 | <s:property value="%{'#request.msg'}"/> |
$ 符号的用法
- 在配置文件中可以使用 OGNL 表达式,例如:文件下载的配置文件。
1 | <action name="download1" class="com.renkaigis.demo2.DownloadAction"> |