struts2中的ognl

1、ValueStack与<s:debug>标签
Struts 2框架使用OGNL作为默认的表达式语言,先用<s:property> 标签体验一下ognl表达式和调动学习热情,例如,显示Action中的一个属性和显示一个请求参数。
OGNL表达式就是针对一个称为OGNL Context的Map对象和一个称之为OGNL根对象进行操作的语言,OGNL表达式可以寻址Context内部的对象和直接调用根对象的属性或方法。
Struts2中设置的OGNL 根对象为CompoundRoot, OGNL Context的Map对象和CompoundRoot 封装在一个ValueStack对象中。由于OGNL Context是一个Map对象,不算什么新知识,不用专门学习了,所以,学习OGNL的重要第一步就是要先了解ValueStack和CompoundRoot 。ValueStack内部封装的CompoundRoot是一个继承了ArrayList实现的堆栈,ValueStack内部还保存了ValueStack Context的引用。(见下页的关系图)
<s:debug>标签可以在jsp页面中查看ValueStack和其关联的Context对象中的信息。
如果不经过struts2的过滤器拦截就直接访问jsp页面,那么其中使用的<s:debug>,<s:text>,<s:property value="%{getText()}">等struts2标签都会报告TagUtil.getStack方法抛出的异常。
获取ValueStack对象的代码如下:
ValueStack stack = ActionContext.getContext().getValueStack();
ValueStack提供了如下一些方法管理其内部的堆栈:
push和pop方法分别对堆栈进行压栈和弹栈。
set方法用于在栈顶的Map对象中设置一个条目,如果栈顶不是一个Map对象,则创建一个Map对象并将其压入栈顶。实验结果:set方法好像不能设置栈顶不同JavaBean对象的属性。

Struts2框架为OGNL Context内部初始填充的几个重要的key:
parameters一个map对象
request 一个map对象
session 一个map对象
application 一个map对象
attr 一个map对象

2、OGNL基础与ValueStack的有关方法:
OGNL(对象图导航语言,Object Graph Navigation Language)是一种用于从ValueStack对象与其关联的Context上下文中获取的值的表达式,最基本的语法如下:
1.可以用#key的形式访问OGNL Context对象中的各个key对应的对象,并可以采用点(.)操作符进行多级导航调用对象的属性和方法,例如,#application、#session.attr1、#key1.sayHello();对于map对象,map.attr不是map.getAttr()方法,而是表示map.get(“attr1”)。
2.如果要访问根对象的属性或方法,则可以省略#key,直接访问该对象的属性和方法。 struts2修改了OGNL表达式的默认属性访问器,它不是直接访问根对象ValueStack的属性或方法,而是在ValueStack内部的堆栈中所有对象上逐一查找该属性或方法,搜索顺序是从栈顶对象开始寻找,依次往下,直到找到为止,例如,sayHello()表示调用堆栈中某个对象的sayHello()方法。
3.特例:如果引用名前面没有#,且valueStack中存储的各个对象没有该属性,则把该名称当作Context对象中的某个key来检索对应的对象,但这种方式不支持点(.)操作符。
ValueStack提供了如下一些方法管理其内部的堆栈和关联的Context:
setValue为ognl表达式寻址到的对象设置属性值。
findValue方法使用OGNL表达式获取结果。
findString方法对findValue方法获取的结果调用转换器转成字符串,如果该对象的类型没有相关转换器,则调用toString方法,并返回结果字符串。一个特殊之处:如果不用#前缀访问ValueStack Context中的对象,则该对象必须是String类型。

<s:property>标签用于输出某个OGNL表达式的值,可以认为其内部使用的是ValueStack对象的findString方法。
如果没有设置value属性,则输出ValueStack栈顶的对象。
特例:如果采用不加#前缀的方式输出Context中的某个对象,这个对象必须是string类型。
<s:push>标签用于将OGNL表达式的值压入栈顶。
看<s:push>标签的帮助,可以知道有一个为top的特殊OGNL表达式,表示栈顶的对象。
<s:bean>标签用于实例化一个JavaBean对象,并将其压入栈顶。
如果设置了var属性,还会将实例化的对象存储进ValueStack关联的Context中。
实验步骤:
查看<s:debug>标签的执行结果。
用<s:push>标签把Context中的一个对象压入栈顶,再查看<s:debug>标签的执行结果,注意<s:debug>标签要位于<s:push>标签对之间。
用<s:bean>标签用于实例化一个java.util.Date实例对象,查看<s:debug>标签的执行结果,注意<s:debug>标签也要位于<s:push>标签对之间;接着设置其var属性,再查看<s:debug>标签的执行结果。

