struts2学习笔记之OGNL表达式

     OGNL全称是Object Graph Navigation Lanaguage, 即对象图形导航语言。工作在视图层,用来取代页面中的java脚本。简化数据访问操作。法,和jsp中内置的EL表达相比,它们都是表达式语言,但是OGNL的功能更强大,可以进行类型转换,访问方法,操作集合对象等。

OGNL主要做两件事情,

1. 表达式语言,数据在框架中的流入流出。OGNL提供了一个简单的语法 ,将表单或者Struts2标签与各ava各种类型的数据绑定起来。如<input  type="text"  name="user.name">的输入对应Action类中的User对象的name属性。在OGNL的帮助下,输入的时候。数据从请求参数转移到了Action的JavaBean属性上;输出时,数据又从属性转移到生成的页面中。

2. 类型转换器

   每一次数据流入或流出框架,页面中字符串类型的数据和Java数据类型之间都会发生转换。OGNL可以实现和各种Java数据类型间的转换,包括集合类型。

框架在处理每个请求时,都会创建该请求对应的运行环境,并将请求对应的Action对象放入其中。Action对象被放在一个叫作值栈的对象中,Action对象的属性被暴露出来。params拦截器会负责把来自HttpServletRequeat对象的数据传到值 栈上。

 

ValueStack值栈:

 值栈是框架创建的一个存储区域,用来保存Model对象。它具有栈的特征,可以存放多个对象,如果存放多个对象,它们是按照先后顺序压入值栈的。框架在处理每个请求时,都会创建该请求对应的运行环境,这时会创建值栈和请求对应的Action实例,并将Action实例压入值栈中。

       值栈是一个虚拟对象,它可以暴露它所包含的所有对象的属性,就好像这些属性是它自己的一样。为什么说值栈是一个虚拟对象呢?因为在解析OGNL表达式时,我们好像面对的是一个单一对象,但实际上并不是这样的,只是值栈把自己伪装成了一个单一对象。值栈包含存放的所有对象的所有属性,假如存放了多个对象,在查找OGNL表达式对应的属性时,会从栈顶开始依次往下查找,一直到栈底,先找到的对象的属性就作为"虚拟"对象的属性。换句话说,假如栈内存放了多个对象,且不同对象存在相同名字的属性时,那么靠近栈顶的对象的优先级更高,下面对象的该属性就被"隐藏"了。

struts2内置转换器:

 对于大部分常用类型,并不需要我们自己编码实现类型转换,struts2框架内部提供的类型转换器可以帮我们完成。这些类型转换器有很多种,用于实现将字符串类型和常用类型之间的转换。具体的转换器种类包括 :

   ① String : 将int,long,double,String类型的数组或者java.util.Date类型转换为字符串。

  ②  boolean/Boolean:  在字符串和布尔值之间进行转换。

  ③  char/Character: 在字符串和字符之间进行转换。

  ④  int/Integer,float,/Float, long/Long, double/Double: 在字符串和数值类型之间进行转换。

  ⑤   Date :  在字符串和日期类型之间进行转换。

  ⑥   数组集合: 在字符串数组和数组对象,集合对象之间进行转换。

  自定义转换器:

          创建自定义类型转换器使用StrutsTypeConvert抽象类,它定义了两个抽象方法,用于不同的转换方法,分别如下:

   public Object convertFormString(Map context,String[]values,Class toType) : 将一个或多个字符串值转换为指定的类型。context表示OGNL上下文的Map对象,参数values是要转换的字符串值,参数toType是要转换的目标类型。

 

public String converToString(Map context,Object object) : 将指定对象转化为字符串。context表示OGNL上下文的Map对象,参数Object是要转换的对象。

如果继承StrutsTypeConverter类编写自定义类型,需要重写上面的两个抽象方法。

自定义类型转换器后,还必须进行配置,将类型转换器和某个类或属性通过properties文件建立关联。Struts2提供了两种方式来配置转换器,一种是应用全局范围的类型转换器,一种是应用于特定类的类型转换器。

       ①    应用于全局范围的类型转换器

                        要指定应用于全局范围的类型转换器,需要在classpath的根路径下(通常是WEB-INF/classess目录,对应开发的src目录,) 创建一个名为xwork-conversion.properties的属性文件,其内容为  :转换类全名=类型转换器类全名

      ②     应用于特定类的类型转换器

                       要指定于特定类的类型转换器,需要在特定类的相同目录下创建一个名为ClassName-conversion.properties的属性文件(ClassName代表实际的类名),其内容为  : 特定类的属性名=类型转换器类全名

下面代码创建和配置一个日期类型转换器

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import org.apache.struts2.util.StrutsTypeConverter;

import com.opensymphony.xwork2.conversion.TypeConversionException;

