OGNL表达式#parameters 用法.score为什么要

Struts2漏洞分析之Ognl表达式特性引发的新思路-系统/上网/安全-就爱阅读网
Struts2漏洞分析之Ognl表达式特性引发的新思路
0x01 摘要在Ognl表达式中,会将被括号&()&包含的变量内容当做Ognl表达式执行。Ognl表达式的这一特性,引发出一种新的攻击思路。通过将恶意代码存储到变量中,然后在调用Ognl表达式的函数中使用这个变量来执行恶意的代码,从而实现攻击。本文将会以CVE-漏洞作为示例,描述这种利用思路的具体过程。但是,本文的内容绝不仅仅局限于这个漏洞,在实际的审计过程中,这种思路可以用来发现很多类似的漏洞。0x02 背景介绍与原理分析这个漏洞和CVE-很相似,都是是通过Ognl表达式执行java,来达到远程代码执行的效果。我们先来回顾下CVE-漏洞,它是攻击者通过get方法提交Ognl表达式,直接来调用java的静态方法来实现代码执行。这个问题爆出来后,struts官方加强了对于用户提交内容的审核,禁止使用&#&、&\&等特殊字符作为参数提交。那么这样我们就没有办法远程执行Ognl表达式了吗?当然不,Ognl给我们提供了另一种执行它的方法,我们来看下官方文档中一部分的内容:For example, this expression#fact(30H)looks up the fact variable, and interprets the value of that variable as an OGNL expression using the BigInteger representation of 30 as the rootobject. See below for an example of setting the fact variable with an expression that returns the factorial of its argument. Note that there is an ambiguity in OGNL's syntax between this double evaluation operator and a method call. OGNL resolves this ambiguity by calling anything that looks like a method call, a method call. For example, if the current object had a fact property that held an OGNL factorial expression, you could not use this approach to call itfact(30H)because OGNL would interpret this as a call to the fact method. You could force the interpretation you want by surrounding the property reference by parentheses:(fact)(30H)Ognl表达式给我们提供了&#fack()&这样调用上下文对象方法的功能,我们需要留意的是红色文字,大概的意思如下:如果你想要调用上下文环境中对象的方法,可以使用&(fact)()&这种格式来书写。而在测试过程中发现,(one)(two)这种形式的Ognl表达式,会先将one当做另一个Ognl表达式先执行一遍,然后再继续他后面的工作。这样的话,如果程序在调用某一可以执行Ognl表达式的函数时,我们通过变量将恶意的表达式传入,那么,struts所做的那些过滤便成为了一扇&透明的门&。0x03 实例模拟与跟踪在正常的调用中,我们找到了setValue这个函数,它的作用是根据Ognl表达式对目标进行赋值,在这个过程中Ognl表达式会执行。而struts2中通过在继承ActionSupport的类中,设置setter和getter方法,可以实现用户通过get和post方法直接为私有成员变量赋值。这种方法便会用到setValue这个函数。下面我们来搭建一个这样的类: www.2cto.comimport ognl.Oimport com.opensymphony.xwork2.ActionS&public class HelloWorld extends ActionSupport{&&& private String tang3;&&& public void settang3(String tang3) {&&&&&&& this.tang3 = tang3;&&& }&&& public String gettang3() {&&&&&&& return tang3;&&& }&&& public String execute() throws Exception {&&&&&&& System.out.println(tang3);&&&&&&& return SUCCESS;&&& }}上面的这段代码只是简单的实现了接受参数&tang3&,并将它的内容打印到控制台中的功能。在跟踪它的过程中发现,用户提交的参数时,会通过调用com.opensymphony.xwork2.interceptor.ParametersInterceptor这个类中的set Parameters方法来获取参数,而这个方法会调用setValue函数,代码如下:if (acceptableName) {&&& Object value = entry.getValue();&&& try {&&&&&&& stack.setValue(name, value); //红色字体&&& } catch (RuntimeException e) {注意红色字体部分,name参数是Ognl表达式部分,value是被赋值的对象,而之前的CVE-漏洞,也是通过这个函数执行的Ognl表达式。下面我们来看下如何结合前面讲到的内容来让这个函数执行我们需要的Java代码。按照之前我们所说的Ognl表达式特性,我们应该构造这样的url:/helloword.acton?tang3=&OGNL statement&&(tang3)('meh')=1提交这样的url后,web server将会做两件事,第一,将Ognl表达式内容存进了tang3变量中;第二,名为(tang3)('meh')的http参数将会被当做另一个Ognl表达式执行,并且action属性tang3将会从action中恢复内容,即变成了(&OGNL statement&)(&meh&)。因为http参数传入到变量中会自动进行url解码,那么我们便可以使用url编码&#&这样的特定字符,来绕过正则表达式的过滤。在构造语句中还需要注意的一点就是,我们要确保tang3属性中的内容先被执行。所以这里需要一个小技巧,在提交参数时,使用z[(tang3)(&meh&)]=1这种形式的参数,可以确保tang3变量被首先执行。下面我们构造一条可以弹出计算器的url:/helloworld.action?tang3=(#context[&xwork.MethodAccessor.denyMethodExecution&]= new java.lang.Boolean(false), #_memberAccess[&allowStaticMethodAccess&]=true, @java.lang.Runtime@getRuntime().exec('calc'))(meh)&z[(tang3)('meh')]=1url编码后:/helloworld.action?tang3=%28%23context[&xwork.MethodAccessor.denyMethodExecution&]%3D+new+java.lang.Boolean%28false%29,%20%23_memberAccess[&allowStaticMethodAccess&]%3dtrue,%[email]20@java.lang.Runtime[/email]@getRuntime%28%29.exec%28%27calc%27%29%29%28meh%29&z[%28tang3%29%28%27meh%27%29]=1效果如下图:从最下面的红色框中,我们可以看出,控制台打印出的tang3变量的内容,就是我们刚才输入的代码。0x04 总结1.&这个漏洞的利用方法,存在局限性,目标代码需要有一个私有成员变量可以直接通过http参数赋值。同时,攻击者需要知道这个私有成员的名字。不过从代码审计的角度来看,可以很容易发现这种问题。但是,由于大部分使用struts框架搭建的网站都是闭源的,导致很难进行白盒测试。2.&这个问题在struts2.3.1.2版本之后便已经修复了,官方补丁的修复原文如下:The regex pattern inside the ParameterInterceptor was changed to provide a more narrow space of acceptable parameter names.Furthermore the new setParameter method provided by the value stack will allow no more eval expression inside the param names.修复方法就是,进一步减少ParameterInterceptor中白名单包含的内容,并且禁止参数名执行正则表达式3.&Ognl表达式的强大,能够明显的从struts所爆出的这些漏洞中看出。只要存在调用Ognl表达式的函数,都有可能出现代码执行问题。我在之前的《Struts2漏洞浅析之Ongl代码执行分析》一文中,称findValue为struts中的eval函数,明显的有些狭隘了。Ognl表达式才称得上是eval函数,在代码的编写的过程中要小心的处理它的表达式。4.&再次重申在本文开始处所强调的,这篇文章并不仅仅局限于CVE-这个漏洞,而且,它已经被修补了。本文的目的是,希望读者能够通过这个漏洞,了解到通过括号包裹变量,执行Ognl表达式这个特性,以此为我们在日后的审计增加一个思路。转自:https://www.t00ls.net/viewthread.php?tid=21197&就爱阅读www.92to.com网友整理上传,为您提供最全的知识大全,期待您的分享,转载请注明出处。
邀请好友扫一扫分享给TA或者 长按上图保存二维码,使用微信扫一扫右上角的"相册"扫码,再分享好友或朋友圈OGNL_百度百科
清除历史记录关闭
声明:百科词条人人可编辑,词条创建和修改均免费,绝不存在官方及代理商付费代编,请勿上当受骗。
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的去存取对象的属性。
OGNL基本介绍
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。这样可以更好的取得数据。
OGNL可以让我们用非常简单的表达式访问对象层,例如,当前环境的根对象为user1,则表达式person.address[0].province可以访问到user1的person属性的第一个address的province属性。
这种功能是模板语言的一个重要补充,像jsp2.0,velocity,jelly等等,都有类似的功能,但是ognl比它们完善得多,而且以一个独立的lib出现,方便我们构建自己的框架。
webwork2和现在的.x中使用OGNL取代原来的EL来做界面数据绑定,所谓界面数据绑定,也就是把界面元素(例如一个textfield,hidden)和对象层某个类的某个属性绑定在一起,修改和显示自动同步。
和1.x的formbean相比,这样做的好处非常明显:在中不需要为每个页面专门写formbean,可以直接利用对象层的对象。例如在对象设计中,我们的User和Person是分开的,而一个注册用户界面需要填写两者的内容,在webwork中,就可以保持后台的对象结构,把属于用户属性的界面元素用user.person.xxx绑定,把属于账号属性的界面元素用user.xxx绑定。
OGNLStruts 2
OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源语言,使页面更简洁;
支持(如+-*/),比普通的标志具有更高的自由度和更强的功能;
Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:
支持对象方法调用,如xxx.doSomeSpecial();
支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAME;
支持赋值操作和串联,如price=100, discount=0.8, calculatePrice(price*discount),这个表达式会返回80;
访问OGNL上下文(OGNL context)和ActionContext;
操作集合对象。
可以直接new一个对象
OGNL是通常要结合Struts 2的标志一起使用。主要是#、%和$这三个符号的使用。使用方法如下:
新建名为Struts2_OGNL的Web工程
#”主要有三种用途:
访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性: 名称 作用 例子
parameters 包含当前参数的Map #parameters.id[0]作用相当于request.getParameterValues("id").get(0);
request 包含当前HttpServletRequest的属性(attribute)的Map #request.userName相当于request.getAttribute("userName")
session 包含当前HttpSession的属性(attribute)的Map #session.userName相当于session.getAttribute("userName")
application 包含当前应用的ServletContext的属性(attribute)的Map #application.userName相当于application.getAttribute("userName")
attr 用于按request & session & application顺序访问其属性(attribute) #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止
用于过滤和投影(projecting)集合,如books.{?#this.price&100};
构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。
下面让我们它们的具体写法,首先是Action类代码:
package tutorial.
import java.util.LinkedL
import java.util.L
import java.util.M
import javax.servlet.ServletC
import javax.servlet.http.HttpServletR
import org.apache..interceptor.ServletRequestA
import org.apache.struts2.interceptor.SessionA
import org.apache.struts2.util.ServletContextA
import tutorial.model.B
import com.opensymphony.xwork2.ActionS
public class OgnlAction extends ActionSupport implements ServletRequestAware, SessionAware, ServletContextAware {
private static final long serialVersionUID = 1L;
private HttpServletR
private ServletC
public void setServletRequest(HttpServletRequest request) {
this.request =
@SuppressWarnings("unchecked")
public void setSession(Map session) {
this.session =
public void setServletContext(ServletContext application) {
this.application =
public List getBooks() {
public String execute() {
request.setAttribute("userName", "Max From request");
session.put("userName", "Max From session");
application.setAttribute("userName", "Max From application");
books = new LinkedList();
books.add(new Book("978 ", "Code Complete, Second Edition", 32.99));
books.add(new Book("978 ", "The Art of Project Management", 35.96));
books.add(new Book("978 ", "Design Patterns: Elements of Reusable Object-Oriented Software", 43.19));
books.add(new Book("978 ", "Information Architecture for the World Wide Web: Designing Large-Scale Web Sites", 25.19));
books.add(new Book("978 ", "Software Estimation: Demystifying the Black Art", 25.19));
return SUCCESS;
以上代码分别在request、session和application的范围内添加“userName”属性,然后再在JSP页面使用OGNL将其取回。
下面是Ognl.jsp的代码,内容如下:
访问OGNL上下文和Action上下文
parameters.userName:
request.userName:
session.userName:
application.userName:
attr.userName:
用于过滤和投影(projecting)集合
Books more than $35
&s:iterator value="books.{?#this.price & 35}"&
&s:property value="title" /& - $&s:property value="price" /&&br&
&/s:iterator&
The price of "Code Complete, Second Edition" is:
The value of key "foo1" is
清单3 WebContent/Ognl.jsp 以上代码值得注意的是“”,因为“books.{?#this.title=='Code Complete, Second Edition'}.{price}”返回的值是集合类型,所以要用“[索引]”来访问其值。 最后是Struts 2的配置文件.xml,内容如下:
“%”符号的用途是在标志的属性为字符串类型时,计算OGNL的值。
“$”有两个主要的用途,用于在国际化资源文件中,引用OGNL表达式。在Struts 2和i18n中配置文件
OGNL stands for Object-Graph Navigation L it is an expression language for getting and setting properties of Java objects. You use the same expression for both getting and setting the value of a property.
The ognl.Ognl class contains convenience methods for evaluating OGNL expressions. You can do this in two stages, parsing an expression into an internal form and then using that internal form to either set or get the or you can do it in a single stage, and get or set a property using the String form of the expression directly.
OGNL started out as a way to set up associations between UI components and controllers using property names. As the desire for more complicated associations grew, Drew Davidson created what he called KVCL, for Key-Value Coding Language, egged on by Luke Blanshard. Luke then reimplemented the language using ANTLR, came up with the new name, and, egged on by Drew, filled it out to its current state. Later on Luke again reimplemented the language using JavaCC. Further maintenance on all the code is done by Drew (with spiritual guidance from Luke).
We pronounce OGNL as a word, like the last syllables of a drunken pronunciation of "orthogonal."
OGNL表达式
OGNL支持各种纷繁复杂的表达式。但是最最基本的表达式的原型,是将对象的引用值用点串联起来,从左到右,每一次表达式计算返回的结果成为当前对象,后面部分接着在当前对象上进行计算,一直到全部表达式计算完成,返回最后得到的对象。OGNL则针对这条基本原则进行不断的扩充,从而使之支持对象树、、容器的访问,甚至是类似SQL中的投影选择等操作。
1. 基本对象树的访问
对象树的访问就是通过使用点号将对象的引用串联起来进行。
例如:xxxx,xxxx.xxxx,xxxx. xxxx. xxxx. xxxx. xxxx
2. 对容器变量的访问
对容器变量的访问,通过#符号加上进行。
例如:#xxxx,#xxxx. xxxx,#xxxx.xxxxx. xxxx. xxxx. xxxx
3. 使用操作符号
OGNL表达式中能使用的操作符基本跟Java里的操作符一样,除了能使用 +, -, *, /, ++, --, ==, !=, = 等操作符之外,还能使用 mod, in, not in等。
4. 容器、、对象
OGNL支持对数组和ArrayList等容器的顺序访问:例如:group.users[0]
同时,OGNL支持对Map的按键值查找:
例如:#session['mySessionPropKey']
不仅如此,OGNL还支持容器的构造的:
例如:{"green", "red", "blue"}构造一个List,#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}构造一个Map
你也可以通过任意类对象的进行对象新建:
例如:new Java.net.URL("xxxxxx/")
5. 对或变量的访问
要引用类的静态方法和字段,他们的表达方式是一样的@class@member或者@class@method(args):
例如:@com.javaeye.core.Resource@ENABLE,@com.javaeye.core.Resource@getAllResources
6. 方法调用
直接通过类似Java的方法调用方式进行,你甚至可以传递参数:
例如:user.getName(),group.users.size(),group.containsUser(#requestUser)
7. 投影和选择
OGNL支持类似数据库中的投影(projection) 和选择(selection)。
投影就是选出集合中每个元素的相同属性组成新的集合,类似于关系数据库的字段操作。投影操作语法为 collection.{XXX},其中XXX 是这个集合中每个元素的公共属性。
例如:group.userList.{username}将获得某个group中的所有user的name的列表。
选择就是过滤满足selection 条件的集合元素,类似于关系数据库的纪录操作。选择操作的语法为:collection.{X YYY},其中X 是一个选择操作符,后面则是选择用的。而选择操作符有三种:
? 选择满足条件的所有元素
^ 选择满足条件的第一个元素
$ 选择满足条件的最后一个元素
例如:group.userList.{? #txxx.xxx != null}将获得某个group中user的name不为空的user的列表。
清除历史记录关闭博客分类:
OGNL(Object Graphic Navigation Language,对象图导航语言)是一种功能强大的EL(Expression Language,表达式语言,JSP2.0规范),Struts2的核心表达式语言,OGNL是一个开源JAVA项目,但因为使用Struts2,我们完全不需要知道OGNL到底里面是什么东东,只需要按照Struts2的规则知道如何使用就OK了!第二章已经说过(请参看第二章的OGNL结构图),Struts2将Action中的实例压入值栈(ValueStack,值栈,Struts2的根对象,可以把它简单的理解为List,只不过它遵循堆栈的特点,先进后出!),session等放入Context Map中,然后使用OGNL遍历对象结构图进行操作。
在JSP中,session、request、application、attr(如果可以就从pageContext查找,否则就依次到request、session、application中查找)、parameters(用于取URL上的参数,同名的变量可以使用索引)等对象取值时要使用前缀 # 告诉Struts2不要到值栈中查找,例如:(1.)#session.infomation,#session[‘student-information’],OGNL中使用 . 或者[‘’]访问对象的属性,两者的区别是当属性中有“-”等特殊字符时,我们需要使用[‘’];
(2.)URL为http://locaohost:9999/struts01/HelloWorld.ok?name=gold&&password=jsmart,如果我想取name的值,需要这样写#parameters.name,取password的值就是#parameters.password;如果是http://localhost:9999/struts01/HelloWorld.ok?password=gold&&password=jsmart,#parameters.password[0]取的就是gold,#parameters.password[1]=jsmart;
(3.)%{A}所有基于这种形式的内容,都会被解析并到值栈中求值,也就是会到Value Stack中查找A所代表的值;如果你想A被当作字符串原样传递,那么可以这样表示%{‘A’},当然你直接使用A有的时候也是可以的,但为了通用性,建议使用%{‘A’},以免产生不必要的麻烦。
(4.)OGNL操作集合,例如值栈中存在map,我们可以这样访问map[‘a’],表示访问Map中key值为a的value值是多少,map.size访问大小等等。
(5.)OGNL访问类中的静态变量和静态方法:@完整类名@属性名,@完整类名@方法名,例如:
Package net.ilkj.ognl
Public Class A{
Public static final String a=”1”;
Public static String findA()
{
Return “2”;
}
,我们就可以在页面上使用&:sproperty value=”@net.ilkj.ognl.A@a”/&尽心输出!
从上面可以看出,在Struts2中使用OGNL,可以简单看作就是对象.属性。
文章来源:wiki
visionary_2006
浏览: 91827 次
来自: 杭州
&form action=&/user/log ...
知道strtus2 的默认命名空间和 跟命名空间分别在什么地方 ...
高手多多啊。
楼主,写一篇 struts1 的标签 和stru ...
我晕,竟然读到两篇相同的文章!!!
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'OGNL表达式#parameters.score为什么要_百度知道
OGNL表达式#parameters.score为什么要
我有更好的答案
具体实现就是一系列的封装。struts是采用ognl模型,就是对象关系模型,想要得到action中的值,首先的一点这个值要有set和get方法,在你请求action的时候,会重新生成一个action对象--》调用set方法给这个属性赋值
采纳率:93%
来自团队:
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。ValueStack对象
相当于一个栈
,它贯穿整个Action的生命周期,每个Action类的对象实例都会拥有一个ValueStack对象
当Struts2接收到一个*.action
请求后,并不是直接调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点
值栈也位于内存中
,它也是和parameters、request、session、application、attr对象
放在一起的
值栈属于ONGL Context
里面的根对象
。也就是说它位于整个内存中最最重要的地方,所以叫根对象
根对象和另外五个对象是有区别的,根对象可以省写#号
,比如&s:property value="user.username"/&
值栈的生命周期与request请求相关,每次请求产生一个值栈。默认所有的Action会被自动放到值栈里
服务器跳转时共用值栈
假设从一个Action11通过服务器跳转到Action22的话,就意味着这两个Action是共享一个值栈的,因为一次请求只使用一个值栈
这时内存中情况是这样的:首先接收到Action11请求后,会产生一个值栈,在栈顶存放Action11对象以及它所有的属性
然后经过服务器跳转到Action22,这时就会把Action22对象压入值栈的栈顶位置,此时Action11对象以及它的所有属性就位于栈底了
栈的特征是后进先出。于是首先到栈顶的对象里查找是否存在这个属性,如果栈顶的Action22对象中不存在这个属性的话
它就会继续向下寻找直至栈底对象,一直查找是否存在这个属性
如果最后找到该属性的话,那么就会在JSP页面中通过&s:property value="username"/&
输出属性值
如果在Action22和Action11都有一个同名的同类型的username属性的话,那么将输出Action22中的属性值
因为它是先从栈顶开始寻找属性的,值栈的特征就是后进先出
,但有个前提:请求过程是通过服务器跳转的
假设此时想要获取Action11中的username属性的话,就可以使用值栈的Top语法
使用Top语法
获取值栈中的第二个对象的属性:&s:property value="[1].top.username"/&
使用 N 语法
获取值栈中的第二个对象的属性:&s:property value="[1].username"/&
另外值栈还有一个@语法
,例如使用@语法调用Action中的静态方法:&s:property value="@vs@getVOMethod()"/&
@vs@get()等价于@vs1@getVOMethod()
,指的是栈顶对象的静态getVOMethod()方法
同理@vs2@getVOMethod()就是取值栈中第二个对象的静态getVOMethod()方法
客户端跳转时使用各自的值栈
假如中间某一个步骤中出现了客户端跳转的话,那么两个Action所使用的就是两个不同的值栈了
所以在Action22中就不能再使用Action11中的属性了,在最后跳转到的JSP页面中也就无法获取Action11的属性了
也即从Action22跳转到JSP页面时使用的是redirect
的话,那么最后值栈中是没有任何的Action对象的
这个时候我们可以通过链接传参,比如&result type="redirect"&test.jsp?netname=${username}&/result&
意思就是取出Action22中的username属性作为参数,通过浏览器地址栏传递到JSP页面中
然后使用OGNL中的#号
获取Paraments对象的属性,即&s:property value="#parameters.netname"/&
就可以取到值了辅助参考:
手工向值栈中压入对象
正常情况下值栈保存的是Action对象,而我们也可以直接往值栈中添加其它对象,这时可以在Action中添加如下代码
向值栈中添加对象:ActionContext.getContext.getValueStack().push(new Student("沈浪",22));
而且我们手工往值栈中添加的Student对象会位于栈顶
。这是因为Struts2会首先初始化Action,然后才能调用它的方法
初始化Action的时候,便把Action放到值栈中了,然后在执行它的execute()方法时,就又往值栈中添加了Student对象
OGNL是Object-Graph Navigation Language
的缩写,是一种功能强大的表达式语言
通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能
OGNL用得最多的地方就是和Struts2的标签绑定,也可以在配置文件中通过${}
使用OGNL表达式
OGNL中$号的使用
在国际化资源文件中,引用OGNL表达式2..
在struts.xml文件中,引用OGNL表达式
OGNL中%号的使用
可以取出保存在值堆栈中的Action对象,直接调用它的方法2..
如果Action继承了ActionSupport,那么在页面标签中可以使用%{getText('key')}
获取国际化信息辅助参考:
OGNL中#号的使用
OGNL中的#号可以取出堆栈上下文中存放的对象
用于按request&&session&&application顺序访问其属性
#attr.userName相当于按顺序从三个范围读取userName属性直到找到为止
包含当前HttpServletRequest的属性的Map
#request.userName相当于request.getAttribute("userName")
包含当前HttpSession的属性的Map
#session.userName相当于session.getAttribute("userName")
application
包含当前应用的ServletContext的属性的Map
#application.userName相当于application.getAttribute("userName")
parameters
包含当前HTTP请求参数的Map
#parameters.id[0]相当于request.getParameter("id")
获取Action中的属性值或者Action中的对象的某某属性值
利用&s:property/&
标签可以直接获取Action中的引用类型user里面的username属性
同样可以通过user.address.addr获取user中引用类型address中的addr属性的值
像这种一层一层往下传递的访问方式,即所谓的导航
,也就是一步步的往下调用
调用Action的对象里面的普通方法
默认的会把Action放到值栈里面,而值栈在访问的时候,并不需要值栈的名字
当我们调用&s:property value="user.getVOMethod()"/&
它会自动到值栈里面查找Action对象里面有没有user对象,然后它就发现有user
然后它就再找user里面有没有getVOMethod()方法,然后它发现有,于是调用getVOMethod()
实际上调用User中的getVOMethod()方法的过程与获取表单中的姓名密码的方式都是相同的都是到值栈里面查找
,找是否存在user对象,如果存在,接着查找user中是否存在某某属性或方法
调用Action中的静态方法
同样我们也可以在JSP页面中写一个OGNL表达式调用Action中的静态方法
调用Action中的静态方法时,与调用user对象的getVOMethod()方法的过程,是截然不同的
此时value的写法是固定的,以@开头,后面跟上具体的包名,然后@加上静态方法
比如&s:property value="@com.jadyer.action.LoginAction@getStatic()"/&
另外user对象是LoginAction中的一个属性,这个属性会自动的放到值栈里面而值栈调用的时候,不用加上@或者包名等等
,所以直接user.getVOMethod()就可以了
调用JDK类中的静态方法
可以使用&s:property value="@@floor(46.58)"/&
输出floor()的执行结果
这就意味着如果不在@@中指定类
的话,默认的就表示java.lang.Math类
当前大多数情况下,我们都不会省略这个类,都会写全了的,然后在后面加上静态方法
集合的伪属性
OGNL能够引用集合的一些特殊的属性,这些属性并不是JavaBean模式,例如size()、length()
当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性
比如获取List的大小:&s:property value="testList.size"/&
List的伪属性:
size、isEmpty、iterator
Set的伪属性:
size、isEmpty、iterator
Map的伪属性:
size、isEmpty、keys、values
Iterator的伪属性:
next、hasNextEnumeration伪属性:
next、hasNext、nextElement、hasMoreElements
获取集合中元素的实质就是调用它的toString()方法
它还可以直接获取集合中的元素,事实上是在调用集合的toString()方法
所以我们可以根据实际情况通过重写集合的toString()方法来实现个性化输出
甚至它还可以像访问数组那样,直接testList[2]
获取集合中的元素
但这种方法只适用于List,不适用于Map。因为Map的索引是key,不是数值
另外,由于HashSet中的元素是没有顺序的,所以也不能用下标获取单个元素
Lambda表达式
补充一下:使用Lambda表达式可以在OGNL中书写递归式子,在帮助中对它有很详细的说明
打开帮助中的//struts-2.0.14-all//struts-2.0.14//docs//index.html
在左侧的Documentation
下面点击Guides
链接,然后在这个页面中点击OGNL
最后跳转到//struts-2.0.14-all//struts-2.0.14//docs//docs//ognl.html
将这个页面右侧的下拉条拖放到最下面,就会看到它的说明了,它举的例子如下所示&s:property value="#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)" /&
Lambda表达式的语法是:[...]
,中括号前面有一个冒号,所有东西都在中括号里面写
也就是说我们只要看到一个冒号跟着一个中括号,就表示这里使用的是Lambda表达式#this
指的是表达式的参数
所以这个例子可以这样理解:先判断这个参数是否等于零,如果等于零,那么它的值最后就是零
如果参数不等于零,就再判断它是否等于壹。如果参数等于壹,那么它的值最后就是壹
如果参数不等于壹,就继续调用#fib
。注意这里已经用中括号将整体的值赋给了fib
实际上很少能够用得到Lambda表达式
利用投影获取属性
利用投影获取List中对象的username属性时,其中{}
表示的是一个集合stus.{username}
就表示将suts中所有的username属性取出组成一个新的列表
利用选择获取属性
OGNL表达式是很灵活的,可以同时使用选择技术
与投影技术
使用选择技术时,#this
代表当前元素,问号?
是把所有满足条件的元素都取出来上箭头^
是开始的意思,所以stus.{^#this.grade&=60}.{username}
输出的是[张三]
注意,此时输出文本中包含中括号,这表示它是一个列表
而stus.{?#this.grade&=60}.{username}[0]
输出的是张三
,是字符串,二者是不同的美元符号$
是结束的意思,所以stus.{$#this.grade&=60}.{username}
输出的是[王五]
这三个符合:问号、上箭头、美元符所返回的都是List
当OGNL取不到值的时候,它不会报错,而是什么都不显示2..
&s:property value="[0]"/&
返回的是ValueStack中从上至下的所有的Object
&s:property value="[1]"/&
返回的是ValueStack中从上至下的第二个Object3..
&s:property value="[0].username"/&
返回的是成员变量username的值
假设ValueStack中存在两个Action的话,如果第一个Action如果没有username变量
那么它会继续找第二个Action。那么在什么情况下ValueStack中会存在两个Action呢
答案是在struts.xml中配置的是从一个Action通过&result type="chain"&
跳转到另一个Action4..
&constant name="struts.ognl.allowStaticMethodAccess" value="true"/&
在Struts2.1.6
中必须设置struts.ognl.allowStaticMethodAccess为true
才允许使用OGNL访问静态方法。而在Struts2.0.11则无需设置
,即可直接访问
下面是OGNL测试的工程代码,这是一个Struts2.0.11应用
首先是web.xml文件
"http://java.sun.com/xml/ns/javaee"
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
org.apache.struts2.dispatcher.FilterDispatcher
然后是用于输入用户名和密码等信息的测试页面login.jsp
pageEncoding
这是测试OGNL使用的登录页面
程序设定的用户名和密码各为
用户名和密码不正确时将停留在页面不动
"&%=request.getContextPath()%&/login.action"
%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%
%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%
"user.username"
"user.password"
"user.address.addr"
"测试OGNL的输出"
然后是用于显示OGNL处理结果的loginSuc.jsp页面
pageEncoding
"/struts-tags"
这是使用OGNL输出的结果页面
获取姓名属性:
"user.username"
%-- 另外还有两种写法也是可以正常输出值栈中对象的普通属性的 --%
"user['username']"
%-- 但是如果写成下面这种形式的话,就什么都不会输出了 --%
"user[username]"
获取地址属性:
"user.address.addr"
调用值栈中的对象的普通方法:
"user.getVOMethod()"
调用值栈中Action的普通方法:
"getCommon()"
获取普通类的静态属性:
"@com.jadyer.vo.Address@TIPS"
访问普通类的构造方法:
"new com.jadyer.vo.Student('张小三',22).username"
调用Action中的静态方法:
"@com.jadyer.action.LoginAction@getStatic()"
调用JDK中的类的静态方法:
"@java.util.Calendar@getInstance().time"
调用JDK中的类的静态方法:
"@java.lang.Math@floor(46.58)"
调用JDK中的类的静态方法:
"@@floor(46.58)"
获取List中的所有元素:
"testList"
获取Set中的所有元素:
获取Map中的所有元素:
获取Map中的某个元素:
"testMap['m22']"
%-- 另外还有两种写法也是可以正常获取Map中的某个具体元素的 --%
"testMap.m22"
="testMap[/"
获取Set中的某个元素:
%-- 由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到 --%
"testSet[2]"
获取List中的某个元素:
"testList[2]"
获取List的大小:
"testList.size"
获取Set的大小:
"testSet.size"
获取Map的大小:
"testMap.size"
获取Map中所有的键:
"testMap.keys"
获取Map中所有的值:
"testMap.values"
Lambda计算4的阶乘:
"#f= :[#this==1?1 : #this*#f(#this-1)],#f(4)"
获取List中的所有对象:
利用投影获取List中对象的名字:
"stus.{username}"
利用投影获取List中第二个对象的名字:
"stus[1].{username}"
获取到的值为:[李四] --%
%-- 二者的区别在于:后者比前者多了一个中括号 --%
"stus.{username}[1]"
"stus[1].{username}"
利用选择获取List中成绩及格的所有对象:
"stus.{?#this.grade&=60}"
利用选择获取List中成绩及格的第一个对象:
"stus.{^#this.grade&=60}"
利用选择获取List中成绩及格的最后一个对象:
"stus.{$#this.grade&=60}"
利用选择获取List中成绩及格的所有对象的名字:
"stus.{?#this.grade&=60}.{username}"
利用选择获取List中成绩及格的第二个对象的名字:
"stus.{?#this.grade&=60}.{username}[1]"
利用选择获取List中成绩及格的第一个对象的名字:
"stus.{^#this.grade&=60}.{username}"
利用选择获取List中成绩及格的最后一个对象的名字:
"stus.{$#this.grade&=60}.{username}"
利用选择获取List中成绩及格的第一个对象然后求大小:
"stus.{^#this.grade&=60}.{username}.size"
利用OGNL中的#号获取attr中的属性:
"#attr.BB"
利用OGNL中的#号获取request范围中的属性:
"#request.req"
利用OGNL中的#号获取session范围中的属性:
"#session.ses"
利用OGNL中的#号获取Paraments对象的属性:
"#parameters.netname"
使用<%=request.getParameter("")%>或者${param.name}获取链接参数值:
${param.netname}
%=request.getParameter("netname")%
查看值栈中的信息:
然后是struts.xml文件
&!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd"
"struts-default"
"com.jadyer.action.LoginAction"
/login.jsp
/loginSuc.jsp?
"redirect"
/loginSuc.jsp?
"redirect"
/loginSuc.jsp?
=${user.username}
接着是用到的三个VO类
com.jadyer.
String getVOMethod(){
"这是User类中的一个普通方法"
com.jadyer.
String TIPS =
"玄玉加油!!"
com.jadyer.
Student(){};
Student(String username,
.username =
String toString() {
"{学生姓名:"
+ username +
",成绩:"
最后是用来提供OGNL测试的数据的LoginAction.java
com.jadyer.
java.util.ArrayL
java.util.HashM
java.util.HashS
java.util.L
java.util.M
java.util.S
org.apache.struts2.interceptor.RequestA
org.apache.struts2.interceptor.SessionA
com.jadyer.vo.S
com.jadyer.vo.U
com.opensymphony.xwork2.ActionS
@SuppressWarnings
"unchecked"
LoginAction
ActionSupport
implements
RequestAware,SessionAware {
List testList =
ArrayList();
Set testSet =
HashSet();
Map testMap =
HashMap();
List stus =
ArrayList();
setRequest(Map request) {
.request =
setSession(Map session) {
.session =
String getStatic(){
"这是LoginAction中的一个静态方法"
String getCommon(){
"这是LoginAction中的一个普通方法"
String execute()
Exception {
(user.getUsername().trim().equalsIgnoreCase(
) && user.getPassword().equals(
testList.add("list11"
testList.add("list22"
testList.add("list33"
testList.add("list44"
testList.add("list55"
testSet.add("set11"
testSet.add("set22"
testSet.add("set33"
testSet.add("set22"
testSet.add("set11"
testMap.put("m11"
testMap.put("m22"
testMap.put("m33"
testMap.put("m44"
testMap.put("m55"
stus.add(new
stus.add(new
stus.add(new
stus.add(new
request.put("req"
"这是通过OGNL中的#号获取的request属性范围的值"
session.put("ses"
"这是通过OGNL中的#号获取的session属性范围的值"
request.put("BB"
"这是通过OGNL中的#号获取的request属性范围的BB"
session.put("BB"
"这是通过OGNL中的#号获取的session属性范围的BB"
浏览: 45621 次
来自: 杭州
所有的 FusionCharts 图表(除了变焦线图表)都支持 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 parameters 用法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信