写在前面:Struts2主要包含前端控制器FC、Action、ValueStack容器、Result、Interceptor拦截器、Tags标签6个核心组件,本文主要介绍这几个组件的合作关系,由此构成Struts2的工作流程,以便更好地理解和使用Struts2。
背景知识
1、Struts2基础标签
1)用于输出的标签
--*<s:property value="name"/> value的值实际上是OGNL表达式
--特殊用法
<s:property /> 用于输出栈顶数据
2)用于调试的标签
<s:debug/>
--该标签仅仅是给程序员用的,用于调试,即用于观察ValueStack中的数据
--当代码提交给测试、客户时,要把该标签删除
--该标签具有互斥性(可以理解为BUG),如果页面上出现多次这个标签时,实际上只有第一个有效
3)用于循环的标签
a、用于循环集合
--比如Action中有集合属性List<User> users
<s:iterator value="users">
<s:property value="userName"/>
</s:iterator>
b、用于循环数字
<s:iterator begin="1" end="3" var="i">
<s:property value="#i"/>
</s:iterator>
2、OGNL表达式
1)类似于EL表达式,但是比EL功能强大
2)表达式允许我们通过一个字符串,来访问JAVA对象。从而避免了在JSP上嵌套着写JAVA代码。即,表达式可以通过字符串间接的帮助我们访问JAVA对象。
3)基本原理
--OGNL表达式将被OGNL引擎解析,这个过程是Struts2自行完成的
--OGNL引擎允许我们访问两种类型的对象,一种是JavaBean类型,称之为root对象;另一种为Map类型,称之为context对象。
--当OGNL表达式以#开头时,OGNL引擎会访问context对象,否则会访问root对象
4)root对象
--我们写OGNL表达式时(不以#开头的情况),首先要明确谁是root对象,其次从该对象的下级属性写起。
举例:
--比如以Action为root对象,Action中有String name, User user属性,那么要在页面显示这两个属性的话,写法如下:
<s:property value="name"/>
<s:property value="user.userName"/>
--比如以User为root对象,要在页面上显示它的名称,写法如下:
<s:property value="userName"/>
5)context对象
--OGNL表达式以#开头,则访问context对象
--#后面写的是context对象的key,context对象是Map类型
3、ValueStack
1)什么是ValueStack
Struts2中并不是直接将OGNL组件搬过来使用,而是使用一个对象容器ValueStack对这个组件进行了改造及封装,因此我们在Struts2中是通过ValueStack来使用OGNL表达式。并且ValueStack中封装了Action的数据,上下文等数据,这些数据我们都可以通过OGNL表达式来获得。
2)原理
--结构:ValueStack中封装了OGNL引擎、context对象、Stack对象。
--规则:当我们在标签中写一个OGNL表达式时,该表达式被Struts2自动的传递给ValueStack中的OGNL引擎,引擎会判断表达式是否以#开头,若是则直接从context对象中取值,否则向Stack中取值。
--如何向Stack取值:OGNL表达式从栈顶向下依次取值,它是以栈的每一级对象作为root对象从中取值的,若取到值则直接返回,否则继续向下取值,直到栈底为止。
3)*栈顶的变化
a、默认情况下,栈顶是Action
*b、在循环时,栈顶将发生变化,规则如下:
--在未循环时,栈顶依然是Action
--在第一次循环时,Struts2将循环变量(如user)压入到栈中,因此循环变量占据栈顶位置,而Action处于栈的第二位。
--在第n次循环时,Struts2将第n-1次的循环变量从栈顶移除,然后再将本次循环的变量压入栈中,因此本次循环的变量占据栈顶位置,而Action依然处于栈的第二位。
--当最后一次循环结束时,Struts2将最后一次循环的变量从栈顶移除,而没有新的变量压入栈中,那么Action再次成为栈顶。
简而言之:
--在循环过程中,栈顶是循环变量
--循环结束后,栈顶是Action
4)*总结(OGNL,ValueStack)
a、在没有循环时,栈顶是Action,即可以以Action为root来写OGNL表达式
b、在循环时,栈顶是循环变量,栈第二位是Action
--循环集合
栈顶是集合中的对象,那么可以以该对象为root,来写OGNL表达式,即直接从该root对象的下级属性写起
举例:Action中有属性List<User> users,在页面上循环users
<s:iterator value="users">
<s:property value="userName"/>
</s:iterator>
即:循环过程中,栈顶是User对象,以它为root来写OGNL表达式的话,就写userName
--循环数字
栈顶是循环变量(数字),但是由于我们不能以数字为root(以JavaBean为root)来写OGNL表达式,因为数字已经是基本类型数据,没有下级属性让我们访问。如果我们想直接输出栈顶可以用<s:property/>,如果我们想引用循环变量,则需要写<s:property value="#i"/>,从context对象中依然可以取得这个值。
举例:从1循环到3
<s:iterator begin="1" end="3" var="i">
<s:property value="#i"/>
</s:iterator>
工作原理
总结8句话,方便记忆:
请求提交控制器,根据配置找Action。创建VS栈容器,实例Action放栈顶。
调用Action算输出,历经层层拦截器。根据方法返回值,调用Result做输出。
详细流程如下(结合图示理解):
1、请求传入前端控制器FC
2、前端控制器FC根据Struts.xml配置文件查找Action
3、创建ValueStack值栈容器
4、创建Action并存入ValueStack栈顶
5、6、7、FC调用并执行Action逻辑,此过程可能先被Interceptor拦截器拦截处理
8、9、FC根据Action返回的result通过Result组件跳转到相应的JSP界面
10、在解析JSP时,若发现OGNL表达式,则向ValueStack容器中的OGNL引擎传入表达式,按照先前介绍的方式查询对应的值
11、OGNL引擎返回查找到的值给JSP,待所有数据加载完成,呈现JSP(通过Tags标签)界面
Tips:当重新提交请求(比如刷新界面)时,Action、ValueStack均会被重新创建。
转载请注明出处:
http://blog.csdn.net/daijin888888/article/details/51461043