目录
在实际项目中,拦截器的使用是非常普遍的,例如在购物网站中通过拦截器可以拦截未登录的用户,禁止其购买商品,或者使用它来验证已登录用户是否有相应的操作权限等。在Struts 2框架中,拦截器是其重要的组成部分,而Spring MVC中也提供了拦截器功能,通过配置即可对请求进行拦截处理。本章将针对Spring MVC中拦截器的使用进行详细讲解。
一、拦截器概述
1、什么是拦截器?
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
2、拦截器的定义
要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
以实现HandlerInterceptor接口方式为例,自定义拦截器类的代码如下:
3、 拦截器的配置
要使自定义的拦截器类生效,还需要在Spring MVC的配置文件中进行配置。
二、拦截器的执行流程
在运行程序时,拦截器的执行是有一定顺序的,该顺序与配置文件中所定义的拦截器的顺序相关。
1、单个拦截器的执行流程
如果在项目中只定义了一个拦截器,那么该拦截器在程序中的执行流程如图所示。
(1)在Eclipse 中,创建一个名为chapter15的 Web项目,将Spring MVC程序运行所需JAR包复制到项目的lib目录中,并发布到类路径下。
(2)在 web.xml 中,配置Spring MVC的前端过滤器和初始化加载配置文件等信息。
(3)在src目录下,创建一个com.itheima.controller包,并在包中创建控制器类HelloController,
package com.itheima .controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@controller
public class HelloController{
/**
*页面跳转
*/
@RequestMapping("/hello")
public String Hello(){
System.out.println ("Hello!");
return "success";
}
}
( 4 )在src目录下,创建一个 com.itheima.interceptor包,并在包中创建拦截器类CustomInterceptor。该类需要实现 HandlerInterceptor 接口,并且在实现方法中需要编写输出语句来输出信息
package com.itheima.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework,web.servlet. Mode1AndView;
/**
*实现了HandlerInterceptor接口的自定义拦截器类
*/
public class CustomInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println ("CustomInterceptor. . .preHandle");
//对拦截的请求进行放行处理
return true;
}
@Override
public void postHandle(HttpservletReqguest request,
HttpServletResponse response, Object handler,ModelAndView modelAndview) throws Exception{
System.out.println("CustomInterceptor. . .postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler,
Exception ex) throws Exception {
System.out.println("CustomInterceptor. . .afterCompletion");
}
}
(5)在src目录下,创建并配置Spring MVC的配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"><!--扫描注册controller -->
<context:component-scan base-package="com.itheima.controller"></context:component-scan>
<!-- 视图解析器 -->
<bean 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直接定义在<mvc:interceptors>下面的拦截器将拦截所有请求-->
<bean class="com.itheima.interceptor.LoginInterceptor"></bean>
</mvc:interceptors>
</beans>
(6)在WEB-INF目录下,创建一个 jsp文件夹,并在该文件夹中创建一个页面文件success.jsp,然后在页面文件的<body>元素内编写任意显示信息,如“ok”。
(7)将项目发布到Tomcat 服务器并启动,在浏览器中访问地址http:/localhost:8080/chapter15/hello,程序正确执行后,浏览器会跳转到success.,jsp 页面,此时控制台的输出结果如图所示。
从图可以看出,程序先执行了拦截器类中的preHandle()方法,然后执行了控制器中的 Hello()方法,最后分别执行了拦截器类中的 postHandle()方法和 afterCompletion()方法。这与上文所描述的单个拦截器的执行顺序是一致的。
2、多个拦截器的执行流程
多个拦截器(假设有两个拦截器Interceptor1和Interceptor2,并且在配置文件中, Interceptor1拦截器配置在前),在程序中的执行流程如下图所示:
为了验证上述描述,下面通过修改单个拦截器的案例来演示多个拦截器的执行,具体步骤如下。
(1)在com.itheima.interceptor包中,创建两个拦截器类Interceptor1和 Interceptor2,这两个拦截器类均实现了HandlerInterceptor接口,并重写其中的方法,
package com.itheima.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework,web.servlet. Mode1AndView;
/**
*以实现接口的方式定义拦截器
*/
public class Interceptor1 implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println ("Interceptor1. . .preHandle");
//对拦截的请求进行放行处理
return true;
}
@Override
public void postHandle(HttpservletReqguest request,
HttpServletResponse response, Object handler,ModelAndView modelAndview) throws Exception{
System.out.println("Interceptor1. . .postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler,
Exception ex) throws Exception {
System.out.println("Interceptor1. . .afterCompletion");
}
}
package com.itheima.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework,web.servlet. Mode1AndView;
/**
*以实现接口的方式定义拦截器
*/
public class Interceptor2 implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println ("Interceptor2. . .preHandle");
//对拦截的请求进行放行处理
return true;
}
@Override
public void postHandle(HttpservletReqguest request,
HttpServletResponse response, Object handler,ModelAndView modelAndview) throws Exception{
System.out.println("Interceptor2. . .postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler,
Exception ex) throws Exception {
System.out.println("Interceptor2. . .afterCompletion");
}
}
(2)在配置文件springmvc-config.xml 中的<mvc:interceptors>元素内配置上面所定义的两个拦截器,配置代码如下所示。
<!-- 配置多个拦截器 -->
<mvc:interceptors>
<!--配置第一个拦截器 -->
<mvc:interceptor>
<!--配置拦截器作用的路径-->
<mvc:mapping path="/**"/>
<!--定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截的-->
<bean class="com.itheima.interceptor.Interceptor1"></bean>
</mvc:interceptor>
<!--配置第2个拦截器 -->
<mvc:interceptor>
<!--配置拦截器作用的路径-->
<mvc:mapping path="/hello"/>
<!--对应的拦截器的类 -->
<bean class="com.itheima.interceptor.Interceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
在上述拦截器的配置代码中,第一个拦截器会作用于所有路径下的请求,而第二个拦截器会作用于以“/hello”结尾的请求。
为了不影响程序的输出结果,可将上一小节案例中所配置的 CustomInterceptor 的拦截器配置注释掉。
( 3)发布项目到-Tomcat 服务器并启动,在浏览器中访问地址 http:/localhost.8080/chapter15/hello,控制台中输出的信息如图所示。
从图可以看出,程序先执行了前两个拦截器类中的preHandle()方法,这两个方法的执行顺序与配置文件中定义的顺序相同;然后执行了控制器类中的 Hello()方法;最后执行了两个拦截器类中的postHandle()方法和afterCompletion()方法,且这两个方法的执行顺序与配置文件中所定义的拦截器顺序相反。
对拦截器类Interceptor1或者Interceptor2中标红信息,修改为return false,会有不同的结果