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

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

上文我们介绍了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

时间: 2024-10-12 19:26:23

白话Spring(中级篇)---拦截器(下)的相关文章

Spring MVC中拦截器HandlerInterceptorAdapter中的preHandle方法

拦截器:顾名思义,就是对请求进行拦截,做一些预处理.后处理或返回处理的操作 Spring MVC中使用拦截器的方法,继承HandlerInterceptorAdapter类,并根据需求实现其中的preHandle方法(预处理).postHandle方法(返回处理),afterCompletion方法(后处理). public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object han

玩转spring MVC(七)----拦截器

继续在前边的基础上来学习spring MVC中拦截器的使用,下面通过一个例子来实现(完整项目在这里下载:http://download.csdn.net/detail/u012116457/8433425). 首先在项目中添加interceptor-servlet.xml来配置拦截器,当然,必须在web.xml中配置在tomcat启动时加载,如下: <!--1.配置spring分发器(是总的控制中心 被拦截的url会汇聚到该servlet) --> <servlet> <se

[转载] Spring MVC - 处理器拦截器

5.1.处理器拦截器简介 Spring Web MVC的处理器拦截器(如无特殊说明,下文所说的拦截器即处理器拦截器)类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.   5.1.1.常见应用场景 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等. 2.权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面: 3.性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间

spring mvc 多拦截器

上次大概写了个可以解决velocity 多视图的东西. 但是实际运用过程中有到处找了些资料看了下.这里 小计下: DispatcherServlet解析过程: 1.HandlerMapping 用于定位具体的Controller类我习惯叫pagehandle,我认为是模块分发modelfactory eg:implement 这个是比较标准,我继承过其他的HandlerMapping 但是实际自己使用还是从接口开始更好实现 public classSpringMvcExtendHandlerMa

spring登录验证拦截器和根据用户角色登录

大家都知道spring的用户登录拦截器,确实省去了程序员不少的精力,下面说说我在项目中使用的感受. 德安微信管理后台是管理多个微信帐号的平台,登录到平台的用户有三个角色,游客和微信帐号管理员.超级管理员.超级管理员负责建立新的微信帐号.建立新的微信帐号管理员:微信帐号管理员负责维护微信菜单:微信图文消息:处理微信事件,发布产品介绍专题等:游客的功能有浏览.下单.手机号绑定等.基于此我们分配了三个用户角色:ROLE_TRAVELER.ROLE_ADMIN.ROLE_SUPER分别对应游客.微信帐号

spring mvc +cookie+拦截器功能 实现系统自动登陆

先看看我遇到的问题: @ResponseBody @RequestMapping("/logout") public Json logout(HttpSession session,HttpServletRequest request,HttpServletResponse response) { Json j = new Json(); if (session != null) { // session.invalidate(); session.removeAttribute(&q

Spring mvc登录拦截器

自己实现的第一个Spring mvc登录拦截器 题目要求:拒绝未登录用户进入系统,只要发现用户未登录,则将用户请求转发到/login.do要求用户登录 实现步骤: 1.在spring的配置文件中添加登录拦截,如下: spring-web.xml <mvc:interceptors> <!-- 配置登陆拦截器 --> <mvc:interceptor> <mvc:mapping path="/**"/> //拦截所有请求 <mvc:e

Spring Boot整合拦截器

过滤器和监听器都属于Servlet 的api,还可以使用 Spring 提供的拦截器(HandlerInterceptor)进行改更精细的控制. 原文地址:https://www.cnblogs.com/natian-ws/p/10823072.html

spring boot 添加拦截器

构建一个spring boot项目. 添加拦截器需要添加一个configuration @Configuration @ComponentScan(basePackageClasses = Application.class, useDefaultFilters = true) public class ServletContextConfig extends WebMvcConfigurationSupport { 为了方便扫描位置,我们可以写一个接口或者入口类Application放置于最外

基于Spring MVC 实现拦截器

Spring MVC 拦截器 一,具体内容: 在所有的开发之中拦截器属于一个重要的组件,可以说几乎所有的项目都会提供的概念应用,不管是Spring MVC,还是Struts 2.x都是提供有拦截器的,利用拦截器可以实现更加方便的数据验证处理. 1,认识拦截器 所谓的拦截器指的是在用户和具体操作的Action之间做了一个屏障,以保证提交到提交到Action的数据是真实有效的数据: 如果要想实现拦截器的操作处理,那么必须掌握"org.springframework.web.servlet.Handl