struts1和struts2的原理区别与使用详解

struts | 2019-09-13 10:02:39

一、Struts1与Struts2原理区别详解

1.struts1和struts2 是2个完全不同的框架,其实struts2核心就是 webwork框架
struts1以ActionServlet作为核心控制器,由ActionServlet负责拦截用户的所有请求。Struts 1框架有3个重要组成部分:Action、ActionForm和ActionForward对象。ActionForm必须实现ActionForm的基类,设计上并不是真正的POJO。
struts2核心控制器是FilterDispatcher,Struts 2用于处理用户请求的Action实例,并不是用户实现的业务控制器,而是Action代理——因为用户实现的业务控制器并没有与Servlet API耦合,显然无法处理用户请求。而Struts 2框架提供了系列拦截器,该系列拦截器负责将HttpServletRequest请求中的请求参数解析出来,传入到Action中,并回调Action的execute方法来处理用户请求。显然,上面的处理过程是典型的AOP(面向切面编程)处理方式。

2.先说一下struts2的工作流程: 
核心控制器FilterDispatcher是Struts 2框架的基础,包含了框架内部的控制流程和处理机制。 
业务控制器Action和业务逻辑组件是需要用户来自己实现的。用户在开发Action和业务逻辑组件 
的同时,还需要编写相关的配置文件,供核心控制器FilterDispatcher来使用。 
Struts 2的工作流程相对于Struts 1要简单,与WebWork框架基本相同,所以说Struts 2是 
WebWork的升级版本。Struts 2框架按照模块来划分,可以分为Servlet Filters、Struts核心模 
块、拦截器和用户实现部分。Struts 2框架结构图如图3.1所示。 
一个请求在Struts 2框架中的处理大概分为以下几个步骤。 
客户端提交一个(HttpServletRequest)请求,如上文在浏览器中输入 http://localhost:
8080/bookcode/ch2/Reg.action就是提交一个(HttpServletRequest)请求。 
请求被提交到一系列(主要是3层)的过滤器(Filter),如(ActionContextCleanUp、其他过 
滤器(SiteMesh等)、 FilterDispatcher)。注意:这里是有顺序的,先ActionContext 
CleanUp,再其他过滤器(Othter Filters、SiteMesh等),最后到FilterDispatcher。 
FilterDispatcher是控制器的核心,就是MVC的Struts 2实现中控制层(Controller)的核心。 
FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个(HttpServlet 
Request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher则把请求的处 
理交给ActionProxy。 
ActionProxy通过Configuration Manager(struts.xml)询问框架的配置文件,找到需要调用的 
Action类。例如,用户注册示例将找到UserReg类。
ActionProxy创建一个ActionInvocation实例,同时ActionInvocation通过代理模式调用Action 
。但在调用之前,ActionInvocation会根据配置加载Action相关的所有Interceptor(拦截器) 。
一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果 
result。 

3.说完struts2还应该说一下struts1的工作原理: 

 由ActionForm和javaBean组成,其中ActionForm用于封装用户的请求参数,封装成ActionForm 

对象,该对象被ActionServlet转发给Action,Action根据ActionFrom里面的请求参数处理用户 

的请求。把我看到的和知道的整理出来。 

对于采用Struts框架的Web应用,在Web应用启动时就会加载并初始化ActionServlet,ActionServlet从struts-config.xml文件中读取配置信息,把它们存放到各种配置对象中,例如Action的映射信息存放在ActionMapping对象中。(struts的配置文件struts-config.xml:一个用户请求是通过ActionServlet来处理和转发的。那么,ActionServlet如何决定把用户请求转发给哪个Action对象呢?这就需要一些描述用户请求路径和Action映射关系的配置信息了。在Struts中,这些配置映射信息都存放在特定的XML文件struts-config.xml中。在该配置文件中,每一个Action的映射信息都通过一个元素来配置。这些配置信息在系统启动的时候被读入内存,供Struts在运行期间使用。在内存中,每一个元素都对应一个org.apache.struts.aciton.ActionMapping的实例) 


用户通过客户端向服务器发出一个请求,而我们已经在web.xml配置了所有符合某某格式的请求都将由指定的Servlet来处理。比如说:只要是以.do结尾的请求(*.do)都由org.apache.struts.action.ActionServlet来对其进行处理。而ActionServlet和ActionMapping都已经在服务器启动的时候被加载到内存里面。 

结合登录例子: 

当用户登录时,地址栏的URL为:http://localhost:8080/struts_login/login.do


ActionServlet会拿到用户的请求,并且去分析这个URL,它会截下/login(不包含.do)这一部分,截来之后,它的目的是为了去struts-config.xml这个配置文件里面找标签path属性的值等于所截部分的那个Action。找到之后,ActionServlet会把表单提交的数据给存放到ActionForm上,那ActionServlet又是怎么找到ActionForm的呢?因为Action标签里面有一个属性是name,它的值就是所要找的ActionForm的名字,这样ActionServlet会去上面的标签里面找(注意不是)标签里面的name属性的值是与Action标签里面的name的值相等的,然后根据里面type属性的值,也就是所指的对象new一个实例,再把表单上相应的数据set进去。同时把标签里面的东西放到继承Action类的那个指定类(本例子用的是LoginAction)的public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception 

这个方法里面参数mapping里面去,放好之后,再去调用我们自己写的类(LoginAction),并把mapping,form,request,response作为参数传到execute方法里面去。 

至于如何转向的问题:这是由Struts完成的,只要你的execute能返回一个ActionForward对象,并且里面包含有转向的信息,Struts就会根据参数(mapping.findForward("success")里面的"success")去找相应配置文件(struts-config.xml)里面的相应标签(),然后再由Struts框架决定转向谁。由于上面已经说过,整个转向的相关信息已经存放在mapping里面,所以mapping.findForward("success")能够找到相应的标签。 


当ActionServlet接收到一个客户请求时,将执行如下流程: 

(1) 检索和用户请求匹配的ActionMapping实例,如果不存在,就返回用户请求路径无效的信息。 

(2) 如果ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中。 

(3) 根据配置信息决定是否需要表单验证。如果需要验证,就调用ActionForm的validate()方法。 

(4) 如果ActionForm的validate()方法返回null返回一个不包含ActionMessage的ActionErrors对象,就表示表单验证成功。 

(5) ActionServlet根据ActionMapping实例包含的映射信息决定将请求转发给哪个Action。如果相应的Action实例不存在,就先创建这个实例,然后调用Action的execute()方法。 

(6) Action的execute()方法返回一个ActionForward对象,ActionServlet再把客户请求转发给ActionForward对象指向的JSP组件。 

(7) ActionForward对象指向的JSP组件生成动态网页,返回给客户。 

对于以上流程的流程(4),如果ActionForm的validate()方法返回一个包含一个或多个ActionMessage的ActionErrors对象,就表示表单验证失败,此时ActionServlet将直接把请求转发给包含用户提交表单的JSP组件。在这种情况下,不会再创建Action对象并调用Action的execute()方法。 

二 最后谈一谈struts1与struts2的区别了: 

首先:struts1是通过servlet启动的。 

1、struts1要求Action类继承一个抽象基类,而不是接口。 

struts2的action类可以实现一个action接口,也可以实现其他接口。 

2、sturts1 action是单例模式,线程是不安全的。 

struts2 action线程是安全的,action为每一个请求都生成了一个实例。 

3、sturts1过去依赖serlet API,不容易测试。 

struts2不依赖于容器,允许Action脱离容器单独被测试。 

4、Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。 

Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。 

5、Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。 

Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL). 