public class DateConverter extends StrutsTypeConverter{
	//支持转换的多种日期格式,可增加时间格式
    private final DateFormat[]dfs={
    		 new SimpleDateFormat("yyyy年MM月dd日"),
    		 new SimpleDateFormat("yyyy-MM-dd"),
    		 new SimpleDateFormat("MM/dd/yy"),
    		 new SimpleDateFormat("yyyy.MM.dd"),
    		 new SimpleDateFormat("yyMMdd"),
    		 new SimpleDateFormat("yyyy/MM/dd")  };		
   
	
	/**
	 * 将指定格式字符串转换为日期类型
	 */
	@Override
	public Object convertFromString(Map context, String[] values, Class toType) {
		String dateStr=values[0];  //获取日期的字符串
		for (int i = 0; i < dfs.length; i++) {
			try {
				return dfs[i].parse(dateStr);
			} catch (Exception e) {
				continue;
			}
		}
		//如果遍历完毕后仍没有转换成功,表明出现转换异常
		throw new TypeConversionException();
	}

	/**
	 *  将日期转换为指定格式字符串
	 */
	@Override
	public String convertToString(Map context, Object object) {
		Date date=(Date)object;
		//输出的格式是yyyy-MM-dd
		return new SimpleDateFormat("yyyy-MM-dd").format(date);
	}

}

然后在src目录下创建文件xwork-conversion.properties,并添加如下代码 :

java.util.Date=包名.DateConverter

如果在页面输入了错误格式的内容,除了在页面中使用JavaScript进行判断外,也可以在服务器端判断。如果要在服务器端判断类型转换错误,需要满足如下前提条件。

     ①   启动StrutsConversionErrorInteceptor拦截器。这个拦截器已经包含在defaultStack拦截器栈中,参看struts-default.xml文件。如果在struts.xml中扩展了"struts-default"包,启动项目时会自动加载。

     ②    实现validationAware接口,ActionSupport实现了该口。

     ③    配置input结果映射。出现类型转换错误后将在所配置页面显示错误信息,如果没有配置将出现错误提示,提示没有指定               input页面。    

     ④    在页面使用Struts2表单标签或使用<s:fielderror>标签来输出转换错误。

在默认情况下,所有的类型转换错误都是通用的i18N消息键xwork.default.invalid.fieldvalue来报告错误信息的,默认文本是

"Invalid field value for fieldxxx",xx是字段名称 。希望提高友好性,可修改默认的错误信息文本。如下面代码所示:

<constant name="struts.custom.i18n.resource value="message" />

 

然后在src目录下创建资源文件message.properties,并添加文本,如下代码所示。

    xwork.default.invalid.fieldvalue=字段"{0}"的值无效

i18n消息键xwork.default.invalid.fieldvalue的设置对图中所有的类型转换错误都适用。如果希望为特定字段单独定制转换错误信息,则可以在Action范围的资源文件中添加i18n消息键invalid.fieldvalue.xxx,其中xxx是字段。

         invalid.fieldvalue.timeDate=日期转换错误

 

     OGNL作为表达式语言,功能十分强大,通常使用它来引用各种Java对象的属性。

1.   访问Bean属性

           表达式是由属性链构成的,如user.father.father.name,这个表达式由4个链式的属性构成,它引用了user祖父的名字。

  我们即可以用表达式来给属性赋值,也可以用它来获取属性的值。在属性链中间的某个对象属性是null的情况下,框架会自动创建对象,并赋值给该属性。它有个两个前提,第一,对象类型必须是遵循JavaBean规范的类,即这个类必须具有无参数的构造方法,否则无法自动创建实例,第二,属性必须提供setter方法,否则框架无法为该属性赋值。

 

2.   访问集合对象

             我们用一段代码来说明如何访问集合对象

Actiono类代码:

import java.util.List;

import com.opensymphony.xwork2.ActionSupport;

public class ShowArrayAndListAction extends ActionSupport{

	private String[]hobbies;
	private List<Double>numbers;
	private List<User>users;
	
	@Override
	public String execute(){
		//省略代码
		return SUCCESS;
	}

}

  在页面展示数据:

<%-迭代数组-%>
<s:iterator values="hobbies">
   <s:property/>
</s:iterator>

<%-迭代集合 元素类型为Double-%>
<s:iterator values="numbers">
   <s:property/>
</s:iterator>

<%-迭代集合 元素类型为User-%>
<s:iterator values="users">
  用户名: <s:property value="name"/></br>
  年龄:   <s:property value="age"/></br>
</s:iterator>

iterator标签迭代一个集合或者数组,其中value属性用于指定要迭代的集合属性,类型可以是Collection,Map,Iterator或者数组类型。iterator标签在迭代过程中,会把迭代的每一个对象暂时压入栈顶,这样在该标签内部可以直接访问元素对象的属性和方法,就可以使用不带value属性的property标签输出数据。在iterator标签执行完毕后,位于栈项的对象就会被删除。迭代下一个元素时,重复该过程。

