OGNL表达式

 

值栈:

  1. 在ValueStack对象的内部有两个逻辑部分

ObjectStack(对象栈):Struts把 Action和相关对象压入 ObjectStack中(对象栈 ,就是root)

ContextMap(Map栈):struts 把各种各样的映射关系(一些Map类型的对象)压入ContextMap中(内容有request,attr,parameters,session,application等)

实际上就是对ActionContext的一个引用

2.Struts会把下面这些映射压入ContextMap中

         Parameters:该Map种包含当前请求的请求参数。

         request:该Map种包含request对象中的所有属性

         session:该Map种包含当前session对象中的所有属性

         application:该Map种包含当前application中对象中的所有属性

         attr:该Map按如下顺序来检索某个属性:request,session,application

 

OGNL是如何在页面上读取值栈当中的内容

 

关于值栈:

1)  helloworld时,${productName} 读取productName值,实际上该属性并不在request等域对象中,而是从值栈中获取的。

2)  ValueStack

可以冲ActionContext中获取值栈对象

可以分为两个逻辑部分

1.  Map栈: 实际上是OGNLContext类型,是个Map,也是对ActionContext(因为对OGNLContext进行了封装)的一个引用,里面保存着各种Map(Map里面存放的还是Map):

requestMap , sessionMap , applicationMap , parametersMap , attr(attr持有对以上Map的引用)

  1. 对象栈:实际上是CompundRoot类型,是一个使用ArrayList定义的栈, 里面保存各种和当前Action 实例相关的对象,是一个数据结构意义的栈

 

 

Property标签

Struts2利用s:property标签 和OGNL表达式 来读取值栈中的属性值

  1. 值栈中的属性值:

1)对于对象栈:对象中某一个对象的属性值

         2)Map栈:request,session , application , 的一个属性值,或一个请求参数的值

2.  读取对象栈中对象的属性:

         1)想访问Object Stack 里的某个对象的属性,可以使用以下几种形式之一:

         Object.propetyName ;

         Object.[‘propertyName’]

         Object.[“propertyName”]

        

         2)ObjectStack 里的对象可以通过一个从零开始的下表来饮用,ObjectStack 里的栈顶对象可以用[0] 来饮用,它下面的那个对象可以用[1] 饮用。

         [0].message

         3)[n]的 含义是从第 n 个开始搜索 , 而不是只搜索第 n 个对象

         4)若从栈顶开始搜索,则可以省略下表部分:message

         5)结合 s:property 标签 : <s:property value=”[0].message” />

<s:property  value=” message” />

 

  1. 默认情况下 ,Action 对象会被Struts2自动的放到ObjectStack对象栈的栈顶

但是下面这种方法栈顶不会是当前Action对象

 

package com.atguigu.struts.valuestack;

 

import com.opensymphony.xwork2.ActionContext;

import com.opensymphony.xwork2.util.ValueStack;

 

public class Product {

         private Integer productId;

         private String productName;

         private String productDesc;

         private double productPrice;

         public Integer getProductId() {

                   return productId;

         }

         public void setProductId(Integer productId) {

                   this.productId = productId;

         }

         public String getProductName() {

                   return productName;

         }

         public void setProductName(String productName) {

                   this.productName = productName;

         }

         public String getProductDesc() {

                   return productDesc;

         }

         public void setProductDesc(String productDesc) {

                   this.productDesc = productDesc;

         }

         public double getProductPrice() {

                   return productPrice;

         }

         public void setProductPrice(double productPrice) {

                   this.productPrice = productPrice;

         }

         @Override

         public String toString() {

                   return "Product [productDesc=" + productDesc + ", productId="

                                     + productId + ", productName=" + productName

                                     + ", productPrice=" + productPrice + "]";

         }

         //当到达save方法的时候,在栈顶的已经是product这个对象

         public String save(){

                   System.out.println("save"+this);

                  

                   //1.获取值栈

                   ValueStack valueStack = ActionContext.getContext().getValueStack();

                   //2.创建一个Test对象,并为其属性赋值

                   Test test = new Test();

                   test.setProductDesc("AABBCCDD");

                   test.setProductName("AABBCC");

                   //3.把该Test对象压入值栈栈顶

                   valueStack.push(test);

                  

                   return "details";

         }

}

 

