Struts作为MVC 2的Web框架,自推出以来不断受到开发者的追捧,得到广泛的应用。作为最成功的Web框架,Struts自然拥有众多的优点:MVC 2模型的使用、功能齐全的标志库(Tag Library)、开放源代码。
但是,正所谓“没有最好,只有更好”,Struts1.x自身也有不少的缺点:需要编写的代码过多,容易引起“类爆炸”、单元测试困难。这些缺点随着Web的发展越来越明显。这就促生了Struts 2,它的诞生能很好的解决上述问题。
一、引言
Struts的第一个版本是在2001年5月份发布的。它的最初设想是通过结合JSP和Servlet,使Web应用的视图和业务/应用逻辑得以清晰地分离开来。在Struts之前,最常见的做法是在JSP中加入业务和应用逻辑,或者在Servlet中通过println()来生成视图。
自从第一版发布以来,Struts实际上已成为业界公认的Web应用标准。它的炙手可热也为自己带来了改进和变更,所以不但要跟上对Web应用框架不断变化的需求,而且要与日渐增多竞争激烈的众多框架的特性相融合。
到最后,产生了几个下一代Struts的解决方案。其中两个最受瞩目的方案是Shale和Struts Ti。Shale是一个基于构件的框架,并在最近成为Apache的顶级项目。而Struts Ti则是在Struts的成功经验基础上继续坚持对前端控制器(Front Controller)和MVC(model-view-controller)模式进行改进。
WebWork项目是在2002年3月发布的,它对Struts式框架进行了革命性改进,引进了不少新的思想、概念和功能,但和原Struts代码并不兼容。WebWork是一个成熟的框架,经过了好几次重大的改进与发布。
在2005年12月,WebWork与Struts Ti宣布合并。与此同时,Struts Ti改名为Struts Action Framework 2.0,成为Struts真正的继承者。
最后要注意的是,并不是说Struts或WebWork项目已经停止开发了。由于人们对这两个项目的兴趣仍然很高,而且也有很多开发者仍然愿意使用它们,因此这两个项目还在继续开发中,继续修复Bug,改进功能和继续添加新功能。
二、 Action的区别
对于有着丰富的Struts1.x开发经验的朋友来说,都十分的清楚Action是整个Struts框架的核心内容,当然Struts2也不例外。不过,Struts1.x与Struts2的Action模型很大的区别。
Struts2和Struts1.x的差别,最明显的就是Struts2是一个pull-MVC架构。这是什么意思呢?从开发者角度看,就是说需要显示给用户的数据可以直接从Action中获取,而不像Struts1.x那样,必须把相应的Bean存到Page、Request或者Session中才能获取。Struts1.x 必须继承org.apache.struts.action.Action或者其子类,表单数据封装在FormBean中。Struts 2无须继承任何类型或实现任何接口,表单数据包含在Action中,通过Getter和Setter获取(如下面的ActionForStruts2的代码示例)。
虽然,在理论上Struts2的Action无须实现任何接口或者是继承任何的类,但是,在实际编程过程中,为了更加方便的实现Action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类,并且重载(Override)此类里的String execute()方法。如下所示:
package ActionDiffer;
import java.text.DateFormat;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
public class ActionForStruts2 extends ActionSupport {
private String message;
public String getMessage() {
return message;
}
@Override
public String execute() {
message = " This is hello from strtuts2. Now is: " +
DateFormat.getInstance().format( new Date());
return SUCCESS;
}
}
首先,从ActionForStruts2可以看出,返回的对象不是ActionForward,而是String。如果你不喜欢以字符串的形式出现在你的代码中,有个Helper接口Action可以以常量方式提供常见结果,如“success”、“none”、“error”、“input”和“login”。
另外, 按照惯例,在Struts1.x中只有“execute”方法能调用Action, 但在Struts2中并非必要,任何声明为public String methodName() 方法,都能通过配置来调用Action。
最后,和Struts1.x最大的革命性的不同是,Struts2处理Action过程中调用的方法(“execute”方法)是不带参数的。那如何获取所需要的对象呢?答案是使用IoC(反转控制,Inversion of Control),也叫“依赖注入(Dependency Injection)”的模式(想更多地了解这方面信息请看Martin Fowler的文章http://www.martinfowler.com/articles/injection.html)。Spring框架使得这个模式流行起来,然而Struts2的前身(WebWork)也同时应用上了这个模式。
三、IoC
IoC(Inversion of Control,以下译为控制反转),随着Java社区中轻量级容器(Lightweight Contianer)的推广而越来越为大家耳熟能详。在此,无需再多费唇舌来解释“什么是控制反转”和“为什么需要控制反转”。因为互联网上已经有非常多的文章对诸如此类的问题作了精彩而准确的回答。读者可以去读一下Rod Johnson和Juergen Hoeller合著的《Expert one-on-one J2EE Development without EJB》或Martin Fowler所写的《Inversion of Control Containers and the Dependency Injection pattern》。
众所周知,Struts2是以Webwork 2作为基础发展出来。而在Webwork 2.2之前的Webwork版本,其自身有一套控制反转的实现,Webwork 2.2在Spring 框架的如火如荼发展的背景下,决定放弃控制反转功能的开发,转由Spring实现。值得一提的是,Spring确实是一个值得学习的框架,因为有越来越多的开源组件(如iBATIS等)都放弃与Spring重叠的功能的开发。因此,Struts2推荐大家通过Spring实现控制反转。
为了更好地了解反转控制,下面来看一个例子,如何利用IoC在Action处理过程中可以访问到当前请求HttpServerRequest对象。
在例子中,使用的依赖注入机制是接口注入。就如其名称一样,接口注入需要的是已经被实现了的接口。这个接口包含了相应属性的setter,为Action提供值。例子中使用了ServletRequestAware接口,如下:
public interface ServletRequestAware {
public void setServletRequest(HttpServletRequest request);
}
当继承这个接口后,原本简单的Action看起来有点复杂了,但是这时可以获取HttpServerRequest对象来使用了。
public class IoCForStruts2 implements ServletRequestAware {
private HttpServletRequest request;
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public String execute() throws Exception {
// 可以开始使用request对象进行工作了
return Action.SUCCESS;
}
}
看起来现在这些属性是类级别的,并不是线程安全的,会出现问题。其实在Struts2里并没有问题,因为每个请求过来的时候都会产生一个新的Action对象实例,它并没有和其他请求共享一个对象,所以不需要考虑线程安全问题。
四、拦截器
Interceptor(以下译为拦截器),在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也提供了一种可以提取action中可重用的部分的方式。
Struts1.x的标准框架中不提供任何形式的拦截器,虽一个名为SAIF的附加项目则实现了这样的功能,但它的适用的范围还很有限。
拦截器是Struts2的一个强有力的工具,有许多功能(feature)都是构建于它之上,如国际化、转换器,校验等。谈到拦截器,还有一个流行的词——拦截器链(Interceptor Chain,在Struts2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
Struts 2的拦截器实现相对比较简单。当请求到达Struts2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),最后一一地调用列表中的拦截器。
Struts 2已经提供丰富多样功能齐全的拦截器实现。读者可以到struts2-all-2.0.6.jar或struts2-core-2.0.6.jar包的struts-default.xml查看关于默认的拦截器与拦截器链的配置。
作为“框架(framework)”,可扩展性是不可缺少的,因为世上没有放之四海而皆准的东西。虽然,Struts 2为我们提供如此丰富的拦截器实现,但是这并不意味我们失去创建自定义拦截器的能力,恰恰相反,在Struts 2自定义拦截器是相当容易的一件事。
五、Struts2和Struts1.x的全面比较
为了对Struts2和Strtus1.x进行全面的比较,让读者了解这两种框架各自的优缺点,以便于在自己的项目中,根据实际情况,选择合适的框架,对它们两者进行比较,总结了如下表分析比较。
特性比较:
Action类
Struts1.x要求Action类要扩展自一个抽象基类。Struts1.x的一个共有的问题是面向抽象类编程而不是面向接口编程。
Struts2的Action类实现了一个Action接口,连同其他接口一起来实现可选择和自定义的服务。Struts2提供一个名叫ActionSupport的基类来实现一般使用的接口。当然,Action接口不是必须的。任何使用execute方法的POJO对象可以被当作Struts 2的Action对象来使用。
线程模型
Struts1.x Action类是单例类,因为只有一个实例来控制所有的请求。单例类策略造成了一定的限制,并且给开发带来了额外的烦恼。Action资源必须是线程安全或者同步的。
Struts2 Action对象为每一个请求都实例化对象,所以没有线程安全的问题。(实践中,servlet容器给每一个请求产生许多丟弃的对象,并且不会导致性能和垃圾回收问题)。
Servlet 依赖
Struts1.x的Action类依赖于servlet API,当Action被调用时,以HttpServletRequest和HttpServletResponse作为参数传给execute方法。
Struts2的Action和容器无关。Servlet上下文被表现为简单的Maps,允许Action被独立的测试。Struts2的Action可以访问最初的请求(如果需要的话)。但是,尽可能避免或排除其他元素直接访问HttpServletRequest或HttpServletResponse。
易测性
测试Struts1.x的主要问题是execute方法暴露了Servlet API这使得测试要依赖于容器)。第三方的扩展,如Struts TestCase,提供了一套Struts1的模拟对象(来进行测试)。
Struts2的Action可以通过初始化、设置属性、调用方法来测试。依赖注入的支持也是测试变得更简单。
捕获输入
Struts1.x使用ActionForm对象来捕获输入。象Action一样,所有的ActionForm必须扩展基类。因为其他的JavaBean不能作为ActionForm使用,开发者经常创建多余的类来捕获输入。DynaBeans可以被用来作为替代ActionForm的类来创建。但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。
Struts2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven 特性简化了taglib对POJO输入对象的引用。
表达式语言
Struts1.x整合JSTL,所以它使用JSTL的表达式语言。表达式语言有基本的图形对象移动,但是对集合和索引属性的支持很弱。
Struts2使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL)。
将值绑定到页面
Struts1.x使用标准JSP机制来绑定对象到页面上下文。
Struts2使用“ValueStack”技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。
类型转换
Struts1.x的ActionForm属性经常都是String。Struts 1.x使用Commons-Beanutils来进行类型转换。转换每一个类,而不是为每一个实例配置。
Struts2使用OGNL进行类型转换。提供基本和常用对象的转换器。
验证
Struts1.x支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。
Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性
Action执行控制
Struts1.x支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。
六、结论
前面已经简要介绍了Struts2的起源,并详细对比了Struts2和Struts1.x的差异,读者应该对Struts2的基础有所了解了——包括高层的框架概念和基础的请求流程,并理解Struts1.x和Struts2两者之间在Action方面的差别,Struts2加强了对拦截器与IoC的支持,而在Struts1.x中,这些特性是很难想象的。
同时,读者应该明白:Struts2是WebWork的升级,而不是Struts 1.x的升级。虽然Struts 2提供了与Struts1.x的兼容,但已经不是Struts1.x的升级。对于已有Struts1.x开发经验的开发者而言,Struts1.x的开发经验对于Struts2并没有太大的帮助;相反,对于已经有WebWork开发经验的开发者而言,WebWork的开发经验对Struts2的开发将有很好的借鉴意义。
分享到:
相关推荐
Struts1和Struts2是两个非常著名的Java Web框架,它们在设计模式、可测试性、输入处理和表现层等方面存在显著的区别。 首先,Action类的设计有所不同。在Struts1中,Action类需要继承一个抽象基类,这限制了Action...
Struts1和Struts2是两个非常著名的Java Web框架,它们在处理MVC(Model-View-Controller)架构方面有着显著的区别。以下是关于这两个框架在关键特性上的对比: 1. **Action类**: - **Struts1**:要求Action类继承...
### Struts1与Struts2的主要区别 #### 1. Action类的设计差异 - **Struts1**: 在Struts1框架中,Action类必须继承自一个抽象类`org.apache.struts.action.Action`。这种方式可能导致的问题是代码灵活性较低,尤其...
综上所述,尽管Struts1和Struts2都属于MVC架构的Web开发框架,但它们在设计理念和技术实现上有显著差异。Struts2在灵活性、可扩展性和易用性方面相对于Struts1有了很大的改进,这使得它成为许多现代Web应用开发的...
Struts1和Struts2是两个著名的MVC框架,它们都是Apache Struts项目的一部分,用于构建基于Java的Web应用程序。虽然两者在核心理念上相似,但在实现方式和设计上存在显著差异,这些差异体现在多个方面。 首先,让...
综上所述,Struts2相较于Struts1,在灵活性、可扩展性、易用性和性能方面都有显著提升,特别是在模型驱动、表达式语言、视图管理和拦截器机制等方面展现了明显的优势。然而,选择何种框架还需根据项目需求、团队熟悉...
Struts1和Struts2是两个非常著名的Java Web开发框架,它们都属于Apache软件基金会的Struts项目。Struts1是最早的版本,而Struts2是其后续的改进版,引入了许多新特性和性能优化。 Struts1的核心是ActionServlet,它...
总结起来,这个Struts2实例项目通过整合国际化、类型转换和Struts2标签,构建了一个完整的用户管理系统,展示了如何在实际开发中高效地处理Web请求,实现业务逻辑,并提供多语言支持。这样的练习有助于提升开发者对...
Struts1和Struts2是两个非常著名的Java Web应用程序框架,它们都是基于Model-View-Controller(MVC)设计模式的。Struts1是Apache软件基金会的早期项目,旨在简化Web应用开发,通过分离业务逻辑和表现层。然而,随着...
### Struts2与Struts1的主要区别 #### Struts2架构设计与实现方式 - **Struts2**在设计上采用了更加灵活的方式,每个请求都对应一个实例化的Action对象,而不是像**Struts1**那样在整个请求周期内共享同一个Action...
Struts 2整合Struts 1,允许开发者利用Struts 1已有的投资,同时享受Struts 2带来的优势,如增强的类型安全和更强大的拦截器机制。 在《Struts 2权威指南--基于WebWork核心的MVC开发》这本书中,作者李纲深入浅出地...
### Struts1与Struts2框架的深度比较 #### 引言 自2001年Struts第一个版本发布以来,Struts凭借其强大的MVC(Model-View-Controller)模型设计模式,迅速成为了Web应用开发领域的重要工具之一。随着时间的发展和...
### Struts1与Struts2本质区别 #### 1. 在Action实现类方面的对比 - **Struts 1**:要求Action类必须继承一个抽象基类`Action`,这种设计方式意味着开发者必须按照预设的结构来编写代码,灵活性较低。这种通过抽象...
Struts1和Struts2是两个非常著名的Java Web框架,它们在处理MVC(Model-View-Controller)架构方面有着不同的实现方式。以下是对这两个框架的详细比较: 1. **Action类** - **Struts1**:在Struts1中,Action类...
虽然从Struts1迁移到Struts2需要一定的努力和时间投入,但从长远来看,这种转变是值得的。Struts2不仅能够提高应用程序的性能和可维护性,还能够更好地适应不断变化的技术环境。通过上述步骤和注意事项,可以确保...
### Struts2 与 Struts1 的核心区别 #### 一、架构设计及Action实现...综上所述,Struts2相比Struts1在架构设计、线程安全性、输入处理、表单验证等方面进行了大量的改进和优化,使得其更适合现代Web应用的开发需求。
1. **配置JSON支持**:要在Struts2中启用JSON响应,首先需要在`struts.xml`配置文件中添加JSON插件的相关配置。这通常涉及到注册一个全局结果类型`json`,例如: ```xml <constant name="struts.action.extension" ...
综上所述,Struts2.x相对于Struts1.x在多个方面进行了改进和优化,包括但不限于Action的实现方式、工作流程、数据绑定、视图技术以及验证机制,这些改进共同构成了Struts2.x相较于Struts1.x的优势,使其成为现代Web...