struts的OGNL(1)

来源:互联网 发布:阿里云地域可以更换吗 编辑:程序博客网 时间:2024/06/07 18:02

转载自:http://m.oschina.net/blog/163300

 

Struts2中的OGNL1 Struts2中OGNL操作的上下文和根对象上下文对象是ActionContext;根对象是ValueStack,它是一个栈结构,提供了压栈和弹栈等方法,通常栈顶元素是当前方法的Action对象;每个请求都有自己的ActionContext,每个ActionContext中都有自己的ValueStack;Struts2中的上下文对象就是ActionContext对象,而根对象是ValueStack对象。但Struts2中根对象ValueStack很特殊,它不是一个对象,而是一组对象(底层是ArrayList的栈结构)。你也可以理解为Struts2的根对象不是一个对象,而是一堆对象。可以通过ActionContext来获取ValueStack:ActionContext.getContext().getValueStack(),也可以从request中获取ValueStack:request.getAttribute(“struts.valueStack”)。ActionContext内部的数据:请求参数和域属性:parameters:Map类型,对应HttpServletRequest中的请求参数;request:Map类型,对应HttpServletRequest中的属性;session:Map类型,对应HttpSession中的属性;application:Map类型,对应ServletContext中的属性;attr:Map类型,对应request、session、application三个域,即全域查询的Map;域对象:com.opensymphony.xwork2.dispatcher.HttpServletRequest:HttpServletRequest对象com.opensymphony.xwork2.dispatcher.HttpServletResponse:HttpServletResposne对象com.opensymphony.xwork2.dispatcher.ServletContext:ServletContext对象;其他信息:com.opensymphony.xwork2.ActionContext.name:<action>的name属性值;action:当前Action对象;com.opensymphony.xwork2.util.ValueStack.ValueStack:ValueStack对象;com.opensymphony.xwork2.ActionContext.locale:当前的Locale。ValueStack内部的数据:Action对象;模型对象(ModelDriven)。  不同的请求对应不同的ValueStack,通过在请求一个Action时,都会把当前Action的引用放到ValueStack中。一般情况下,当前Action就在ValueStack的栈顶!2 Struts2标签使用OGNL表达式使用<s:property>标签可以执行OGNL表达式,例如:<s:property value=”name”/>;当OGNL访问的是根对象时(例如OGNL表达式name),Struts2会把ValueStack中每个元素当成根对象,从栈顶依次向下查找,直到找到某个元素有name属性。Struts2中有很多标签都支持OGNL表达式,我们也知道OGNL表达式访问的数据是在OgnlContext中。在Struts2中上下文对象就是ActionContext,其中根对象就是ValueStack。例如<s:property value=”name”/>这个标签的value属性值name就必须是一个OGNL表达式。我们知道,没有使用“#”为前缀的OGNL表达式表示是在获取根对象的name属性值,但在Struts2中根对象是ValueStack,它不是一个对象,而是一组对象,一个栈!Struts2的根对象特殊之处是,它会在ValueStack中从栈顶开始,直接到栈尾遍历每个栈中的对象,查看是否有name属性,如果找到栈中某个对象存在name属性,那么就不会再向下去找!也就是说,如果栈顶元素就有name属性,那么就算第二个元素也有name属性,那么输出的也是栈顶元素的name属性值。前面我们也说过了,当访问一个Action后,Struts2会把当前Action对象压入到值栈中,即栈顶位置上(当然我们也可以调用ValueStack的push()方法来向其压入对象)。然后在Action跳转的JSP页面中使用<s:property>标签来获取值栈中元素的属性值。public class OgnlDemo1Action extends ActionSupport {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String execute() throws Exception {return SUCCESS;}}<action name="demo1" class="cn.itcast.action.OgnlDemo1Action"><result>/index.jsp</result></action>http://localhost:8080/ognl/demo1.action?name=zhangSan<s:property value="name"/>当我们在浏览器中访问http://localhost:8080/ognl/demo1.action?name=zhangSan时,给Action的属性name赋值为zhangSan,然后Action跳转到index.jsp页面中,在index.jsp页面中我们使用<s:property>标签打印name属性值。因为“name”是一个OGNL表达式,它表示访问根对象的name属性,即调用根对象的getName()方法!但我们不要忘了,在Struts2中,这个动作表示在ValueStack中从上而下,依次查看每个元素是否有getName()方法,直到找到第一个有getName()方法的元素,然后返回它getName()方法的结果,才会结束。因为刚刚访问了Action,把当前Action对象会被压入到ValueStack中,它是在ValueStack的栈顶,所以其实就是在获取当前Action的getName()。我们知道,还可以通过OGNL表达式访问上下文中其他的对象,但这需要以“#”为前缀。例如可以访问parameters、request、session、application、attr这些Map对象。<s:property value="#parameters.password"/><br/><s:property value="#request.hello"/><br/>在ActionContext中存放着很多个Map:keyvaluerequestMap类型,对应request中的属性,但它不是request对象本身sessionMap类型,对应session中的属性applicationMap类型,对应application中的属性parametersMap类型,对应request中请求参数attrMap类型,对应所有域对象,依次查找。#request表示一个Map,而#request.hello表示获取#request这个Map中key为hello的值。当然,如果你只有request.setAttribute(“hello”, “xxx”)过,才能获取到值。3 [N]语法[N]语法用来获取子栈,例如[3]表示截取从下标3位置开始到栈底的一个子栈。例如[3].name表示从[3]子栈中查找每个元素是否存在name属性,如果下标3元素就存在name属性,那么直接返回即可。例如我们向ValueStack中压入两个对象:public class OgnlDemo1Action extends ActionSupport {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String execute() throws Exception {Emp emp = new Emp();emp.setName("emp_zhangSan");Student stu = new Student();stu.setName("stu_liSi");ValueStack vs = ActionContext.getContext().getValueStack();vs.push(emp);vs.push(stu);return SUCCESS;}}<s:property value="[0].name"/><br/><s:property value="[1].name"/><br/><s:property value="[2].name"/><br/>  千万注意,[1]不是表示下标1的元素,而是一个子栈。4 top关键字top语法用来获取栈顶元素本身。例如还是上面的例子,值栈中从上到下依次是Student、Emp、Action三个对象,那么top表示的就是Student对象本身。而[1].top表示获取[1]子栈的栈顶元素,即Emp对象。<s:property value="[0].top"/><br/><s:property value="[1].top"/><br/><s:property value="[2].top"/><br/>5 访问静态成员我们知道OGNL可以访问类的静态方法和属性,但在Struts2中默认是不允许OGNL访问静态成员的,如果想访问类的静态成员,需要设置一个常量:struts.ognl.allowStaticMethodAccess,该常量默认值为false,我们需要把它设置为true,这样就可以访问静态成员了。<constant name="struts.ognl.allowStaticMethodAccess" value="true"/><s:property value="@@min(10,20)"/><br/>除了使用标准的OGNL表达式访问静态属性和静态方法外,Struts2还允许你不指定完整的类名,而是通过“vs”前缀来调用保存在值栈中对象的静态属性和静态方法。例如:@vs@hello(),表示调用栈顶元素的静态方法hello(),如果栈顶元素是MyAction类型的对象,那么@vs@hello()就表示MyAction.hello()!还可以指定值栈中元素序号来调用静态成员,例如@vs1@hello()表示调用的是值栈中第一个元素的静态方法,其实它与@vs@hello()是相同的。因为不存在@vs0@,序号是从1开始的。@vs2@hello()表示调用值栈中第2个元素的静态方法hello()。6 模型驱动与ValueStack我们知道,Struts2会把当前Action对象压入到值栈中,所以我们在JSP页面中总是可以直接使用OGNL来访问Action元素的属性:<s:property value=”username”/>,如果我们没有自己向值栈中压入其他元素,那么Action就是栈顶元素了,所以上面的标签输出的就是当前Action的username属性值。当Action使用模型驱动时,ModelDrivenInterceptor拦截器会把当前model对象压入值栈,这时值栈中model对象就是栈顶元素,所以<s:property value=”username”/>访问的是model对象的username属性。7 EL表达式访问值栈让人感到奇怪的是,可以通过EL表达式访问到值栈。例如在JSP页面中使用${name},但在域对象中没有name这个域属性,奇怪的是它会去到值栈中找到元素的name属性值。这是因为Struts2对request对象进行了装饰,这个装饰类是StrutsRequestWrapper,它对getAttribute()方法进行了增强,它会先到域对象中查找名为name的属性值,但如果没有找到它会去到ValueStack中去找,所以EL才会有这个本事。8 Struts2 OGNL中的#、%、$在Struts2的标签中,有些标签可以直接使用OGNL表达式,但有些是不能直接使用的。例如我们使用过的<s:property>标签的value属性就是默认为OGNL表达式的。但<s:url>标签的action属性默认是字符串,而不是OGNL表达式。例如<s:url action=”demo1”/>会在页面中输出/day03/damo1.action。如果你想在<s:url>标签的action属性中使用OGNL,那么需要使用%{},这样Struts2就知道你给出的值是一个OGNL表达式了,例如:<s:url action=”%{#request.url}”/>,其中#request.url会被Struts2当做OGNL表达式来解析!当然,你也可以在<s:property>标签的value属性中使用%{},但对于默认就是OGNL表达式的属性而言,添加%{}是没有意义的:<s:property value=”%{name}”/>对于OGNL表达式中的“#”,表示的是访问上下文中的非root对象时需要使用以“#”开头。这个应该没什么问题吧。${}是在国际化资源文件中用来使用OGNL表达式用的,${}还可以在struts.xml文件用来使用OGNL表达式。例如在res.properties文件中:msg:我的名称叫${#request.name},然后在Action或JSP中就可以使用它了。    <s:i18n name="res"><s:text name="msg"></s:text></s:i18n>例如在struts.xml文件中使用:<result type=”stream”>  <param name=”contentType”>${type}</param></result>其中${type}表示OGNL表达式,即调用当前Action的getType()方法(因为Action在值栈的栈顶位置)。9 从Action中向页面传递数据1.一般性数据传递每个Action都有自己保存信息的地方,这是从ActionSupport类继承而来的!ActionSupport#addFieldError(“字段名”, “字段错误信息内容”):它会把信息添加到Map<String,List>中;ActionSupport#addActionError(“Action错误信息内容”):它会把信息添加到Collection<String>中;ActionSupport#addActionMessage(“Action通知信息内容”):它会把信息添加到Collection<String>中。因为Action会被压入到值栈中,所以在页面中Struts2的标签就可以来获取这些信息了。<s:fielderror fieldame=”字段名”/>:打印指定字段的所有错误信息;<s:actionerror/>:打印Action错误信息;<s:actioinmessage/>:打印Action通知信息。  2. 复杂数据传递也可以把复杂类型的数据通过压入值栈来向页面传递:valueStack.push(new User(“zhangSan”, “123”));在页面中可以使用Struts2标签来获取值栈的内容:<s:property value=”username”/><s:property value=”password”/>10 页面中查看ValueStack内部数据  Struts2为开发人员提供了一个标签:<s:debug/>,它会在页面中生成一个超链接,点击链接会在页面中显示ValueStack的内部数据。

****************************************************************************************************************************************************************************************