PlayJava SpringMVC与Struts2杂谈

先做一个简单对比:

1. SpringMVC的入口是Servlet,核心是DispatcherServlet,Struts2是Filter,核心是FilterDispatcher

2. SpringMVC应当会比Struts2稍微快些。SpringMVC是基于方法设计,Struts2是基于类,即每发一次请求都会实例一个Action

3. SpringMVC使用相对简洁一些,支持JSR303,处理ajax请求更加方便,开发效率应当会比Struts2要高些

4. Struts2的OGNL表达式使页面的开发效率相比SpringMVC更高些

Struts2的核心控制器是FilterDispatcher,在Struts1系列版本中,所有的请求是通过一个Servlet(ActionServlet)来管理控制的,在Struts2系列版本中是经过一个Filter来处理请求的。Struts2选择Filter而不是Servlet来设计核心控制器,是为了实现AOP思想。

Struts1.x的配置:

<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    ......
</servlet>

Struts2.x的配置:

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>*.action</url-pattern>
</filter-mapping>

在具体的框架实现中,包含了3个部分:核心控制器FilterDispatcher、控制器和业务逻辑组件。Struts2框架提供了核心控制器FilterDispatcher,而开发人员需要实现控制器和业务逻辑组件。核心控制器作为一个Filter运行在Web应用中,负责拦截所有的用户请求。当请求到达时,该Filter会过滤这些请求,如果请求以action结尾,则该请求将被转入Struts2框架处理。Struts2框架获得了*.action请求后,将根据*.action请求的前面部分决定调用哪个业务逻辑组件。例如对于login.action请求,Struts2调用名为login的Action来处理该请求。Struts2应用中的Action都被定义在struts.xml文件中,在该文件中定义Action时,需定义该Action的name属性和class属性,其中name属性决定了该Action处理哪个请求,而class属性决定了该Action的实现类。Struts2用于处理请求的Action实例是Action代理,因为实现的Action类并没有与Servlet API耦合,显然无法直接处理请求,因此这个Action类仅仅是Action代理的代理目标,拦截器负责将HttpServletRequest中的请求参数解析出来,传入到Action中,并回调Action的execute方法来处理请求。这个处理过程是典型的AOP处理方式。

Struts2是以WebWork为核心的。WebWork是由OpenSymphony组织开发的,致力于组件化和代码重用的J2EE Web框架。目前的WebWork2.x前身是Rickard Oberg开发的WebWork,现在WebWork已经被拆分成了Xwork1和WebWork2两个项目。该框架主要是实现了Interceptor接口的拦截器,代码部分在intercept方法中实现。在intercept方法中,可以直接返回一个Result字符串,这样整个执行直接“短路”,这时Action的execute方法也不会执行(一般很少会这么用)。所以一般都会在这个方法里调用参数对象invocation的invoke方法,并返回这个方法执行的结果。这样会持续执行后面的拦截器方法以及Action的execute方法等。

WebWork的三个关键部分

1.Actions。一般一个Action代表一次请求或调用。在WebWork中,Action类需要实现Action接口,或者直接继承基础类ActionSupport。然后实现默认的execute方法,并返回一个在配置文件中定义的Result(也就是一个自定义的字符串)。此外,Action也可以只是一个POJO,不用实现任何接口也不用继承任何类。Action是一次请求的控制器,同时也充当数据模型的角色,因此建议不要将业务逻辑放在Action中。

2.Results。Result是一个结果页面的定义,用来指示Action执行之后,如何显示执行的结果。Result Type表示如何以及用哪种视图类型展现结果。通过Result Type,WebWork可以方便的支持多种视图技术,而且这些视图技术可以互相切换,Action部分不需做任何改动。

3.Interceptors。WebWork的拦截器,当截获到Action请求时,在Action执行之前或之后调用拦截器方法。这样,可以用插拔的方式将功能注入到Action中。WebWork框架的很多功能都是以拦截器的形式提供出来。例如:参数组装,验证,国际化,文件上传等。

WebWork的基于OGNL的强大的数据存、取方式,解耦的拦截器功能,无侵入的架构设计等特点让Web编程变得更加的自然、简单、灵活、高效。

