`

Struts1与Struts2的区别

阅读更多

Struts2继承了Struts与WebWork的血脉,吸取了两者的精华而成。

不同点主要包括以下几个方面:

Action类

在Struts中都是使用抽象类编程而不是接口,因此它要求开发的Action类继承一个抽象基类,如DispatchAction等。

Struts2刚基于接口编程,我们的Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现常用的接口。更强大的是,在Struts2中Action接口不是必需的,任何有execute()函数的POJO对象都可以用做Strut2的Action类来使用。

线程模式

Struts的Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts Action所能做的事,并且要在开发时特别小心,Action资源必须是线程安全的或同步的

Struts2的Action对象为每一个请求产生一个实例,因此没有线程安全问题。

Servlet依赖

Struts的Action依赖于Servlet API, 当一个Action被调用时,HttpServletRequest和HttpServletResponse被传递给执行的方法,例如:

Public ActionForward execute(ActionMapping mapping, ActionForm form,HttpServletRequest request,HttpServletResponse response){

     

}

Struts2的Action不依赖容器,允许Action脱离容器单独测试。如果需要,Struts2的Action仍然可以访问初始的request和response。例如下面的这个类MyAction.java,它可以通过ActionContext对象取得Session值,也可以通过ServletActionContext对象取得request值。

Public class MyAction{

Protected Object getSession(String key){

    Return ActionContext.getContext().getSession(key);

}

Protected HttpServletRequest getRequest(){

    Return (String)ServletActionContext.getRequest();

}

}

可测试性

测试Strtus Action的一个主要问题是,execute()方法暴露了Servlet API,这使得测试要依赖于容器。虽然有第三方的软件Struts TestCase能够使用模拟对象来进行测试,但显然会让我们的测试变得更加复杂。

Struts2 Action的类是POJO类,因此可以直接编写测试类来测试Action类,只需要在测试类中为Action注入属性即可。

捕获输入

Struts使用ActionForm对象捕获用户输入,所有的ActionForm必须继承一个基类ActionForm。因为其他的JavaBean不能用做ActionForm,开发者经常创建多余的类捕获输入。动态表单可以作为创建传统ActionForm的选择,但是,开发者可能是在重新创建已经存在的JavaBean,仍然会导致有冗余的JavaBean。

Struts2直接使用Action属性作为输入属性,消除了对第2个输入对象的需求。输入属性可能是有自己子属性的rich对象类型。Action属性能够通过Web页面上的taglibs访问。同时,Struts2也支持ActionForm模式。

表达式语言

Struts整合了JSTL,这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。

Struts2可以使用JSTL,但是也支持一个形影相随强大和灵活的表达式语言OGNL(Object Graph Notation Language

绑定值到页面 

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

Struts2使用ValueStack策略允许通过一系列名称相同,但类型不同的属性重用页面(View)。

类型转换

Struts的ActionForm属性通常都是String类型,并使用Commons-Beanutils进行类型转换。每个类提供一个转换器,对每一个实例来说是不可配置的。

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

数据校验

Struts的ActionForm属性的validate()方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。

Struts2支持通过validate()方法和XWork校验框架来进行校验,XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性。

Action执行的控制

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

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

以上描述的都是内部实现机制的不同,从开发者的角度来看,其实主要是Action类不同。

在Struts2中共包含两个配置文件:

Struts.properties:定义了Struts2运行的属性配置,通过修改这些属性可以控制Struts2的行为。

Struts.xml:供开发者添加用户请求的映射列表,通过该列表可以将用户的请求与Action类对应起来。(还可以在struts.xml文件中引用别的XML文件,如user.xml,可以在struts.xml文件中使用<include>来引用)

Struts2的请求是由FilterDispatcher来进行拦截的,当接收到用户的请求时,它会在struts.xml中查找对应的请求映射配置,得到使用哪些拦截器Interceptors、 Action类和返回结果Results的信息,然后依次做如下的操作:

1, 请求通过一系列的拦截器:Interceptors是Struts2中的一种过滤机制,它基于AOP的思想进行设计,通常可以用于日志记录、权限限制等;拦截器和拦截器组可以按照不同级别进行组合配置来处理请求。它们为请求提供各种预处理和切面处理的应用功能,这和Struts的使用Jakarta Commons Chain构件的RequestProcessor类很类似。

2, 调用Action:产生一个新的Action对象实例,并提供请求所调用的处理逻辑的方法,并调用Model层执行业务逻辑的操作,然后返回映射配置中指定的Result页面。

3, 业务处理:业务逻辑通常由JavaBean或EJB组件来实现,以实现文件、数据库、通信等的相关操作。

4, 调用相应的Result:通过匹配处理Action方法之后的返回值获取相应Result类,生成并调用它的实例。处理Result可能产生的结果之一就是对UI模板(但并非只有一个)进行渲染,来产生HTML。如果是这种情况的话,模板中的Struts2 tags可以直接从Action中获取要被渲染的值。

5, 响应被返回给用户:最后一步是将控制权交还给Servlet引擎。最常见的结果是把渲染后的HTML返回给用户,但返回的也可能是指定的HTTP头或者进行HTTP重写向。你应该已经注意到Struts2和Struts的差别了,最明显的就是Struts2是一个pull-MVC架构。这是什么意思呢?从开发者的角度看,就是说需要显示给用户的数据可以直接从Action中获取,也就是说JSP页面可能直接访问Action中的数据了,而不像Struts那样必须把相应的Bean存到Page、Request、或者Session中才能获取。

Com.opensymphony.xwork2.Action是个接口,这个类来自于XWork,它的定义如下:

package com.opensymphony.xwork2;

public interface action{

public static final java.lang.String SUCCESS = success;

public static final java.lang.String NONE = none;

public static final java.lang.String ERROR = error;

public static final java.lang.String INPUT = input;

public static final java.lang.String LOGIN = login;

public abstract java.lang.String execute() throws java.lang.Exception;

}

Execute()方法是每个Action的入口方法

Struts.xml文件中,首先是Action的访问地址,它的访问地址由两个部分来决定,一个是package中的namespace定义,一个是action的name.

属性

必需

说明

Name

 是

供其它包引用的包名

Extends

继承自其它包并获得其全部行为

Namespace

参考正文的命名空间介绍

Abstract

声明包为抽象(包内不需要配置action)

Package元素只需要一个必须的属性:name。extends属性是可选的,它可以让当前包继承一个或者多个以前包——包括所有的拦截器,拦截器栈,以及action配置。只有namespace属性对我们的action的访问路径有影响的,它的默认值是“”,也就是空字符串,它还可以聚会为根目录,也就 是“/”,被称为Root Namespace,它对应着访问web应用根目录的情况。如果当前例子的配置文件的package 为:

重新发布项目后,访问路径将是:

http://localhost:8080/struts2hello/test/HelloWorld.action

接下来对访问路径有影响的,当然是Action 的 name 属性了,假设这样写

这时候的访问路径将会变成

http://localhost:8080/struts2hello/test/a.HelloWorld.action

不赞成在action的name属性中加符号如:“.,-主要是ajax支持会出问题。

Result:

<package name=default extends=struts-defaultnamespace=/test>

<action name=a.HelloWorld class=com.login.action.HelloWorld>

它相当于JSP编程当中的forward,因此,默认的type类型就是dispatcher

可以这样写

<result-types>

<result-type class=org.apache.struts2.dispatcher.ServletDispatcherResult default=true/>

</result-types>

Param元素可以省略掉。

还有一种结果类型,那就是重定向,它的写法是:

<result type=redirect-action>Menu</result>

类似于struts1中的GlobalFowards,struts2也支持将某些通用的Result定义成为全局的,即Global Results:

<result name=success type=dispatcher>

      <param name=location>/HelloWorld.jsp</param>

</result>

强烈建议能用EL表达式和JSTL表达式的时候就用它,而抛弃框架自带的那些非标准和容易变动的自定义标签库。这就是一直提倡的面向标准和尽量独立于框架编程的好处,可维护性和移植性是远远好于绑定某个特定标签库的,开发不能只看眼前,要尽量多考虑以后的扩展和维护。

· Struts2的国际化问题:

比如说在SRC的com.login.action包上右击新建一个文件名为package.properties,接着在打开的编辑器中键入以下内容

HelloWorld.message = Struts 2 is up and running

Package.properties是默认的,一般情况下得有,如果想在中文浏览器里面显示的话,就需要建立一个package_zh_CN.properties文件了,这个properties文件就像struts1那样差不多,在native2ascii里面先转换然后,再粘贴就OK。

Struts2对开发人员提供了很大的方便,既不用关心Struts2自身的接口和类,也不用关心方法到底应该如何命名,还可以将功能相似的方法合并到一个Action中,例如,将用户管理的功能都写到一个UserAction中, 里面带有login,logout,add,delete等处个模块的方法,而配置的时候只要按需要根据method参数即可配置出对应的5个访问地址,分别对应这些方法的调用。5个页面都对应着结果页面success.jsp。

映射还可以使用通配符的方式如:

<global-results>

<result name=error>/Error.jsp</result>

<result name=invalid.token>/Error.jsp</result>

</global-results>

当访问地址saveUser的时候,将会调用com.login.action.ActionMethod Action类的某个实例上的save方法,后面的method={1}这个定义的值{1}等于用户输入的*,即{1}=*

Struts2的验证机制

和struts1相比,这里的验证工作相当的简单,首先,是表单提交的action后台所对应的类必须继承自ActionSupport类,只有这样才能使用Struts2自带的验证机制。其次,必须使用Struts2里面的form标签来定义表单。再次,action定义中必须有名为input的result来指定表单的来源页面,便于出错后返回表单输入页面显示相关的信息,如:

<result name=input>/login.jsp</result>

最后是需要编写一份针对表单域的验证说明文件,并放在和action类相同的包下。配置文件有两种命名约定方式:

1. Action类名-validation.xml,不是Action名字_validation.xml,放在和Acton类相同的包下。例如在这里我们的验证文件名可以为:Login-validation.xml。

2. Action类名-Action别名-validation.xml,如Login-Login-validation.xml。

Interceprors(拦截器)

Struts2 中提供的很多特性都是通过拦截器实现的,例如异常处理,文件上传,生命周期回调与验证。拦截器从概念上来讲和Servlet过滤器或者JDK的Proxy类是一样的。它提供了一种对Action进行预处理和事后处理的功能。

依赖注入可以有多种不同的实现方式:

Spring框架——ActionAutowiringInterceptor拦截器

请求字符串和表单值——ParametersInterceptor拦截器

基于Servlet的对象——ServletConfigInterceptor拦截器

如果要想在Action中激活依赖注入功能,就必须要对Action进行配置。

<action name=*User class=com.login.action.ActionMethod method={1}

   <result>/hello.jsp</result>

</action>

在action配置 中就应该这样来写,把它配置上

<interceptors>

<interceptor name=autowiring class=

”…xwork2.spring.interceptor.ActionAutowiringInterceptor/>

</interceptors>

也可以直接放在package中

<default-interceptor-ref name=autowiring/>

由于Struts2的很多功能是基于拦截器完成的,所以一个Action对应有7,8个拦截器也并不稀奇,因此我们一般都用拦截器栈(interceptor stack)来管理拦截器。

OGNL的全称是Object Graph Navigational Language(对象图导航语言),提供了访问值栈中对象的统一方式。

值栈中的对象构成及基排列顺序

1. 临时对象——在执行过程中,临时对象被创建出来并放到了值栈中。

2. 模型对象——如果模型对象正在使用,那么会放在值栈中action的上面

3. Action对象——正在被执行的action

4. 固定名称的对象(Named Objects)——这些对象包括有#application,#session,#request,#attr和#parameters,以及相应的servlet作用域

在OGNL里面,可以用“.来遍历对象图(比如说,使用”person.address而不是“

getPerson().getAddress()),还有类型转换,方法调用,集合的操作与生成,集合间的映射,表达式运算和lambda表达式。

<!--EndFragment-->
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics