OGNL
在 JSP 页面上可以可以利用 OGNL(Object-Graph Navigation Language: 对象-图导航语言) 访问到值栈(ValueStack) 里的对象属性.
若希望访问值栈中 ContextMap 中的数据, 需要给 OGNL 表达式加上一个前缀字符 #. 如果没有前缀字符 #, 搜索将在 ObjectStack 里进行.
property 标签
Struts 的 property 标签用来输出值栈中的一个属性值.
读取 ObjectStack 里的对象的属性
若想访问 Object Stack 里的某个对象的属性. 可以使用以下几种形式之一: ObjectStack 里的对象可以通过一个从零开始的下标来引用.
ObjectStack 里的栈顶对象可以用 [0] 来引用, 它下面的那个对象可以用 [1] 引用.
若希望返回栈顶对象的 message 属性值: [0].message 或 [0][“message”] 或 [0][‘message’]
若在指定的对象里没有找到指定的属性, 则到指定对象的下一个对象里继续搜索.
即 [n] 的含义是从第 n 个开始搜索, 而不是只搜索第 n 个对象 若从栈顶对象开始搜索, 则可以省略下标部分
读取 Context Map 里的对象的属性
若想访问 ContextMap 里的某个对象的属性, 可以使用以下几种形式之一:
示例: 返回 session 中的 code 属性: #session.code
返回 request 中的 customer 属性的 name 属性值: #request.customer.name
返回域对象(按 request, session, application 的顺序)的 lastAccessDate 属性: #attr.lastAccessDate
调用字段和方法
可以利用 OGNL 调用 任何一个 Java 类里的静态字段或方法. 被压入到 ValueStack 栈的对象上的公共字段和方法.
默认情况下, Struts2 不允许调用任意 Java 类静态方法, 需要重新设置 struts.ognl.allowStaticMethodAccess 标记变量的值为 true.
调用静态字段或方法需要使用如下所示的语法: @fullyQualifiedClassName@fieldName: @java.util.Calendar@DECEMBER @fullyQualifiedClassName@methodName(argumentList): @app4.Util@now()
调用一个实例字段或方法的语法, 其中 object 是 Object Stack 栈里的某个对象的引用:
.object.fieldName: [0].datePattern .object.methodName(argumentList): [0].repeat(3, “Hello”);
访问数组类型的属性
有些属性将返回一个对象数组而不是单个对象, 可以像读取任何其他对象属性那样读取它们.
这种数组型属性的各个元素以逗号分隔, 并且不带方括号
可以使用下标访问数组中指定的元素: colors[0] 可以通过调用其 length 字段查出给定数组中有多少个元素: colors.length
访问 List 类型的属性
有些属性将返回的类型是 java.util.List, 可以像读取任何其他属性那样读取它们.
这种 List 的各个元素是字符串, 以逗号分隔, 并且带方括号
可以使用下标访问 List 中指定的元素: colors[0] 可以通过调用其 size 方法或专用关键字 size 的方法查出给定List 的长度: colors.size 或 colors.size()
可以通过使用 isEmpty() 方法或专用关键字 isEmpty 来得知给定的 List 是不是空. colors.isEmpty 或 colors.isEmpty() 还可以使用 OGNL 表达式来创建 List, 创建一个 List 与声明一个 Java 数组是相同的: {“Red”, “Black”, “Green”}
访问 Map 类型的属性
读取一个 Map 类型的属性将以如下所示的格式返回它所有的键值对:
若希望检索出某个 Map 的值, 需要使用如下格式: map[key] 可以使用 size 或 size() 得出某个给定的 Map 的键值对的个数
可以使用 isEmpty 或 isEmpty() 检查某给定 Map 是不是空. 可以使用如下语法来创建一个 Map:
使用 EL 访问值栈中对象的属性
<s:property value=“fieldName”> 也可以通过 JSP EL 来达到目的:
${fieldName} 原理: Struts2 将包装 HttpServletRequest 对象后的 org.apache.struts2.dispatcher.StrutsRequestWrapper 对象传到页面上, 而这个类重写了 getAttribute() 方法.
异常处理: exception-mapping 元素
exception-mapping 元素: 配置当前 action 的声明式异常处理 exception-mapping 元素中有 2 个属性 exception: 指定需要捕获的的异常类型。
异常的全类名 result: 指定一个响应结果, 该结果将在捕获到指定异常时被执行, 既可以来自当前 action 的声明, 也可以来自 global-results 声明. 可以通过 global-exception-mappings 元素为应用程序提供一个全局性的异常捕获映射.
但在 global-exception-mappings 元素下声明的任何 exception-mapping 元素只能引用在 global-results 元素下声明的某个 result 元素 声明式异常处理机制由 ExceptionMappingInterceptor 拦截器负责处理, 当某个 exception-mapping 元素声明的异常被捕获到时, ExceptionMappingInterceptor 拦截器就会向 ValueStack 中添加两个对象: exception: 表示被捕获异常的 Exception 对象 exceptionStack: 包含着被捕获异常的栈 可以在视图上通过 <s:property> 标签显示异常消息
实例
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="product-input.action">product-input</a>
</body>
</html>
input.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <s:debug></s:debug> <!-- <s:property value="exceptionStack"/> <br> --> <s:property value="exception"/>- ${exception } <s:property value="exception.message"/>- ${exception.message } <br><br><br> <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" name="Submit"/> <br><br> </form> </body> </html>
details.jsp
<%@page import="java.util.HashMap"%> <%@page import="java.util.Map"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <s:debug></s:debug> ProductName:${productName} <br> <br> ProductName1: <s:property value="[1].productName" /> <br> <br> ProductName2:${sessionScope.product.productName} <s:property value="#session.product.productName" /> <br> <br> <br> <br> ProductDesc:${productDesc} <br> <br> ProductPrice:${productPrice} <br> <br> ProductPrice*: <s:property value="[0].productPrice" /> <br> <br> productPrice**: <s:property value="productPrice" /> <br> <br> <!-- 使用OGNL调用public类的public类型的静态字段和静态方法 --> <s:property value="@java.lang.Math@PI" /> <br> <br> <s:property value="@java.lang.Math@cos(0)" /> <!-- 调用对象栈的方法为一个属性赋值 --> <br> <br> <s:property value="setProductName('yuyiiiii')" /> <br> <br> <s:property value="productName" /> <!-- 调用数组对象的属性 --> <% int[] number=new int[]{1,2,3,4,5}; request.setAttribute("number", number); %> <br> <br> length:<s:property value="#attr.number.length" /> <br> <br> number[2]:<s:property value="#attr.number[2]"/> <br><br> <% Map<String,String> letter=new HashMap<String,String>(); request.setAttribute("letter", letter); letter.put("AA", "a"); letter.put("BB", "b"); letter.put("CC", "c"); %> <!-- 使用OGNL访问Map --> Size:<s:property value="#attr.letter.size"/> <br><br> AA:<s:property value="#attr.letter['AA']"/> </body> </html>
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- 打开静态方法调用的限制 --> <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant> <!-- 配置Struts可以受理的请求的扩展名 --> <constant name="struts.action.extension" value="action,do"></constant> <package name="default" extends="struts-default"> <action name="product-input"> <result>/input.jsp</result> </action> <action name="product-save" class="com.yuyi.struts.valueStack.Product" method="save"> <exception-mapping result="input" exception="java.lang.ArithmeticException"></exception-mapping> <result name="input">/input.jsp</result> <result name="details">/details.jsp</result> </action> </package> </struts>
Product.java
package com.yuyi.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 RequestAware,SessionAware{ 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 [productId=" + productId + ", productName=" + productName + ", productDesc=" + productDesc + ", productPrice=" + productPrice + "]"; } public String save() { System.out.println("save:"+this); //1.获取值栈 ValueStack valueStack=ActionContext.getContext().getValueStack(); //2.创建Test对象,并为其属性赋值 Test object=new Test(); object.setProductName("AABBCC"); object.setProductDesc("AABBCCDD"); //3.把Test对象压入值栈的栈顶 valueStack.push(object); session.put("product", this); request.put("test", object); int i=10/0; return "details"; } private Map<String, Object> session; @Override public void setSession(Map<String, Object> arg0) { this.session=arg0; } private Map<String, Object> request; @Override public void setRequest(Map<String, Object> arg0) { this.request=arg0; } }
Test.java
package com.yuyi.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; } }