在实际的开发中的大部分情况,Struts2框剪已经非常好的自动完成了数据转移和类型转换任务。然而若想进一步提高我们的能力,花一点时间和精力来学习数据转移和类型转换究竟是如何工作的将是必要的。也许你已经学会了在简单的情况下如何利用自动数据转移,然而在面临更加复杂的Java端类型(例如Map和List)时,将怎样编写代码呢?本节内容正是要解答上述疑问的。

1.数据转移和类型转换:Web应用程序领域的常见任务

Web应用程序领域的一个常见任务是从基于字符床的HTTP向Java语言的不同类型移动和转换数据。将字符床解析为double或者float,捕获坏数据抛出的异常,这些任务没有一点意思。更糟的是,这些任务实际上是纯基础设施。

数据转移和类型转换实际上发生在请求处理周期的两端。几乎Web应用程序中的每一个请求都会发生这个过程,它是这个领域与生俱来的部分。大部分时候我们会将这个责任交给框架,然而有些时候我们会想扩展或者配置这个自动化支持。Struts2类型转换机制功能强大并且特别容易扩展。

1.1 OGNL和Struts2

我们还没有解释所有这些数据如何从HTTP请求到Java语言,以及如何再通过JSP标签回到HTML。下面的内容将阐明这个神秘的过程。

1.1.1 OGNL是什么

OGNL是Object-Graph Navigation Language(对象图导航语言)的简称。这听起来有些让人恐惧,似乎我们在学校里学的还不够,它听起来太学术味了。OGNL是一种强大的技术,它被集成在Struts2框架中用来帮助实现数据转移和类型转换。从开发人员基于Struts2框架构建应用程序的角度看,OGNL包含两件事:表达式语言和类型转换器。

1.表达式语言

我们已经在表单输入字段的name属性和JSP标签中使用过OGNL表达式语言了。这这两个地方,我们使用OGNL表达式将Java端的数据属性和基于文本的视图层中的字符串绑定起来。

<h5>Congratulations! You have created </h5>
<h3>The <s:property value="portfolioName" /> Portfolio</h3>

OGNL表达式语言是value属性双引号之间的片段,Struts2 property标签从对象的属性中取值,然后将它写入到HTML中代替这个标签,这是表达式语言的要点。表达式语言允许我们使用简单的语法来引用Java环境中存在的对象。

注:OGNL转义序列%{表达式}可用来告诉框架什么时候把表达式当成OGNL表达式而不是作为字符串面值解析;在默认情况下,框架敬爱那个自动把字符串当作OGNL表达式求值。

2.类型转换

基于字符串的HTML世界和框架的本地Java类型之间移动数据时类型转换是如何发生的呢?除了表达式语言,我们也一直在使用OGNL类型转换器。数据转移时类型转换必定发生,即使是两端类型(是字符串时)相同,这仅仅意味着类型转换比较容易。

1.1.2 OGNL如何融入框架

数据进入和离开框架时,数据在不同的区域间移动时,OGNL如何帮助绑定和转换数据呢?下图展示了整个过程。

数据转移和类型转换过程.png

1.数据进入

用户输入名字和年龄,并提交了表单,数据的旅程就开始了。当数据进入框架后,它作为一个HttpServletRequest对象公开给Java语言。Struts2经请求参数作为名/值对存储,名和值都是String类型。接下来框架开始处理这些参数的数据转移以及类型转换。

如图所示,在开始时,Struts2就会将动作对象置于叫做ValueStack的对象上,而User对象作为动作的组件的JavaBean属性也被公开出来。而另一方面,当用户发出请求时,params拦截器会把请求对象中的数据转移到ValueStack上。于是,用户提交的数据属性和Struts2公开的属性就会在ValueStack上出现重复。此时神奇的事情发生了,接下来就是见证奇迹的时刻:

ValueStack是一个Struts2结构,它呈现了一堆对象属性的聚合。如果有重复属性存在,那么栈中最高的对象的属性会是由ValueStack代表的虚拟对象公开的属性。在上述情况下,由于Struts2公开属性在前,而用户提交数据在后,在栈中用户提交的数据更高,于是数据就自动找到了转移到Struts2公开的对象的属性上的道路。

在使用OGNL表达式定位到目标属性之后,可以通过使用正确的值调用属性的set方法把数据移动到这个属性上。这是类型转换就开始工作了。我们需要把字符串转换为OGNL指向的age属性的Java类型。OGNL会咨询它可用的类型转换器的集合一确定是否他们中某个可以处理这个特定的转换。

2.数据流出

与数据进入相反,在动作完成自身的业务、调用业务逻辑、做数据操作后,某个最终结果会触发,它会向用户呈现一个新的应用程序试图。在这个过程中,数据对象会一直保留在ValueStack上。当结果开始自己的呈现过程时,它也通过标签中的OGNL表达式语言访问ValueStack,从其中取得数据。