白话Spring(中级篇)---拦截器(下)

来源:互联网 发布:青少年编程网 编辑:程序博客网 时间:2024/05/19 01:32

[一知半解,就是给自己挖坑]

上文我们介绍了Spring中过滤器的基本用法,本文我们来介绍多个拦截器的执行情况,另外一种拦截器的实现方式,以及拦截器与java过滤器的区别。特别的,在本文中,我们将不在演示具体的拦截的实例,请读者们参照上文的实现以及配置方式自行实现。

--------------------------------------------------------------------------------------------------------------------------------------------------------

一。多个拦截器的执行情况。

1.在上文中,我们创建了HelloWorldInterceptor.java文件,在此基础之上,我们再创建一个HelloWorldInterceptor2.java文件,文件与上面的内容基本保持一致,唯一需要修改的是,在输出语句中标识出当前的拦截器名称即可。如下:

 System.out.println("preHandle2");  
2.在上文的配置文件中,我们演示了如何针对单一的controller进行拦截,现在,我们来介绍如何在全局范围内使用拦截器。具体配置如下:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:jdbc="http://www.springframework.org/schema/jdbc"    xmlns:jee="http://www.springframework.org/schema/jee"    xmlns:tx="http://www.springframework.org/schema/tx"    xmlns:jpa="http://www.springframework.org/schema/data/jpa"    xmlns:util="http://www.springframework.org/schema/util"    xmlns:mvc="http://www.springframework.org/schema/mvc"    xsi:schemaLocation="            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd            http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">    <context:component-scan base-package="interceptor" />    <!-- 视图处理 -->    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <property name="prefix" value="/WEB-INF/jsp/"></property>        <property name="suffix" value=".jsp"></property>    </bean>   <mvc:interceptors>      <bean class="interceptor.HelloWorldInterceptor"></bean>   <bean class="interceptor.HelloWorldInterceptor2"></bean>   </mvc:interceptors></beans>

</pre><p></p><pre>
3.保存当前修改,再次启动服务器观察控制台输出即可。

4.多个拦截器的执行顺序。【注,下图来自imooc.com】

-------------------------------------------------------------------------------------------------------------------------------------------------------

二,拦截器的第二种实现---WebRequestInterceptor 接口

1.WebRequestInterceptor 中也定义了三个方法,我们也是通过这三个方法来实现拦截的。这三个方法都传递了同一个参数WebRequest ,那么这个WebRequest 是什么呢?这个WebRequest 是Spring 定义的一个接口,它里面的方法定义都基本跟HttpServletRequest 一样,在WebRequestInterceptor 中对WebRequest 进行的所有操作都将同步到HttpServletRequest 中,然后在当前请求中一直传递。

示例代码如下:

