之前的javaweb中,在页面中做显示,我们很快就能想到
Javaweb 页面显示 : JSP + JSTL + EL
Struts2 页面显示支持 JSP 、Freemarker, Velocity ,引入非常强大表达式语言 OGNL
OGNL 五个功能
1) 支持对象 实例方法调用
2) 支持静态方法调用
3)表达式赋值
4) 访问OGNL上下文(OGNL context)和ActionContext; ------ 值栈操作 (重要)
5) 操作集合对象 构造List 构造Map
1、 调用静态方法和 实例方法, 都需要通过<s:property > 标签完成使用struts2标签要导入标签库
<%@tagliburi="/struts-tags" prefix="s"%>
实例方法 <s:propertyvalue="'abcd'.length()"/>
静态方法 <s:propertyvalue="@java.lang.String@format('你好, %s','小明')"/> 默认没有被解析
备注:%s相当于占位符,例子中用小明来代替了。
* 如果使用静态方法调用,需要在struts.xml中设置<!--支持OGNL 静态方法调用 -->
<constantname="struts.ognl.allowStaticMethodAccess"value="true"></constant>
2、ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础
ValueStack值栈对象,是Action 实例拥有,每次访问 都会有新的Action实例, 每次访问都会有一个新的值栈
ValueStack(值栈):贯穿整个 Action 的生命周期(每个 Action类的对象实例都拥有一个ValueStack对象). 相当于一个数据的中转站.在其中保存当前Action 对象和其他相关对象.
Struts 框架把 ValueStack对象保存在名为“struts.valueStack”的请求属性中,request中
获得值栈对象
方式:
第一种 ValueStack valueStack = (ValueStack)ServletActionContext.getRequest().getAttribute("struts.valueStack");(通过request域获取)
第二种 ValueStackvalueStack2 = ActionContext.getContext().getValueStack();(通过actionContext获取)
值栈ValueStack 由两个部分组成
第一部分ObjectStack (保存root属性,类型CompoundRoot) ----- ArrayList
第二部分 ContextMap(保存context属性, 类型 ) ------ Map
Struts 会把下面这些映射压入 ContextMap 中OgnlContext
parameters: 该 Map 中包含当前请求的请求参数
request: 该 Map 中包含当前 request 对象中的所有属性
session: 该 Map 中包含当前 session 对象中的所有属性
application:该 Map 中包含当前 application 对象中的所有属性
attr: 该 Map 按如下顺序来检索某个属性: request, session, application
注:CompoucdRoot继承了ArrayList,实际上就是一个集合,用于存储元素的数据,OgnlContext实现了Map, 其中持有CompoucdRoot对象的引用,其key为_root
JSP中的数据访问
在JSP页面内,通过 <s:property>等标签去访问值栈的数据,访问root中数据,不需要#,访问 Context中数据必须以#开始
之前在取数据的时候用的方法实际上就是在操作值栈
ServletActionContext.getRequest().setAttribute("requestmsg","requestinfo");
ServletActionContext.getRequest().getSession().setAttribute("sessionmsg","session info");
ServletActionContext.getServletContext().setAttribute("applicationmsg",applicationinfo");
现在在页面中取数据
<s:propertyvalue="#request.requestmsg"/> <br/>
<s:propertyvalue="#session.sessionmsg"/> <br/>
<s:propertyvalue="#application.applicationmsg"/> <br/>
<s:propertyvalue="#attr.requestmsg"/> arr:会自动搜索 request session application中的这个数据
当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。
Action对象会被保存root 对象栈中,Action所有成员变量属性,都位于root中 ,访问root中数据不需要#
<s:propertyvalue="company" /> 实际上是访问到Action 中 getCompany() 方法
向值栈保存数据
1) 只要定义到Action 成员变量,提供get方法,该数据就在值栈中
在jsp中 <s:debug> 进行值栈调试
2) valueStack 对象 提供 push方法,用来将一个对象压入 root栈
3) 调用valueStack 的set方法,向root中保存数据,如果执行set,将在root中创建一个map对象
* 向context保存数据 valueStack.getContext().put("addr", "西三旗金燕龙"); (一般不向其保存,因为root 就够用了)
3、 ognl 表达式写法
第一类符号 # , 使用# 访问 OGNL Context中数据 , 访问root 数据不需要添加 #
<s:propertyvalue="#parameters.name" /> --------->request.getParameter("name");
<s:property value="#request.name"/> --------- > request.getAttribute("name");
<s:property value="#session.name"/> -------- >session.getAttribute("name");
<s:propertyvalue="#application.name" /> ------ >application.getAttribute("name");
<s:property value="#attr.name"/> ------- 依次查找request 、session 、application 中 name数据
#request ---相当于---- ActionContext.getContext().getRequest()
使用EL表达式,能否访问 值栈中 root中数据 ???
request对象在struts2被装饰了, getAttribute 方法被重写了,如果request.getAttribute找不到对应属性,会自动去值栈root中找,因此使用EL表达式能够访问valueStack中对象的属性
结论: 值栈root对象中所有数据,都可以通过 request进行访问 !!!!!!!!!
值栈数据 通过 JSTL + EL 遍历显示
4、通过OGNL去遍历值栈中集合(投影过滤显示) ---------很重要!!!!
将集合对象,保存到Action成员变量,自动加入值栈,传递jsp
在jsp页面内,通过 <s:iterator> 迭代标签<s:property>取值标签 去遍历显示值栈中 List数据
例:
<s:iteratorvalue="#request.products" var="product">
<!-- 显示product数据,每个product对象会被保存到 root和 context 中各一份 -->
访问root中的<s:propertyvalue="name"/> <s:property value="price"/>
访问context中的<s:propertyvalue="#product.name"/> <s:propertyvalue="#product.price"/>
两个地方都能取到
</s:iterator>
投影过滤(遍历的时候加入表达式)
语法 集合name.{表达式}
例如 : value="products.{name}" ----- 只获取每个商品name属性
例:
<h1>投影案例---- 只获得每个商品名称显示</h1>
<s:iteratorvalue="products.{name}" var="name">
<s:propertyvalue="#name"/>
</s:iterator>
value="products.{?#this.price >3000}" 过滤所有价格大于3000手机
value="products.{^#this.price >3000}" 只要价格大于3000 第一条信息
value="products.{$#this.price >3000}" 只要价格大于3000 最后一条信息
value="products.{?this.prive>3000}.{name}" 显示价格大于3000所有手机的name
5、 #可以用来构造 List 或者 Map 对象, 主要用于表单 select radio checkbox 按钮生成(放到form标签)
<s:radio list=“#{‘male’:‘男’,‘female’:‘女’}” name=“sex” label=“性别” />
运行结果是相当于之前标签的两个radio
<input type="radio"name="sex" id="sexmale" value="male"/>男
<input type="radio"name="sex" id="sexfemale" value="female"/>女
6、 %的使用 控制转义 (使用OGNL被是否被解析或者忽略 )
在很多struts2 标签中, 通过% 指定 OGNL表达式 是否进行解析
例:
控制ognl表达式 不被解析:<s:property value="%{'#request.company'}"/>加‘’
控制目标 OGNL表达式 被解析:<s:textfieldlabel="%{#request.company}"></s:textfield>不加‘’
7、$ 的使用 (用于配置文件,读取一个变量信息)
1) 用于国际化文件,读取变量信息
2) struts.xml 中使用 ${contentType} 会自动读取 值栈数据
例:在国际化文件 添加 msg = 我们的城市是${#request.city} ---- 可以在值栈根对象中保存city, 通 过request保存
<%
// 在request范围保存数据,在国际化文件 ${#request.city} 获得信息
ServletActionContext.getRequest().setAttribute("city","北京");
%>
<s:i18n name="message">
<s:textname="msg"></s:text>
</s:i18n>
面试题: # 、 % 、 $ 区别
# 在jsp中读取 Ognl Context中数据, 投影过滤,构造List和Map
% 控制struts2 标签中 OGNL表达式是否解析 , %{表达式} ---- 解析 、 %{'表达式'} ---- 不会解析
$ 在struts2 配置文件(struts.xml 国际化文件),定义变量,读取值栈信息 ${city} 读取root 中city ${#session.info} 读取session 中 info信息