valueStack(值栈)
贯穿整个Action生命周期(每个Action实例都拥有一个valueStack对象),相当于一个数据的中转站,在其中保存当前Action对象和其他对象
ValueStack可以分为两个逻辑部分
Map栈:实际上是OgnlContext类型,是个Map,也是对ActionContext的引用,里面存放着各种Map:requestMap,sessionMap,applicationMap,parametersMap,attr
- parameters: 该 Map 中包含当前请求的请求参数
- request: 该 Map 中包含当前 request 对象中的所有属性
- session: 该 Map 中包含当前 session 对象中的所有属性
- application:该 Map 中包含当前 application 对象中的所有属性
- attr: 该 Map 按如下顺序来检索某个属性: request, session, application
对象栈:实际上是CompoundRoot类型,是一个使用ArrayList定义的栈,里面保存着各种和当前Action实例相关的对象,是一个数据结构上的栈(后进先出)
Struts2利用s:property 和OGNL表达式来读取值栈中的值
- 值栈中的属性值:
- 对于对象栈:对象栈中某个对象的属性值
- Map栈:request,session,application的一个属性值或一个请求参数的值
读取对象栈中对象的属性:
若想访问Object Stack里的某个对象的属性,可以使用以下几种形式:
Object.propertyName;
Object[‘propertyName’];
Object[“propertyName”]ObjectStack里的对象可以通过一个下标来指定,ObjectStack里的栈顶对象可以使用[0]来引用,它下面的对象可以使用[1]来引用;若在指定的对象里没有找到指定的属性,则到指定对象的下一个对象里去找,即[n]表示从第n个对象开始搜索属性值,而不是只搜素第n个对象,若从栈顶对象开始搜索,可以省略下标:message;结合s:property标签: 等同于:
默认情况下,Action对象会被Struts2自动的放入到值栈的栈顶
- 值栈中的属性值:
在jsp页面中可以利用OGNL访问到值栈里的对象属性,若希望访问值栈中的ContextMap中的数据,需要给OGNL表达式加上一个前缀字符#,可以通过这种形式访问ContextMap里的对象的属性,调用java类的静态公开属性或方法,访问数组的属性和元素,访问集合的属性和元素
以下为通过超链接创建一个 Product 类并且显示在 jsp 页面上的完整流程
<struts>
<!-- 配置struts2 可以受理请求的扩展名:以.action,.do,结尾或者什么都不写均可 -->
<constant name="struts.action.extension" value="action,do,"></constant>
<!-- 通配符的配置方法一:需要设置这个常量为true,然后再在action中单独设置 -->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<!-- 静态方法调用 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<package name="actionContext" extends="struts-default" >
<action name="product-add">
<result>/WEB-INF/pages/productAdd.jsp</result>
</action>
<action name="product-*" class="cn.zc_cris.Product" method="{1}">
<result name="{1}">/WEB-INF/pages/showDetails.jsp</result>
<allowed-methods>save</allowed-methods>
</action>
</package>
</struts>
public class Product implements SessionAware,RequestAware{
private Integer id;
private String name;
private String desc;
private BigDecimal price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", desc=" + desc + ", price=" + price + "]";
}
public String save() {
System.out.println("save: "+this);
//1. 获取值栈
ValueStack valueStack = ActionContext.getContext().getValueStack();
//2. 创建Test对象,为其属性赋值,和product的name属性和desc属性相同
Test test = new Test("cris", "你好");
//3. 将Test对象压入值栈栈顶
valueStack.push(test);
requestMap.put("product", this);
sessionMap.put("test", test);
return "save";
}
private Map<String, Object> requestMap;
private Map<String, Object> sessionMap;
@Override
public void setRequest(Map<String, Object> arg0) {
this.requestMap = arg0;
}
@Override
public void setSession(Map<String, Object> arg0) {
this.sessionMap = arg0;
}
}
public class Test {
private String name;
private String desc;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Test() {
super();
}
public Test(String name, String desc) {
super();
this.name = name;
this.desc = desc;
}
}
<%@page import="java.util.HashMap"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:debug/>
productId:${id }
<br>
productName:${name }
<br>
productPrice:${price }
<br>
productPrice:<s:property value="[0].price"/>
<br>
productPrice:<s:property value="price"/>
<br>
Test.productDesc:${sessionScope.test.desc }
<s:property value="#session.test.desc"/>
<br>
Product.productDesc:${requestScope.product.desc }
<s:property value="#request.product.desc"/>
<!-- 使用OGNL调用public类的public类型的静态字段和静态方法 -->
<s:property value="@java.lang.Math@PI"/>
<br>
<s:property value="@java.lang.Math@cos(0)"/>
<!-- 使用OGNL调用对象栈的方法 -->
<s:property value="setName('james')"/>
<s:property value="name"/>
<!-- 使用OGNL来访问数组的属性和其中的元素 -->
<%
String[] names = {"aa","bb","cc","dd"};
request.setAttribute("names", names);
%>
<br><br>
names.length:<s:property value="#attr.names.length"/>
<br>
names[2]:<s:property value="#attr.names[2]"/>
<!-- 使用OGNL来访问Map -->
<%
Map<String, String> map = new HashMap<>();
map.put("AA", "a");
request.setAttribute("map", map);
%>
<br>
<s:property value="#attr.map.size"/>
<br>
AA:<s:property value="#attr.map['AA']"/>
</body>
</html>
异常处理:Exception-mapping元素
- Exception-mapping:配置当前的Action的声明式异常或者application的全局异常
- Exception-mapping元素中的两个属性:
- exception:指定需要捕获的异常类型,即异常的全类名
- result:指定一个响应结果
声明式异常处理机制由ExceptionMappingInterceptor拦截器负责处理,当某个Exception-mapping元素声明的异常被捕获后,ExceptionMappingInterceptor拦截器就会向ValueStack中添加两个对象
- exception:表示被捕获异常的Exception对象
- ExceptionStack:包含被捕获异常的栈
jsp页面可以通过标签来显示异常信息
<struts>
<!-- 配置struts2 可以受理请求的扩展名:以.action,.do,结尾或者什么都不写均可 -->
<constant name="struts.action.extension" value="action,do,"></constant>
<!-- 通配符的配置方法一:需要设置这个常量为true,然后再在action中单独设置 -->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<!-- 静态方法调用 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<package name="actionContext" extends="struts-default" >
<!-- 全局的异常设置
<global-results>
<result name="index">/index.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="index" exception="java.lang.ArithmeticException"></exception-mapping>
</global-exception-mappings>
-->
<action name="product-add">
<result>/WEB-INF/pages/productAdd.jsp</result>
</action>
<action name="product-*" class="cn.zc_cris.Product" method="{1}">
<!-- 针对每个Action设置的异常处理 -->
<exception-mapping result="index" exception="java.lang.ArithmeticException"></exception-mapping>
<result name="index">/index.jsp</result>
<result name="{1}">/WEB-INF/pages/showDetails.jsp</result>
<allowed-methods>save</allowed-methods>
</action>
</package>
</struts>
<s:property value="exception"/>
<br>
<s:property value="exception.message"/>
<br>