import org.springframework.ui.ModelMap;  import org.springframework.web.context.request.WebRequest;  import org.springframework.web.context.request.WebRequestInterceptor;    public class AllInterceptor implements WebRequestInterceptor {            /**      * 在请求处理之前执行,该方法主要是用于准备资源数据的,然后可以把它们当做请求属性放到WebRequest中      */      @Override      public void preHandle(WebRequest request) throws Exception {          // TODO Auto-generated method stub          System.out.println("AllInterceptor...............................");          request.setAttribute("request", WebRequest.SCOPE_REQUEST);//这个是放到request范围内的,所以只能在当前请求中的request中获取到          request.setAttribute("session", WebRequest.SCOPE_SESSION);//这个是放到session范围内的,如果环境允许的话它只能在局部的隔离的会话中访问,否则就是在普通的当前会话中可以访问          request.setAttribute("globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//如果环境允许的话,它能在全局共享的会话中访问,否则就是在普通的当前会话中访问      }        /**      * 该方法将在Controller执行之后,返回视图之前执行,ModelMap表示请求Controller处理之后返回的Model对象,所以可以在      * 这个方法中修改ModelMap的属性,从而达到改变返回的模型的效果。      */      @Override      public void postHandle(WebRequest request, ModelMap map) throws Exception {          // TODO Auto-generated method stub          for (String key:map.keySet())              System.out.println(key + "-------------------------");;          map.put("name3", "value3");          map.put("name1", "name1");      }        /**      * 该方法将在整个请求完成之后,也就是说在视图渲染之后进行调用,主要用于进行一些资源的释放      */      @Override      public void afterCompletion(WebRequest request, Exception exception)      throws Exception {          // TODO Auto-generated method stub          System.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");      }  }  
特别注意:与第一种方式实现不同的是,这里的三个返回值类型都是void。即我们不能通过此拦截器进行请求拦截。因此,我们推荐使用功能较为完整的第一种方式。读者可按照自身的需求来选择即可。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

三,拦截器与过滤器的区别

拦截器的常见应用场景:日志记录,权限检查,性能监控,通用行为等AOP常用功能。

过滤器的常见应用场景:统一编码,禁止动态页面缓存,静态资源缓存,自动登陆等。

A.Filter开发示例

1.在上文的工程基础之上,创建MyFilter.java,具体内容如下:

package filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;/*** @ClassName:MyFilter* @Description:filter的三种典型应用:*                     1、可以在filter中根据条件决定是否调用chain.doFilter(request, response)方法,*                        即是否让目标资源执行*                     2、在让目标资源执行之前,可以对request\response作预处理,再让目标资源执行*                     3、在目标资源执行之后,可以捕获目标资源的执行结果,从而实现一些特殊的功能*/ public class MyFilter implements Filter {    public void init(FilterConfig filterConfig) throws ServletException {        System.out.println("----过滤器初始化----");    }    public void doFilter(ServletRequest request, ServletResponse response,            FilterChain chain) throws IOException, ServletException {                //对request和response进行一些预处理        request.setCharacterEncoding("UTF-8");        response.setCharacterEncoding("UTF-8");        response.setContentType("text/html;charset=UTF-8");                System.out.println("MyFilter执行前!!!");</span>        chain.doFilter(request, response);  //让目标资源执行,放行        System.out.println("MyFilter执行后!!!");</span>    }    public void destroy() {        System.out.println("----过滤器销毁----");    }}
2.修改web.xml配置文件如下:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID" version="2.5"><display-name>Shiro11</display-name><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>*</url-pattern></filter-mapping><filter><filter-name>myFilter</filter-name><filter-class>filter.MyFilter</filter-class></filter><filter-mapping><filter-name>myFilter</filter-name><url-pattern>*</url-pattern></filter-mapping><servlet><servlet-name>springMvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring-mvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springMvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>  
3.在实际开发中,我们可能会使用到过个filter。这些Filter组合起来称之为一个Filter链。
  web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。

示例代码:

public void doFilter(ServletRequest request, ServletResponse response,                  FilterChain chain) throws IOException, ServletException {              System.out.println("Demo1过滤前");              System.out.println(filterConfig.getInitParameter("param1"));              chain.doFilter(request, response);//放行。让其走到下个链或目标资源中              System.out.println("Demo1过滤后");          }    
4.filter的生命周期

创建:

Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。【请注意观察控制台输出】
销毁:

Web容器调用destroy方法销毁Filter。destroy方法在Filter的生命周期中仅执行一次。在destroy方法中,可以释放过滤器使用的资源。

FilterConfig接口:

       用户在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过filterConfig对象的方法,就可获得:
  String getFilterName():得到filter的名称。
  String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
  Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
  public ServletContext getServletContext():返回Servlet上下文对象的引用。

示例代码:

package me.gacl.web.filter;import java.io.IOException;import java.util.Enumeration;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;public class MyFilter02 implements Filter {    /* 过滤器初始化     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)     */    @Override    public void init(FilterConfig filterConfig) throws ServletException {        System.out.println("----过滤器初始化----");        /**         *  <filter>                  <filter-name>MyFilter2</filter-name>                  <filter-class>filter.MyFilter2</filter-class>                  <!--配置MyFilter2过滤器的初始化参数--></span>                  <init-param>                      <description>配置MyFilter2过滤器的初始化参数</description>                      <param-name>name</param-name>                      <param-value>gacl</param-value>                  </init-param>                  <init-param>                      <description>配置MyFilter2过滤器的初始化参数</description>                      <param-name>like</param-name>                      <param-value>java</param-value>                  </init-param>            </filter>                         <filter-mapping>                  <filter-name>MyFilter2</filter-name>                  <!--“/*”表示拦截所有的请求 -->                  <url-pattern>/*</url-pattern>             </filter-mapping>         */        //得到过滤器的名字        String filterName = filterConfig.getFilterName();        //得到在web.xml文件中配置的初始化参数        String initParam1 = filterConfig.getInitParameter("name");        String initParam2 = filterConfig.getInitParameter("like");        //返回过滤器的所有初始化参数的名字的枚举集合。        Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();                System.out.println(filterName);        System.out.println(initParam1);        System.out.println(initParam2);        while (initParameterNames.hasMoreElements()) {            String paramName = (String) initParameterNames.nextElement();            System.out.println(paramName);        }    }    @Override    public void doFilter(ServletRequest request, ServletResponse response,            FilterChain chain) throws IOException, ServletException {        System.out.println("MyFilter2执行前!!!");        chain.doFilter(request, response);  //让目标资源执行,放行        System.out.println("MyFilter2执行后!!!");    }    @Override    public void destroy() {        System.out.println("----过滤器销毁----");    }}

配置web.xml示例:

<filter>          <description>MyFilter过滤器</description>          <filter-name>MyFilter</filter-name>          <filter-class>MyFilter2</filter-class>          <!--配置MyFilter2过滤器的初始化参数-->          <init-param>              <description>配置MyFilter2过滤器的初始化参数</description>              <param-name>name</param-name>              <param-value>gacl</param-value>          </init-param>          <init-param>              <description>配置MyFilter2过滤器的初始化参数</description>              <param-name>like</param-name>              <param-value>java</param-value>          </init-param></filter> <!--映射过滤器-->   <filter-mapping>       <filter-name>MyFilter02</filter-name>       <!--“/*”表示拦截所有的请求 -->       <url-pattern>/*</url-pattern>   </filter-mapping>

  • <description>用于添加描述信息,该元素的内容可为空,<description>可以不配置。
  • <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
  • <filter-class>元素用于指定过滤器的完整的限定类名。
  • <init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。如果过滤器不需要指定初始化参数,那么<init-param>元素可以不配置。
  • <filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
  • <filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
  • <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
  • <servlet-name>指定过滤器所拦截的Servlet名称。
  • <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。如下:

 <filter-mapping>     <filter-name>testFilter</filter-name>    <url-pattern>/index.jsp</url-pattern>    <dispatcher>REQUEST</dispatcher>    <dispatcher>FORWARD</dispatcher></filter-mapping>

<dispatcher> 子元素可以设置的值及其意义:

REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。

INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。

ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

拦截器与过滤器的执行顺序:【注:此图摘自其他博文,详情见参考资料】


拦截器与过滤器的对比:

①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

特别备注:

Filter的执行顺序是按照web.xml中的配置顺序执行的。


-------------------------------------------------------------------------------------------------------------------------------------

至此,白话Spring(中级篇)---拦截器(下)结束


参考资料:

http://www.cnblogs.com/xdp-gacl/p/3948353.html

http://blog.csdn.net/chenleixing/article/details/44573495

http://www.cnblogs.com/dreamroute/p/4198087.html?utm_source=tuicool

http://haohaoxuexi.iteye.com/blog/1750680


0 0
原创粉丝点击