访问列表或数据的某个元素,可以用属性名[index]的方式,如users[1].name。

访问Map的某一个元素,可以用属性名[key]的方式 ,如userMap['userA'].name。

可以通过size或者length来访问集合的长度。

 

访问ActionContext中的数据:

  Actioncontext中所包含的内容:

① ValueStack      ②  parameters    ③  application  ④ session    ⑤ attr      ⑥   request

OGNL所有表达式的解析必须针对ActionContext中的某个对象,这个对象也称为根对象。默认情况下,OGNL表达式是针对值栈解析 的,值栈是默认的根对象,也可以通过明确指定名字的方式将其他对象作为根对象。下面对ActionContext中的对象进行说明 。

application:用于访问application属性。#application.username或者#application['username'],相当于调用             application.getAttribute("username")。

session: 用于访问sessin属性,#session.username或者 #session["username"],相当于session.getAttribute("username")。

request :用于访问request属性,#request.username 或者 #request["username"],相当于request..getAttribute("username").。

parameters  :用于访问HTTP的请求参数。#parameters.username或者 #parameters['username']相当于调用request.getParameterValues("username"),将返回一个数组。

attr : 按照pageContext——request——session——application顺序访问其属性。

 

查看ActionContext中的数据:

 在Struts2中为了方便页面的数据调试和查看,特别提供了<s:debug>标签,该标签的作用就是辅助调试,该标签会在页面中生成一个超链接,单击超链接会分别显示ValueStack和 Stack Context中的所有信息。

Struts2标签与OGNL表达式:

使用OGNL表达式最多的地方就是Struts2标签,在标签中使用表达式需要注意以下几点。

①  Struts2标签的 属性都可以使用OGNL表达式。Struts2标签的属性是具有类型的,分为字符串类型和对象类型。例如创建URL      的标签<s:url>中的value属性为字符串类型,<s:set><s:property>标签的value属性为Object类型。

②  对于字符串类型的属性,如果要访问动态数据,必须使用%{...}这样的语法,否则将被直接看作字符常量。例如:

      <s:set name="myurl"  value="  'http://www.sohu.com'  "/>

     <s:url value="#myurl"/>   //显示#myurl

    <s:url value="%{#myurl}"/>   显示http://www.sohu.com

③  对于对象类型的属性,将直接作为OGNL表达式进行计算。如果需要对对象类型的属性指定字符常量,则必须在这个字符串        常量外加上一对单引号或者使用%{'constant string'}这样的语法 。

//要使用单引号或%{' '}      

   <s:set name="myurl"   value="  'http://www.sohu.com'  "/>

     <s:url value="#myurl"/>   // 显示http://www.sohu.com

④  如果对对象类型的属性使用了%{..}的语法,则语法会被忽略,而直接把内容当作OGNL表达工求解。例如,

<s:property value="%{#myurl}" /> 和 <s:property value="#myrul" /> 作用相同。如果分不清一个属性的值的类型是不是字符串类型,则可以直接加上%{...} 。

 

URl标签:

    URL标签的作用是构建一个URL地址,在该标签中借助param子元素可以指定在跳转URL的同时传递的参数

语法 :<s:url  value="url"

     <s:param name="parname"  value="parvalue" />

</s:url>

URL的标签使用如下:

<body>
     使用value指定url地址
    <s:url value="http://www.sohu.com"/><br/>

    使用变量生成url地址
    <s:set name="myurl" value="http://www.sohu.com"/>
    <s:url value="%{#myurl}"/><br/>

    使用param指定参数<br/>
    <s:url value="show.action">
         <s:param name="id" value="123" />
    </s:url>

</body>

 

日期标签:

   日期标签用于格式化输出一个日期,除此之外,还可以计算指定日期和当前日期时刻之间的时差。

语法 : <s:date format="format" nice="true | false" name="name"  id="id" />

format属性:表示按照指定的格式进行日期格式化。

nice属性: 用于指定是否输出指定日期与当前时间的时差,只有true和false两个值 ,默认是false 。

name属性: 表示当前需要格式化的日期。

id属性:表示引用该元素的id值。

 

我们通过一段代码来了解<s:date./>标签的用法

public class DateAction extends ActionSupport{

    private  Date currentDate;

    public String execute(){
      currentDate=new Date();
      return SUCCESS;
  }

    public Date getCurrentDate(){

       return  currentDate;
  }

     public void setCurrentDate( Date currentDate){

       this.currentDate=currentDate;
  }

}

页面:

<body>
    指定日期格式
   <s:date name="currentDate" format="dd/MM/yyyy" /><br/>

    不指定日期格式
   <s:date name="currentDate"/>

</body>

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值