您的位置:首页 > 编程语言 > Java开发

Struts2-6 OGNL表达式

2017-01-04 21:45 260 查看
  在HelloWorld实例中,通过
${productName}
表达式直接获取productName值;而在打印request域对象(
<%=request %>
)时,发现其并非原生的
javax.servlet.http.HttpServletRequest
,而是经Struts2封装后的
org.apache.struts2.dispatcher.StrutsRequestWrapper
对象;由此可见,productName属性值并不在request等域对象中,而是从值栈(ValueStack)中获取的……

一、ValueStack

 可以从ActionContext中获取ValueStack对象,其内部分为两个逻辑部分

Map栈:实际是OgnlContext类型,是对ActionContext的一个引用,保存着各种各样的Map对象;

对象栈:实际是CompoundRoot类型,是采用ArrayList定义的数据结构意义上的栈,保存着各种与Action相关的对象。





那么该如何从值栈中获取对象属性呢?

二、OGNL表达式

  Struts2利用s:property标签和OGNL(Object-Graph Navigation Language,对象-图导航语言) 表达式来读取值栈中的属性值。

  property标签的属性如下:



1. 读取ObjectStack中对象的属性

 1). 访问其中对象的属性:
object.productName、object['productName']、object.["productName"]
;

 2). 引用对象栈中的对象:

可以采用从零开始的下标来引用对象栈中的对象,即栈顶对象用[0]来引用,其下面的那个对象用[1]来引用,如
[0].message


的含义是从第n个对象开始搜索,而不是只搜索第n个对象;

若从栈顶对象开始搜索,则可以省略下标部分;

结合s:property标签:
<s:property value="[0].message">
<s:property value="message">


注意:默认情况下,Struts2自动将Action对象放到值栈的栈顶。

……
<!-- 在JSP页面可以导入Struts2提供的标签 -->
<%@ taglib prefix="s" uri="/struts-tags" %>

<body>
<!-- JSP页面:利用Struts2的调试功能,显示值栈的内容 -->
<s:debug></s:debug>
<!-- JSP页面:利用Struts2的property标签,输出其中某对象的属性值 -->
<s:property value="[0].productName"/>
<s:property value="productDesc"/>
</body>


/**
* 创建对象,将其压入到值栈的对象栈中
*/
// 1. 获取ValueStack
ValueStack stack = ActionContext.getContext().getValueStack();
// 2. 创建TestProduct对象,并为其属性赋值
TestProduct object = new TestProduct();
object.setProductName = "spring";
object.setProductDesc = "java";
// 3. 将TestProduct对象压入值栈
stack.push(object);


2. 读取ContextMap中对象的属性

 1). 访问其中对象的属性:
#object.proName、#object['proName']、#object.["proName"]


 

 2). 示例:

返回session中的code属性:
#session.code


返回request中的customer属性的name属性:
#request.customer.name


返回域对象(按request、session、application的顺序)的lastAccessData属性:
#attr.lastAccessDate


3. 使用OGNL调用字段和方法

 1). 调用任何公共Java类的公共静态字段或静态方法:

调用字段:
@fullyQualifiedClassName@fieldName
,如
@java.util.Calendar@DECEMBER


调用方法:
@fullyQualifiedClassName@methodName(argumentList)
,如
@app4.Util@now()


注意:默认情况下,Struts2不允许调用任意Java类的静态方法,需要在struts.xml文件中进行如下配置:

<!-- 打开静态方法调用的限制 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>


 2). 调用ObjectStack中某对象的属性或方法:

调用字段:
object.fieldName
,如
[0].datePattern


调用方法:
object.methodName(argumentList)
,如
[0].repeat(3, "Hello")


示例代码如下:

<!-- 1). 使用OGNL调用任何public类的public类型的静态字段或静态方法 -->
<s:property value="@java.lang.Math@PI"/>        <br><br>
<s:property value="@java.lang.Math@cos(0)"/>    <br><br>

<!-- 2). 使用OGNL调用ObjectStack中某个对象的属性或方法 -->
<s:property value="setProductName('java')"/>    <br><br>
ProductName:<s:property value="productName"/>   <br><br>


4. 使用OGNL访问数组类型的属性

 有些属性将返回对象数组而不是单个对象,可以采用如下方式读取对象数组的元素数和各个属性:

<!-- 调用数组对象的属性 -->
<%
String[] names = new String[]{"qiaobc", "qiaob", "qiaoc"};
request.setAttribute("names", names);
%>
length: <s:property value="#attr.names.length"/>    <br><br>
names[1]: <s:property value="#attr.names[1]"/>      <br><br>


5. 使用OGNL访问List类型的属性

采用下标的方式直接访问List中的指定元素,如
nameList[0]


调用其size关键字或size()方法获取List的长度,如
nameList.size
nameList.size()


调用其isEmpty关键字或isEmpty()方法判断List是否为空;

可以采用OGNL表达式创建List,与生命Java数组相同,如
{"Red", "Green", "Black"}


6. 使用OGNL访问Map类型的属性