SpringMVC中的Interceptor拦截器的主要作用是拦截请求并进行相应的处理,其他的作用比如通过它来进行权限验证,或者是判断用户是否登录,日志记录,或者限制时间点访问等。在SpringMVC中定义一个拦截器主要有两种方式,第一种方式是定义的Interceptor类直接实现HandlerInterceptor接口,或者继承实现了HandlerInterceptor接口的类,比如Spring提供的实现了HandlerInterceptor接口的抽象类HandlerInterceptorAdapter;第二种方式是实现WebRequestInterceptor接口,或者继承实现了WebRequestInterceptor接口的类。

HandlerInterceptor接口中定义了三个方法,通过这三个方法来对用户的请求进行拦截处理:

1. preHandle方法。该方法在请求处理之前调用。SpringMVC中的Interceptor是链式调用的,在一个应用中或者一个请求中可以同时存在多个Interceptor。每个Interceptor的调用会依据声明顺序依次执行,并且最先执行的都是preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔类型,为false时表示请求结束,后续的Interceptor和Controller都不会执行;为true时就会继续调用下一个Interceptor的preHandle方法,如果已经是最后一个Interceptor的时候就调用当前请求的Controller。

2. postHandle方法。此方法在Controller的方法调用之后执行,但是会在DispatcherServlet进行视图渲染之前调用,所以可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。postHandle方法被调用的方向跟preHandle是相反的,先声明的Interceptor的postHandle方法反而会后执行,这和Struts2里面的Interceptor的执行过程有点类似。Struts2里面的Interceptor的执行过程也是链式的,只是在Struts2里面需要手动调用ActionInvocation的invoke方法来触发对下一个Interceptor或者是Action的调用,然后每一个Interceptor中在invoke方法执行之前的内容都是按照声明顺序执行的,而invoke方法之后的内容就是反向的。

3. afterCompletion方法。该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。主要作用是用于进行资源清理工作,拦截系统日志以便记录日志的相关参数,检测方法的执行。

文章参考:

Filter is used only in web applications whereas interceptor can be used with web as well as enterprise applications. Life cycle methods of both, also differs. The Interceptor stack fires on requests in a configured package while filters only apply to their mapped URL‘s. 
Example: 
A Servlet Filter is used in the web layer only, you can‘t use it outside of a web context. Interceptors can be used anywhere. 
The interceptor stack fires on every request. Filters only apply to the urls for which they are defined. 
Filters can be used when you want to modify any request or response parameters like headers. For example you would like to add a response header "Powered By Surya" to each generated response. Instead of adding this header in each resource method you would use a response filter to add this header. 
There are filters on the server side and the client side. 
In Summary: 
Filters: 
(1)Based on Servlet Specification 
(2)Executes on the pattern matches on the request. 
(3)Not configurable method calls. 
Interceptors: 
(1)Based on Struts2. 
(2)Executes for all the request qualifies for a front controller( A Servlet filter ).And can be configured to execute additional interceptor for a particular action execution. 
(3)Methods in the Interceptors can be configured whether to execute or not by means of excludeMethods or includeMethods.

我进行了带理解的翻译:

过滤器仅在Web应用中使用,而拦截器可以与Web以及企业级应用一起使用。两者中(关于对象或者Bean)的生命周期的(具体)方法(实现)也不同。拦截器栈会处理一个已配置好的(项目)包中的(每一个)请求,而过滤器仅处理那些为它映射好的URL。

例如:

一个Servlet过滤器仅在Web层中使用,而不能在Web(配置)环境之外使用它。拦截器则可以在任何地方使用。
拦截器栈会处理每一个请求。过滤器仅处理已经为其定义好(即映射好)的URL。
如果想要修改任何请求对象或者响应对象的参数(如请求头/响应头)时,可以使用过滤器。举个例子,假如你想要在每个生成的响应对象的响应头中添加”Powered By Surya“,不用在每个资源方法中添加此响应头,使用一个响应过滤器就可以很方便的实现了。
服务器端和客户端都有过滤器。

综上所述:

过滤器:
(1)基于Servlet规范
(2)根据配置的规则来对相应的请求进行处理
(3)调用没有配置的方法

拦截器:
(1)基于Struts2
(2)所有符合前置控制器(一个Servlet过滤器)条件的请求都会执行。并且可以将一些附加的、特殊需求的拦截逻辑配置到里面去
(3)可以通过excludeMethods(排除某些方法)或includeMethods(包含某些方法)来配置拦截器中的方法是否执行

相关推荐