Details.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>

  <body>

    <%--

    //这是解决乱码解决不了 的 ,因为我们已经调用了request.getParameter方法

    //我们应该调用一个filter 该filter应该放在struts2那个filter之前

        request.setCharacterEncoding("UTF-8");

    --%>

    <s:debug></s:debug>

    ProductName:<s:property value="[0].productName"/>

    <!-- ↑这个事读取值栈中第一个对象的属性 -->

    <br/><br/>

    ProductDesc:<s:property value="[1].productDesc"/>

    <br/><br/>

    ProductPrice:${productPrice }

    <br/><br/>

    ProductPrice:<s:property value="[0].productPrice"/>

    <br/><br/>

    ProductPrice:<s:property value="productPrice"/>

  </body>

 

 

使用OGNL调用字段和方法

    利用任何一个java类里的静态字段或方法。

    被压入到ValueStack栈的对象上的公共字段和方法

默认情况下 Struts2不允许调用任意Java类静态方法,需要从新设置

struts.ognl.allowStaticMethodAccess 标记变量的值为true

调用 静态 字段或方法需要使用如下所示的语法:

    @fullyQualifiedClassName@fieldName;

    @java.util.Calender@December

    @fullyQualifiedClassName@methodName(argumentList);

    @java.util.Math@cos(0);

调用一个实例字段或方法的语法,其中 object 是Object Stack 栈里的某个对象的引用:

    -object.fieldName:[0].datePattern

    -object.methodName(argumentList): [0].repeat(3,”hello”);

如果访问省略了[n]则代表调用从栈顶的对象开始

 

访问数组类型的属性

有些属性将返回一个对象数组而不是单个对象,可以像读取任何其他对象属性那样读取它们,

这种数组属性的各个元素以逗号分隔,并且不带方括号

 

可以使用下表访问数组中制定的元素:colors[0]

 

可以调用起length字段查出给定数组中有多少个元素

colors.length

    <!-- 调用数组对象的属性 -->

    <%

       String[] names = new String[]{"aa","bb","cc","dd"};

       request.setAttribute("names",names);

    %>

    length: <s:property value="#attr.names.length" />

    <br/><br/>

   

    names[2] : <s:property value="#attr.names[2]"/>

访问List类型的属性

    Colors.size 或 colors.size();

是否为空 colors.isEmpty 或者color.isEmpty();

访问方式跟数组相同

 

 

访问Map类型的属性

 

读取一个Map类型的属性将

<!-- 调用Map对象的属性 -->

    <%

       Map<String,String> letters = new HashMap<String,String>();

       request.setAttribute("letters",letters);

       letters.put("AA","a");

       letters.put("BB","b");

       letters.put("CC","c");

   

    %>

    <s:property value="#attr.letters.size" />

    <br/>

    <br/>

    AA:<s:property value="#attr.letters['AA']"/>

    <br/><br/>

 

 

使用EL访问值栈中对象的属性

<s:property value=”filename” >也可以通过JSP EL来达到目的的:${fieldName}

 

原理:Struts2将包装HttpServletRequest 对象后的 org.apache.struts2.dispatcher.StrutsRequestWrapper对象传到页面上,而这个类重写了getAttribute()方法

 

总体代码整理:

 

Test.java

package com.atguigu.struts.valuestack;

 

public class Test {

    private String productName;

    private String productDesc;

    public String getProductName() {

       return productName;

    }

    public void setProductName(String productName) {

       this.productName = productName;

    }

    public String getProductDesc() {

       return productDesc;

    }

    public void setProductDesc(String productDesc) {

       this.productDesc = productDesc;

    }

   

}

 

Product.java

 

package com.atguigu.struts.valuestack;

 

import java.util.Map;

 

import org.apache.struts2.interceptor.RequestAware;

import org.apache.struts2.interceptor.SessionAware;

 

import com.opensymphony.xwork2.ActionContext;

import com.opensymphony.xwork2.util.ValueStack;

 

public class Product implements SessionAware ,RequestAware{

    private Integer productId;

    private String productName;

    private String productDesc;

    private double productPrice;

    public Integer getProductId() {

       return productId;

    }

    public void setProductId(Integer productId) {

       this.productId = productId;

    }

    public String getProductName() {

       return productName;

    }

    public void setProductName(String productName) {

       this.productName = productName;

    }