6、Struts 1使用标准JSP机制把对象绑定到页面中来访问。 

Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。 

7、Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。 

Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。 

8、Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。 

Struts2支持通过validate方法和XWork校验框架来进行校验。 

9、Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 

Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。


10.执行流程
a)struts1 
jsp发起httprequest请求->servlet捕获->struts.xml->namespace+ActionName-> Action->填充表单setXxx()->action.execute()->”success”->Result->设置request属性->跳转目标页
b) Action(jsp发起httprequest请求,被过滤器捕获)->FilterDispatcher->struts.xml->namespace+ActionName->new Action->填充表单setXxx()->action.execute()->”success”->Result->设置request属性->跳转目标页


二、使用区别详解

1) 在Action实现类方面的对比:Struts 1要求Action类继承一个抽象基类;Struts 1的一个具体问题是使用抽象类编程而不是接口。Struts 2 Action类可以实现一个Action接口,也可以实现其他接口,使可选和定制的服务成为可能。Struts 2提供一个ActionSupport基类去实现常用的接口。即使Action接口不是必须实现的,只有一个包含execute方法的POJO类都可以用作Struts 2的Action。 
2) 线程模式方面的对比:Struts 1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts 1 Action能做的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的;Struts 2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。 
3) Servlet依赖方面的对比:Struts 1 Action依赖于Servlet API,因为Struts 1 Action的execute方法中有HttpServletRequest和HttpServletResponse方法。Struts 2 Action不再依赖于Servlet API,从而允许Action脱离Web容器运行,从而降低了测试Action的难度。 当然,如果Action需要直接访问HttpServletRequest和HttpServletResponse参数,Struts 2 Action仍然可以访问它们。但是,大部分时候,Action都无需直接访问HttpServetRequest和HttpServletResponse,从而给开发者更多灵活的选择。 
4) 可测性方面的对比:测试Struts 1 Action的一个主要问题是execute方法依赖于Servlet API,这使得Action的测试要依赖于Web容器。为了脱离Web容器测试Struts 1的Action,必须借助于第三方扩展:Struts TestCase,该扩展下包含了系列的Mock对象(模拟了HttpServetRequest和HttpServletResponse对象),从而可以脱离Web容器测试Struts 1的Action类。Struts 2 Action可以通过初始化、设置属性、调用方法来测试。 
5) 封装请求参数的对比:Struts 1使用ActionForm对象封装用户的请求参数,所有的ActionForm必须继承一个基类:ActionForm。普通的JavaBean不能用作ActionForm,因此,开发者必须创建大量的ActionForm类封装用户请求参数。虽然Struts 1提供了动态ActionForm来简化ActionForm的开发,但依然需要在配置文件中定义ActionForm;Struts 2直接使用Action属性来封装用户请求属性,避免了开发者需要大量开发ActionForm类的烦琐,实际上,这些属性还可以是包含子属性的Rich对象类型。如果开发者依然怀念Struts 1 ActionForm的模式,Struts 2提供了ModelDriven模式,可以让开发者使用单独的Model对象来封装用户请求参数,但该Model对象无需继承任何Struts 2基类,是一个POJO,从而降低了代码污染。 
6) 表达式语言方面的对比:Struts 1整合了JSTL,因此可以使用JSTL表达式语言。这种表达式语言有基本对象图遍历,但在对集合和索引属性的支持上则功能不强;Struts 2可以使用JSTL,但它整合了一种更强大和灵活的表达式语言:OGNL(Object Graph Notation Language),因此,Struts 2下的表达式语言功能更加强大。 
7) 绑定值到视图的对比:Struts 1使用标准JSP机制把对象绑定到视图页面;Struts 2使用“ValueStack”技术,使标签库能够访问值,而不需要把对象和视图页面绑定在一起。 
8) 类型转换的对比:Struts 1 ActionForm 属性通常都是String类型。Struts 1使用Commons-Beanutils进行类型转换,每个类一个转换器,转换器是不可配置的;Struts 2使用OGNL进行类型转换,支持基本数据类型和常用对象之间的转换。 
9) 数据校验的对比:Struts 1支持在ActionForm重写validate方法中手动校验,或者通过整合Commons alidator框架来完成数据校验。Struts 2支持通过重写validate方法进行校验,也支持整合XWork校验框架进行校验。 
10) Action执行控制的对比:Struts 1支持每一个模块对应一个请求处理(即生命周期的概念),但是模块中的所有Action必须共享相同的生命周期。Struts 2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。开发者可以根据需要创建相应堆栈,从而和不同的Action一起使用。 
11) 捕获输入:Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。




登录后即可回复 登录 | 注册
    
关注编程学问公众号