Struts1的技术缺陷:
(1) 支持的表现层技术单一
Struts仅仅支持JSP作为表现层的技术,不提供其他的表现层的技术,比如说Vlocity,FreeMarker等技术的融合.这一点严重制约了Struts1框架的使用,对于目前很多java EE应用而言,并不一定非得使用JSP作为前台的表现层的技术.
虽然Struts1处理完用户的请求之后,并没有直接转到特定的视图资源,而是返回一个ActionForward对象,可以理解ActionForward是一个逻辑视图名,在Struts-config.xml文件中定义了逻辑视图名和试图资源名之间的对应关系,当ActionServlet得到处理器返回的ActionForward对象之后,可以根据逻辑视图和视图资源之间的对应关系,将试图资源呈现给用户.
从上面的设计来看,不得不佩服Struts1的设计者的高度解耦的设计:控制器并没有直接执行转发请求,而仅仅返回一个逻辑视图名---实际的转发在配置文件中进行管理.但因为Struts1框架出现的年代太早了,那时候还没有出现FreeMarker,Velocity等技术,因而没有考虑到与这些视图技术的整合.
“Struts1 已经通过配置文件管理逻辑视图名和实际视图之间的对应关系,只是没有做到让逻辑视图名可以支持更多的试图技术”
虽然Struts1 有非常优秀的设计,但是由于历史原因,它没有提供与更多视图技术的整合,着严重限制了Struts1的使用.
(2) 与ServletAPI严重耦合,难于测试
因为Struts1框架是在Model2基础上发展起来的,因此它完全是基于ServletAPI的,所以在Struts 1的业务逻辑控制器内,充满了大量的Servlet API.
看看下面的Action片段:
//业务逻辑控制器必须继承Struts1提供的Action类
public class LoginAction extends Action{
//处理用户请求的execute方法
public ActionForward execute(ActionMapping mapping,ActionForm form,
HttpServletRequest,request,HttpServletResponse,response
)throws AuctionException{
LoginForm loginForm=(LoginForm)form;
if(“scott”.equals(loginForm.getUsername)&&
”tiger”.equals(loginForm.getPassword)){
return mapping.findForward(“success”);
}else{
return mapping.findForward(“fail”);
}
}
}
当我们需要测试上面Action类的execute方法的时候,该方法有四个参数:ActionMapping,ActionForm,HttpServletResponse,HttpServletRequest,初始化这四个参数比较困难,尤其是HttpServletRequest和HttpServletResponse这两个参数,通常这两个参数的初始化是由web容器负责实例化的.
(3) 代码严重依赖于Struts1 Api 属于侵入式设计
正如上面代码片段中看到的,Struts1的Action类必须继承Struts1的Action基类,实现处理方法的时候,又包含了大量的Struts1 API:如ActionForm,ActonMapping和ActionForward类,这种侵入式设计的最大弱点在于,一旦系统需要重构的时候,这些Action类将完全没有价值,成为一堆废品.
可见,Struts1的Action类这种侵入式的设计导致了较低的代码复用.
WebWork的优点:
(1) Action无需与Servlet API耦合,更加容易测试
相对于Struts1框架中的Action出现了大量的Servlet API而言,WebWork的Action更像是一个普通的java对象,该控制器代码中没有耦合任何的ServletAPI,看下面的WebWork的Action示例:
public class LoginAction implements Action{
private final static String LOGINFIAL=”loginfail”;
private String password;
private String username;
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password=password;
}
public String getUsername(){
return username;
}
public void SetUsername(String username){
this.username=username;
}
public String execute()throws Exception{
if(“yeeku”.equalsIgnoreCase(getUsername)&&“password”.equals(getPassword()))
{
ActionContext ctx=ActionContext.getContext();
Map session=ctx.getSession();
session.put(“username”,getUsername());
return SUCCESS;
}
else{
return LOGINFAIL;
}
}
}
在上面的Action代码中,我们看不到任何的ServletAPI,当系统需要处理两个请求参数:username和password的时候,Action并没有通过HttpServletRequest对象来得到请求参数,而是直接调用访问该Action的username和password成员属性—这两个属性由Action拦截器负责初始化,以用户请求参数为其赋值.
即使Action中需要访问HttpSession对象,依然没有在代码中直接出现HttpSessionAPI,而是以一个Map对象代表了HTTPSession对象.
当我们将WebWork的Action和Struts1的Action进行了比较的时候,不难发现Struts1的Action是在是太臃肿了,确实不如WebWork的Action那么优雅.
如果需要测试上面的Action代码,测试用例的书写将非常的容易,因为execute方法中没有包含任何的ServletAPI,甚至没有WebWork的API.
(2) Action无需与WebWork耦合,代码重复率高
在上面Action代码中,不难发现WebWork中的Action其实就是一个POJO,该Action仅仅是实现了WebWork的Action接口,包含一个execute方法.
Struts1中的Action类需要继承Struts1的Action类,我们知道实现一个接口和继承一个类是两个完全不同的概念:实现一个接口对类的污染要小的多,该类也可以实现其他的任意的接口,还可以继承一个父类,但是一旦已经集成了一个父类,则意味着不能够继承其他的父类.
初次之外,Struts1中Action也包含了一个execute方法,但是该方法需要四个参数,类型分别为ActionMapping,ActionForm,HttpServletRequest,HttpServletResponse,一个包含了这四个参数的方法,除了在Struts1框架下面有用之外,很难想象该代码还有什么复用价值,但是WebWork的execute方法就不同,该方法没有出现任何的ServletAPI,也没有出现任何的WebWork的API.这个方法在任何环境下都用重用的价值.
得益于WebWork灵巧的设计,WebWork中的Action无需与任何ServletAPI,WebWorkAPI耦合,从而具有更好的代码重用率.
(3) 支持更多的表现技术,有更好的适应性.
WebWork对多种表现技术:JSP,Velocity和FreeMarker等都有很好的支持,从而给开发更多的选择.提供了更好的适应性.