<!-- 使用OGNL访问Map类型的属性 -->
<%
Map<String, String> letters = new HashMap<String, String>();
request.setAttribute("letters", letters);
letters.put("qiaobc", "qiaob");
letters.put("qiaob", "qiaobc");
%>

<!-- 1). 读取Map类型的属性:返回结果为“{qiaob=qiaobc, qiaobc=qiaob}” -->
qiaobc: <s:property value="#attr.letters"/>             <br><br>
<!-- 2). 读取Map中某个key的值:mapObject[keyString] -->
qiaobc: <s:property value="#attr.letters['qiaobc']"/>   <br><br>

<!-- 3). 读取Map对象的长度 -->
size: <s:property value="#attr.letters.size()"/>        <br><br>
<!-- 4). 判断Map对象是否为空 -->
isEmpty: <s:property value="#attr.letters.isEmpty"/>    <br><br>

<!-- 5). 创建Map:#{key1:value1, key2:value2, key3:value3} -->


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

 原理:Struts2将HttpServletRequest对象包装为org.apache.struts2.dispatcher.StrutsRequestWrapper对象传到页面上,而该类重写了getAttribute(String attrName)方法;

 示例:
<s:property value="fieldName">
等价于EL表达式的
${fieldName}


 注意:EL表达式可以实现的,OGNL均能实现,但反之不然。

三、声明式异常

1. exception-mapping元素

 用于在struts.xml文件中配置当前action请求的声明式异常处理,其包含两个属性:

exception属性:指定需要捕获的异常类型,即异常的全类名;

result属性:指定响应结果,即当捕获该异常时执行当前响应结果;其结果可以来自当前action的result声明,也可来自global-results声明。

<action name="product-save" class="com.qiaobc.struts2.domain.Product" method="save">
<!-- exception-mapping配置算术异常:当save方法中发生算术异常时触发 -->
<exception-mapping result="input" exception="java.lang.ArithmeticException"></exception-mapping>
<result name="input">/WEB-INF/pages/input.jsp</result>
<result name="details">/WEB-INF/pages/details.jsp</result>
</action>


2. 声明式异常处理机制

 声明式异常由ExceptionMappingInterceptor拦截器负责处理,当捕获异常时拦截器向ValueStack的对象栈栈顶添加com.opensymphony.xwork2.interceptor.ExceptionHolder对象,其包含两个属性:

exceptionStack属性:包含被捕获异常的栈,其实是以getter()方法的形式存在的;

exception属性:表示被捕获异常的Exception对象。

<!-- 在异常处理页面上通过Struts2提供的debug标签来查看对象栈栈顶的异常信息 -->
<s:debug></s:debug> <br><br>

<!-- 显示对象栈栈顶ExceptionHolder对象的exceptionStack和exception属性信息 -->
<s:property value="exceptionStack"/>                                <br><br>
<s:property value="exception"/> --> ${exception }                  <br><br>
<s:property value="exception.message"/> --> ${exception.message }  <br><br>


  源代码分析:

/**
* 默认情况下的异常拦截器,在struts-default.xml文件中默认配置
*/
public class ExceptionMappingInterceptor extends AbstractInterceptor {

// ……

/**
* 重写父类的拦截方法
*/
@Override
public String intercept(ActionInvocation invocation) throws Exception {
String result;

try {
result = invocation.invoke();  // 按顺序执行其他拦截器并执行Action方法
} catch (Exception e) {
if (isLogEnabled()) {
handleLogging(e);
}
List<ExceptionMappingConfig> exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings();
// 发生异常时,获取exception-mapping元素的配置信息
ExceptionMappingConfig mappingConfig = this.findMappingFromExceptions(exceptionMappings, e);
if (mappingConfig != null && mappingConfig.getResult()!=null) {
Map parameterMap = mappingConfig.getParams();
// create a mutable HashMap since some interceptors will remove parameters, and parameterMap is immutable
invocation.getInvocationContext().setParameters(new HashMap<String, Object>(parameterMap));
result = mappingConfig.getResult();
// 发布异常(创建了封装有异常信息的ExceptionHolder对象)
publishException(invocation, new ExceptionHolder(e));
} else {
throw e;
}
}

return result;
}

// ……

/**
* 发布异常
*/
protected void publishException(ActionInvocation invocation, ExceptionHolder exceptionHolder) {
// 将封装有异常信息的ExceptionHolder对象压入值栈,故可从值栈中获取异常信息
invocation.getStack().push(exceptionHolder);
}

// ……
}


3. global-exception-mappings元素

  采用global-exception-mappings元素可为应用程序添加全局性的异常捕获映射,但其声明的异常映射只能应用在global-results元素下声明的某个result元素。

<!-- 注意两者的相对位置 -->
<global-results>
<result name="input">/WEB-INF/pages/input.jsp</result>
</global-results>

<global-exception-mappings>
<exception-mapping result="input" exception="java.lang.ArithmeticException"></exception-mapping>
</global-exception-mappings>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: