OGNL表达式
值栈:
- 在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的引用)
- 对象栈:实际上是CompundRoot类型,是一个使用ArrayList定义的栈, 里面保存各种和当前Action 实例相关的对象,是一个数据结构意义的栈
Property标签
Struts2利用s:property标签 和OGNL表达式 来读取值栈中的属性值
- 值栈中的属性值:
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” />
- 默认情况下 ,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>