    public String getProductDesc() {

       return productDesc;

    }

    public void setProductDesc(String productDesc) {

        this.productDesc = productDesc;

    }

    public double getProductPrice() {

       return productPrice;

    }

    public void setProductPrice(double productPrice) {

       this.productPrice = productPrice;

    }

    @Override

    public String toString() {

       return "Product [productDesc=" + productDesc + ", productId="

              + productId + ", productName=" + productName

              + ", productPrice=" + productPrice + "]";

    }

    //当到达save方法的时候,在栈顶的已经是product这个对象

    public String save(){

       System.out.println("save"+this);

      

       //1.获取值栈

       ValueStack valueStack = ActionContext.getContext().getValueStack();

       //2.创建一个Test对象,并为其属性赋值

       Test test = new Test();

       test.setProductDesc("AABBCCDD");

       test.setProductName("AABBCC");

       //3.把该Test对象压入值栈栈顶

       valueStack.push(test);

      

       sessionMap.put("product", this);

       requestMap.put("test", test);

      

       return "details";

    }

    private Map<String , Object> sessionMap;

   

    public void setSession(Map<String, Object> arg0) {

       this.sessionMap = arg0;

    }

    private Map<String , Object> requestMap;

    public void setRequest(Map<String, Object> arg0) {

       this.requestMap = arg0;

    }

}

 

Index.jsp

<body>

   <a href="product-input.action">Product Input</a>

  </body>

 

 

    Struts.xml

<struts>

    <!--  -->

    <package name="default" namespace="/" extends="struts-default">

       <action name="product-input" >

           <result>/input.jsp</result>

       </action>

       <action name="product-save" class="com.atguigu.struts.valuestack.Product" method="save">

           <result name="details">/details.jsp</result>

       </action>

    </package>

</struts>

 

 

Input.jsp

 

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

  </head>

  <body>

       <form action="product-save.action" method="post" >

           ProductName:<input type="text" name="productName"/>

           <br/><br/>

           ProductDesc:<input type="text" name="productDesc"/>

           <br/><br/>

           ProductPrice:<input type="text" name="productPrice"/>

           <br/><br/>

           <input type="submit" value="Submit"/>

       </form>

  </body>

</html>

 

Details.jsp

 

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

    <head>

  </head>

  <body>

    <%--

    //这是解决乱码解决不了 的 ,因为我们已经调用了request.getParameter方法

    //我们应该调用一个filter 该filter应该放在struts2那个filter之前

        request.setCharacterEncoding("UTF-8");

    --%>

    <s:debug></s:debug>

    ProductName:<s:property value="[0].productName"/>

    <!-- ↑这个事读取值栈中第一个对象的属性 -->

    <br/><br/>

    ProductDesc:<s:property value="[1].productDesc"/>

    <br/><br/>

   

    ProductPrice:${productPrice }

    <br/><br/>

    ProductPrice:<s:property value="[0].productPrice"/>

    <br/><br/>

    ProductPrice:<s:property value="productPrice"/>

    <br/><br/>

   

    ProductName1:${sessionScope.product.productName }<!-- 是通过EL表达式来表示的 -->

    ProductName1:<s:property value="#session.product.productName" />

    <br/><br/>

    PruductName2: <s:property value="#request.test.productName" />

    PruductName2:${requestScope.test.productName }

    <br/><br/>

   

   

    <!-- 调用数组对象的属性 -->

    <%

       String[] names = new String[]{"aa","bb","cc","dd"};

       request.setAttribute("names",names);

    %>

    length: <s:property value="#attr.names.length" />

    <!--

       这个不能通过EL表达式来进行访问 ,因为length 对应的没有响应的get方法

       还有集合对应的size属性也不能通过 EL表达式访问

     -->

    <br/><br/>

    names[2] : <s:property value="#attr.names[2]"/>

   

    <!-- 调用Map对象的属性 -->

    <%

       Map<String,String> letters = new HashMap<String,String>();

       request.setAttribute("letters",letters);

       letters.put("AA","a");

       letters.put("BB","b");

       letters.put("CC","c");

    %>

    <s:property value="#attr.letters.size" />

    <br/>

    <br/>

    AA:<s:property value="#attr.letters['AA']"/>

    <br/><br/>

  </body>

</html>