<s:set>标签用于将某个值存入指定范围域中,通常用于将一个复杂的ognl表达式用一个简单的变量来进行引用。
scope属性:指定变量被放置的范围,该属性可以接受application、session、request、 page或action(context)。该属性的默认值为action,文档说即表示同时存储进request作用域和OGNL Context中,但实验结果是只存储进了OGNL Context中。
value属性:赋给变量的ognl表达式结果.如果没有设置该属性,则将ValueStack栈顶的值赋给变量。
<s:if/elseif/else>等标签用于判断test属性中指定的ognl表达式的结果是否为true,为真则执行标签体重的内容。
<s:iterator>标签用于迭代一个OGNL集合,并逐一将迭代出来的元素压入栈顶和弹栈。
status属性:创建代表当前迭代状态的IteratorStatus对象,并指定将其存储进ValueStack Context中时的key。
输出迭代后的ValueStack栈顶对象的属性并利用迭代状态的示例代码如下:
<s:iterator value="#request" status="status">
<tr class='<s:property value="#status.odd ? 'odd':'even'"/>' >
<td><s:property value="key"/>::::<s:property value="value"/></td>
</tr>

3、OGNL的语法细节:
参看ognl的参考手册
类似EL表达式的JavaBean属性访问和索引访问,例如,可以用”#parameter.id[0]”或”#parameter[‘id’][0]”访问名称为id的请求参数。
问题:ValueStack Context有一个名称为com.opensymphony.xwork2.ActionContext.locale的key,使用一个怎样的OGNL表达式可引用这个key对应的值对象呢?答:可以先从request中得到valueStack,再从ValueStack获得context,再从context中用[]的方式获取。
支持类静态方法调用和属性访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format(‘foo %s’, ‘bar’)或@cn.itcast.Constant@APP_NAME;
session.attribute[“foo”]等效于session.getAttribute(“foo”)方法。
在OGNL中可以写很大的整数,例如,<s:property value="%{1111111111111111111111H.bitLength()}"/>,而在java中则不能直接写1111111111111111111111这么大的整数。
对当前值可以进一步操作,<s:property value=“110H.intValue().(#this<112?#this*2:#this/2)”/>,其中.(#this …..)部分相当于定义了一个匿名方法,并调用这个匿名方法,方法的代码就是()里面的内容。
Struts2扩展的特殊功能
[n]表示从原来堆栈中截取一个子堆栈并对这个子堆栈进行操作,子堆栈为原始堆栈的栈顶开始的索引号为n的元素一直到栈底,例如,[1].age表示从原始堆栈中的索引号为1的对象(即第二个对象)开始查找age属性,以找到的第一个为准。
top表示ValueStack栈顶的对象,[0].top和top表示同一个对象。

{}用于创建List集合对象,其中的各个元素之间用逗号分隔。
<s:set value=“{1,3,5,7}” var=“list”/>
采用类似Java的语法创建数组
<s:set value=“new int[]{1,3,5,7}” var=“array”/>
<s:set value=“new int[4]” var=“array”/>
#{}用于创建Map集合对象,其中的各个元素之间用逗号分隔,元素的key和value之间采用冒号分隔。另外,还可以指定Map实例对象的类型。
<s:set value=“#{‘lhm’:96,’zxx’:93,’xpc’:97}”
<s:set value=“#@java.util.LinkedHashMap@{‘lhm’:96,’zxx’:93,’xpc’:97}”
in与not in操作符用于判断某个值是否位于某个集合中。
集合伪属性:size/isEmpty/iterator/keys/values/next/hasNext

投影就是拿着集合中的每个元素去进行运算,各个元素运算的结果组成一个新集合,新集合中的元素个数与原始集合中的元素个数相同。
<s:property value=“persons.{name}”/>
<s:property value=“{5,3,2}.{#this*2}”/>
过滤就是拿着集合中的每个元素去进行布尔运算,运算的结果为true,则将该元素保存到新集合中去。
?:获得所有符合逻辑的元素。
<s:property value=“{5,3,2}.{? #this }”/>
^:获得符合逻辑的第一个元素。
<s:property value=“{5,3,2}.{^ #this>3 }”/>
$:获得符合逻辑的最后一个元素。
<s:property value=“{5,3,2}.{$ #this>2 }”/>

转换成boolean类型
整数0转换为false
值为0的字符转化为false
Null对象转化为false
投影和选择操作符(e1.{e2} and e1.{?e2})前面的内容会被转换成集合
Map会被转化成其values属性返回的集合
数字会被转换成从0开始到比该数字小1的所有数字的集合。
单个对象被转换成仅仅只含有该对象的集合。

4、在配置文件中使用OGNL:
在struts2的各种配置文件中也可以使用OGNL,只需要将OGNL表达式套在${}中,即${ognl表达式}。
总结列表:对${ognl}的总结涉及一些大家暂时还没学习到的内容,大家可以在学完相关知识后再来看这个总结列表
在struts.xml文件的<result>元素中,经常需要使用${属性名}表达式访问action中的属性,表达式里的属性名对应action中的属性。如下:
<result type="redirect">view.jsp?id=${id}</result>
在校验配置文件的<message>元素中,可能需要使用${getText(‘key’)}表达式访问国际资源包的消息。
在国际化资源文件中,也可以使用${ognl表达式},例如,使用${getText(‘key’)}表达式来获取国际化消息填充另一个资源的占位符。
在jsp页面中可以使用${获取属性的ognl表达式},但不能在${}使用调用方法的ognl表达式,否则,会把它当作el表达式的自定义函数。

<s:url>和<s:a>标签的四个好处:
使用<s:url action=“” namespace=“” method=“”/>不用关心web应用程序的路径和Action映射的扩展名。<s:url>中没有指定namespace属性时,将根据浏览器当前所访问的url地址来推测包名,并与action属性指定的内容一起生成最终的url地址。
可以自动附加jsessionid参数进行url重写。
可以对参数信息进行url编码。 备注:jstl中的<c:url>标准标签也有<s:url>标签的后两个作用。
直接使用<s:url />标签可以获得当前地址,只有使用includeParams属性会带上原来的请求参数。大型网站的链接地址总是要带上userid之类的信息。
实验步骤:
启动一个新浏览器访问第一个Action,查看<s:url>生成的超链接地址,刷新的访问,再查看<s:url>生成的超链接地址,比较差异说明<s:url>标签的url重写功能。
在<s:url>的action属性值的路径后也可以直接加参数,但不能对其中的中文进行编码。使用<s:param>子标签设置一个或多个参数,可以完成中文参数的url编码。
再写一个<s:url>标签,其中不带任何属性,并在访问地址中增加一些参数,查看其生成的url地址;接着设置其includeParams属性,再查看结果。这里应该打开标签的帮助文档进行讲解。
为上面的<s:url>标签增加var属性,并用<s:property>标签输出var属性指定的变量。
问题:使用s:url>标签的value属性时,其中的值不会当作OGNL表达式处理,而是当作普通字符串处理,如果value的内容要根据表达式运算,如何做?
在value属性值中使用%{},struts2就会把其中内容当作ognl表达式处理。


测试代码:

<%@page import="com.opensymphony.xwork2.ActionContext"%>
<%@page import="java.util.List"%>
<%@page import="java.util.Arrays"%>
<%@page import="cn.itcast.struts2valuestack.domain.User"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Ognl标签应用</title>
</head>
<bodys>
<!--
value : ognl表达式
default : 默认值
escapeHtml : true 如果文本中有标签,那么转义
-->
<s:property value="name" default="表达式没有找值" escapeHtml="true"/><br/>

获取map中值:<s:property value="#name"/><br/>

<!-- #context Ongl内置的命令 -->
获取map中特殊key的值:<s:property value="#context.get('com.opensymphony.xwork2.ActionContext.locale')"/><br/>
获取map中特殊key的值:<s:property value="#context['com.opensymphony.xwork2.ActionContext.locale']"/><br/>

获取ValueStack栈:<s:property/><br/>

<!-- 不加#在栈中查找属性,如果没有找到,它在下面Map中查找,并且强行转为String类型 -->
获取map中的值:<s:property value="haha"/><br/>


<!--
value : ognl表达式
通过ognl表达式获取值,并把值压入栈顶 ,标签结束弹栈
-->
<s:push value="#currentDate">
当前毫秒数:<s:property value="time"/><br/>
</s:push>


<!--
var : 存储在map中变量的名字
name : 需要创建对象的类全名
-->
<s:bean var="myDate" name="java.util.Date"></s:bean>


<!--
var : 存储在作用域中变量的名字
value : ognl表达式
scope : application, session, request, page, or action(map),默认是action
-->
<s:set var="varxxx" value="name" scope="action"/>

<!--
把ognl强行当初一个字符串处理,%{'字符串'}
-->
<s:set var="varyyy" value="%{'你好啊'}" scope="action"/>

<!-- if elseif esle -->
<!-- test:ognl表达式 -->
<s:if test="1<0">
1<0(if)
</s:if>
<s:elseif test="1!=1">
1!=1(elseif)
</s:elseif>
<s:else>
1==1(else)
</s:else>


<%
User user1 = new User("张三","123456");
User user2 = new User("李四","123456");
User user3 = new User("王五","123456");
User user4 = new User("赵六","123456");
User user5 = new User("田七","123456");
List<User> users = Arrays.asList(user1,user2,user3,user4,user5);
ActionContext.getContext().put("users",users);
%>

<%-- <s:iterator >迭代器 --%>
<h3>第一种迭代(可以使用)</h3>
<table border="1">
<tr>
<th>用户名</th>
<th>密码</th>
</tr>
<!--
var : 没迭代一次,每个对象名字
value : ognl表达式
-->
<s:iterator var="item" value="#users">
<tr>
<td>
<s:property value="#item.userName"/>
</td>
<td>
<s:property value="#item.password"/>
</td>
</tr>
</s:iterator>
</table>

<h3>第二种迭代(推荐使用)</h3>
<table border="1">
<tr>
<th>序号</th>
<th>用户名</th>
<th>密码</th>
</tr>
<!--
var : 没迭代一次,每个对象名字
value : ognl表达式
status : 迭代器状态对象,比如:index,count....,对应org.apache.struts2.views.jsp.IteratorStatus类
"把当前迭代出来的对象,压入栈顶,迭代完后,弹栈"
-->
<s:iterator value="#users" status="mystatus">
<tr>
<td>
<s:property value="#mystatus.count"/>
</td>
<td>
<s:property value="userName"/>
</td>
<td>
<s:property value="password"/>
</td>
</tr>
</s:iterator>
</table>

<%
//request.setAttribute("userName","我是request中东东....");
//System.out.println(request);
%>

<h3>第三种迭代(不推荐使用)</h3>
<table border="1">
<tr>
<th>用户名</th>
<th>密码</th>
</tr>
<!--
var : 每迭代一次,每个对象名字
value : ognl表达式
"把当前迭代出来的对象,压入栈顶,迭代完后,弹栈"
-->
<s:iterator value="#users">
<tr>
<td>
${userName}
</td>
<td>
${password}
</td>
</tr>
</s:iterator>
</table>

<h3>OGNL的语法细节</h3>

<%--
String.format("hello %s !","张三");
支持类静态方法调用和属性访问 ,需要加入配置

<!-- ognl表达式执行静态方法调用 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
--%>
<s:property value="@java.lang.String@format('hello %s','张三')"/><br/>

<%--
Struts2扩展的特殊功能
--%>
获取栈顶:<s:property/><br/>
获取栈顶:<s:property value="top"/><br/>
[n(number)]:<s:property value="[1].top"/><br/>

<h3>OGNL的语法细节——集合对象与操作</h3>

<%--{}用于创建List集合对象,其中的各个元素之间用逗号分隔 --%>
<s:set var="myList" value="{1,2,3,4,5,6,7,8}"/>
<s:property value="#myList[0]"/><br/>

<!-- 采用类似Java的语法创建数组 -->
<s:set value="new int[]{1,3,5,7}" var="array1"/>
<s:property value="#array1"/><br/>
<s:set value="new int[4]" var="array2"/>
<s:property value="#array2"/><br/>

<%--
#{}用于创建Map集合对象,其中的各个元素之间用逗号分隔,元素的key和value之间采用冒号分隔。
另外,还可以指定Map实例对象的类型。
--%>
<s:set value="#{'key1':'value1','key2':123456}" var="myMap"/>
<s:property value="#myMap"/><br/>

<!-- in与not in操作符用于判断某个值是否位于某个集合中。 -->
in:<s:property value="5 in #myList"/><br/>
not in:<s:property value="5 not in #myList"/><br/>

<!-- 集合伪属性:size/isEmpty/iterator/keys/values/next/hasNext -->
集合伪属性:<s:property value="#myList.size"/><br/>



<h3>OGNL的语法细节——集合的投影与过滤</h3>
<%
User user11 = new User("张三","123456");
User user12 = new User("李四","123456");
User user13 = new User("王五","123456");
User user14 = new User("赵六","123456");
User user15 = new User("田七","123456");
List<User> myusers = Arrays.asList(user11,user12,user13,user14,user15);
ActionContext.getContext().put("myusers",myusers);
%>
<%-- 投影就是拿着集合中的每个元素去进行运算,各个元素运算的结果组成一个新集合,新集合中的元素个数与原始集合中的元素个数相同。--%>
<s:property value="#myusers.{userName}"/><br/>

<%-- #this集合中的每一个元素 --%>
<s:property value="{5,3,2}.{#this*2}"/><br/>

<%--过滤就是拿着集合中的每个元素去进行布尔运算,运算的结果为true --%>

<!-- ?:获得所有符合逻辑的元素 -->
<s:property value="{5,3,2}.{? #this>0}"/><br/>

<!-- ^:获得符合逻辑的第一个元素 -->
<s:property value="{-1,5,3,2}.{^ #this>0}"/><br/>

<!-- $:获得符合逻辑的第一个元素 -->
<s:property value="{5,3,2}.{$ #this>0}"/><br/>

<a href="testOgnl">在配置文件中使用OGNL</a>


<%--<s:url>与<s:a>标签 --%>
<!--
action : struts2中action的名字
namespace : struts2package的命名空间

url 它会自动加上appPath(<Context path="/xxx"/>)
-->
<br/>
<a href="<s:url action="testOgnl" namespace="/xxx"></s:url>">
testOgnl
</a>
<br/>
<%ActionContext.getContext().put("id","010");%>
<%--
把ognl当成一个字符串执行 %{'字符串'}
把一个字符串当成ognl表达式执行 %{表达式}

includeParams : 把"get"请求参数,加载url后面
includeParams : 把"get"和"post"请求参数,加载url后面
--%>
<s:a action="testOgnl?username=009&id=%{#id}" namespace="/xxx" includeParams="all">
testOgnl
<%--value : ognl表达式 ,如果使用<s:param>配置请求参数,名字不能一样--%>
<s:param name="username">007</s:param>
<%--value : ognl表达式 --%>
<s:param name="username" value="%{'008'}"></s:param>
</s:a>

<s:debug/>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Struts2面试题包括以下内容: 1. SpringMVC与Struts2的主要区别。 2. Struts2如何访问HttpServletRequest、HttpSession和ServletContext三个域对象? 3. Struts2的拦截器有什么用途? 4. Struts2的默认包struts-default有什么作用? 5. Struts2,Action并没有直接收到用户的请求,那它为什么可以处理用户的请求?又凭什么知道一个请求到底交给哪一个Action来处理? 6. Struts2,Action通过什么方式获取用户从页面输入的数据,又是通过什么方法把数据传给视图层显示的? 7. struts2的执行流程。 8. 具有相同名称的一组值,struts2如何实现封装? 9. 简述struts2值栈的原理和生命周期? 10. 简述Struts2异常处理机制? 11. 谈一下你的项目选择Struts2的理由? 12. 阐述Struts2的Action如何编写,是否采用单例?[1] Struts2是一个经典的MVC框架,与Struts1相比,有以下区别: 1. 核心控制器改成了过滤器,比Servlet的级别要高。 2. Struts1要求业务类必须继承Action或dispatchAction,而Struts2只需要提供一个POJO类。 3. 绑定值到业务类时,Struts1是通过ActionForm,而Struts2是通过模型或属性驱动直接绑定到Action属性。 4. Struts1严重依赖于Servlet的API,而Struts2则脱离了Servlet的API。 5. 管理Action时,Struts1是单例模式,而Struts2是每个请求产生一个实例。 6. 在表达式的支持上,Struts2不仅有JSTL,还有功能更加强大的OGNL表达式。 7. Struts1的类型转换是单向的,而Struts2是双向的。 8. Struts2提供了拦截器,可以在访问Action之前或之后增加如权限拦截等功能。 9. Struts2提供了国际化资源文件管理实现。 10. Struts2支持多种视图类型,如JSP、Freemarker、Velocity等。[2] 在使用Struts2时,可能会遇到一些常见的问题,例如: 1. 表单重复提交的问题可以通过使用令牌机制来解决。 2. 国际化必须经过Action来实现。 3. 使用模型驱动时,可能会出现地址内存不一致的问题,可以通过对象拷贝来解决。 4. 在页面使用转发时可能会报404错误,可以通过过滤器改变请求地址来解决。 5. 在使用字符串时需要注意使用双引号而不是单引号。 6. 当校验出错时,需要跳转到相应的页面,可以使用通配符来解决。[3] 总结起来,Struts2面试题主要涉及Struts2与其他框架的区别、Struts2的核心概念和特性,以及在实际使用可能遇到的问题和解决方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值