Struts2是一套很优秀的Web应用框架,实现优雅、功能强大、使用简洁。能够说是Struts2是一款很成熟的MVC架构。
在我们学习Struts2时,最好是先学习它的执行流程、核心概念。从中得到启示。提升自己,而不不过学习怎么怎么使用它。
在网上看到这样一句话:
你千万不要成为一个仅仅会熟练使用框架的程序猿。那样。你会疲于奔命,你或许永远仅仅会使用 Hadoop ,而写不出一个 Hadoop ,你仅仅是一个 Hadoop程序猿,而不是一个分布式project师。
你或许永远仅仅会使用 Struts,而忘记了自己写 filter,你仅仅是一个 SSH 程序猿,而不是一个 Web project师。
话不多说,一起走进Struts2
一、系统架构
Struts2的官方文档附带了Struts2的架构图。
从这张图能够非常好的去理解Struts2
关于图中的Key:
- Servlet Filters:过滤器链,client的全部请求都要经过Filter链的处理。
- Struts Core:Struts2的核心部分,可是Struts2已经帮我们做好了,我们不须要去做这个
- Interceptors。Struts2的拦截器。Struts2提供了非常多默认的拦截器。能够完毕日常开发的绝大部分工作;而我们自己定义的拦截器,用来实现实际的客户业务须要的功能。
- User Created,由开发者创建的。包含struts.xml、Action、Template。这些是每一个使用Struts2来进行开发的人员都必须会的。
- 1.FilterDispatcher是整个Struts2的调度中心。也就是MVC中的C(控制中心),依据ActionMapper的结果来决定是否处理请求,假设ActionMapper指出该URL应该被Struts2处理。那么它将会运行Action处理,并停止过滤器链上还没有运行的过滤器。
-
2.ActionMapper 会推断这个请求是否应该被Struts2处理,假设须要Struts2处理。ActionMapper会返回一个对象来描写叙述请求相应的ActionInvocation的信息。
- 3.ActionProxy。它会创建一个ActionInvocation实例,位于Action和xwork之间,使得我们在将来有机会引入很多其它的实现方式。比方通过WebService来实现等。
- 4.ConfigurationManager是xwork配置的管理中心,能够把它看做struts.xml这个配置文件在内存中的相应。
- 5.struts.xml,是开发人员必须光顾的地方。是Stuts2的应用配置文件,负责诸如URL与Action之间映射关系的配置、以及运行后页面跳转的Result配置等。
-
6.ActionInvocation:真正调用并运行Action,它拥有一个Action实例和这个Action所依赖的拦截器实例。ActionInvocation会依照指定的顺序去运行这些拦截器、Action以及相应的Result。
- Interceptor(拦截器):是Struts2的基石。类似于JavaWeb的Filter,拦截器是一些无状态的类。拦截器能够自己主动拦截Action,它们给开发人员提供了在Action运行之前或Result运行之后来运行一些功能代码的机会。
-
7.Action:用来处理请求,封装数据。
- 二、执行流程
注意:Action完整的调用过程都是由ActionInvocation对象负责
拦截器的执行被分成两部分,一部分在Action之前执行,一部分在Result之后执行,并且顺序是刚好反过来的。也就是在Action执行前的顺序,比方是拦截器1、拦截器2、拦截器3,那么执行Result之后,再次执行拦截器的时候,顺序就变成拦截器3、拦截器2、拦截器1了。
这就好比,你要去奶奶家。需要通过 水泊梁山->盘丝洞 -> 索马里,到了奶奶家。看奶奶回来的时候,就必需要通过 索马里 -> 盘丝洞 -> 水泊梁山。
所以ActionInvocation对象运行的时候须要通过非常多复杂的过程,依照指定拦截器的顺序依次运行。
相应Struts2的架构图例如以下
9.到了奶奶家,然后运行Action的execute方法
10.然后依据execute方法返回的结果(Result),去struts.xml中匹配选择下一个页面
11.依据结果(Result)找到页面后,在页面上(有非常多Struts2提供的模板),能够通过Struts2自带的标签库来訪问须要的数据,并生成终于页面
注意:这时还没有给client应答,仅仅是生成了页面
12.最后,ActionInvocation对象倒序运行拦截器,从奶奶家回来
13.ActionInvocation对象运行完成后,已经得到响应对象(HttpServletResponse)了,最后按与过滤器(Filter)配置定义相反的顺序依次经过过滤器,向client展示出响应的结果
得到完整Struts2架构图
当客户端向服务器端发送一个action请求,该请求进入到action前会经历Struts2的多个拦截器,例如modeldriven(model拦截器)和parms(参数封装拦截器)等多个拦截器,也可以自己定义拦截器,当拦截器接收到一个action请求,就会调用create()方法创建一个值栈对象(作用范围为一次请求),再调用init()方法初始化,值栈中包含了两个对象,一个是Struts2的上下文对象contextMap和对象栈,上下文对象其实就是一个Map集合。值栈中包含了一次请求的过程中所有的参数。
Struts2参数是怎样封装到值栈中去的?
如果一个action实现了modelDriven接口,则action请求在经过modeldriven拦截器的时候会将model对象放入对象栈栈顶
例子:
public class ProductAction extends ActionSupport implements ModelDriven{
private Product model = new Product();
public Product getModel() {
return model;
}
}
经过modeldriven拦截器拦截器的时候会先判断action类是否实现了ModelDriven接口,如果实现了则会调用action类中实现的getModel方法,返回一个model对象(model对象就是要接收参数的对象,需要在类中先实例化),再放入对象栈栈顶(原本的栈顶对象是action)。当action请求经过parms(参数封装拦截器)时,parm会将参数封装到对象栈中去,如果传出来的参数有id=3,而model对象和action对象都有id这个属性,因为封装时是从栈顶开始查找的,如果找到相同的属性名,就会开始赋值,即使下面的其他对象有相同的属性名,也不会赋值,因此action对象中的id属性为null,赋值成功后再从栈顶重新找下一个属性。
注:action对象指的是action请求的那个action类的实例化对象,action对象要封装请求里面的参数需要声明和参数名相同的变量,再生成get()和set()方法。
在转发页面怎么获取Struts2传过来的参数?
action在执行的时候可以将处理好的数据放入值栈中去,当action执行完转发(重定向不行,因为值栈的作用域是一次请求)到JSP页面时可以通过OGNL表达式获取值栈中的数据,如果ognl表达式中只是写属性名,例如id,则会调用findValue()从对象栈栈顶开始找同名的属性,对象栈找不到,则会到contextMap寻找与属性名相同的key,找到后就会返回,如果在OGNL表达式中,在属性名前加上#,则表示直接从contextMap中查找,不去对象栈中查找。
在JSP页面也可以通过EL表达式获取值栈中的参数,因为struts2重写了request的getAttriture()方法(多加了一个findValue()方法),当EL开始从page域查找相同的属性名,查到request域还是找不到的话,会调用findValue()方法,从值栈中开始查找。