SpringMVC拦截器

702 阅读5分钟

​ 在正常的业务逻辑中,加入一些常见的条件判断;条件判断的本身和业务逻辑是完全分离没有任何关系的; AOP思想的实现;

业务场景:

  1. 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PVPage View)等。
  2. 权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
  3. 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
  4. 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取LocaleTheme信息等,只要是多个处理器都需要的即可使用拦截器实现。
  5. OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session

1、SpringMVC拦截器介绍

​ SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理,可以用来做日志记录,通过它来进行权限验证,或者是来判断用户是否登陆。

​ SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式,第一种方式是要定义的Interceptor类要实现了Spring 的**HandlerInterceptor** 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类**HandlerInterceptorAdapter** ;第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。

2、SpringMVC拦截器使用步骤

2.1 定义一个拦截器的类

让这个类去继承其他类/或者是实现和拦截器有关的接口;重写里面的方法,这里实现HandlerInterceptor接口:

public class MyInterceptor01 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
  • preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false;

  • postHandle():这个方法**在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,**在该方法中对用户请求request进行处理;

  • afterCompletion():这个方法**在 DispatcherServlet 完全处理完请求后被调用,**可以在该方法中进行一些资源清理的操作;

2.2 配置拦截器:

在springMVC的配置文件中配置拦截器,创建拦截器类的bean ,同时要配置在哪些地方使用拦截器(Controller)

<!--配置拦截器-->
<!--你用那个拦截器,拦截了哪些资源?-->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 所有都会拦截,/**包含子目录 -->
        <mvc:mapping path="/**"/>
        <!-- 此时访问api/下的url则不会被拦截 -->
        <mvc:exclude-mapping path="/api/*"/>
        <bean class="com.singerw.interceptor.MyInterceptor01"></bean>
    </mvc:interceptor>
</mvc:interceptors>

3、多个拦截器执行顺序

<!--配置拦截器-->
<!--你用那个拦截器,拦截了哪些资源?-->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 所有都会拦截,/**包含子目录 -->
        <mvc:mapping path="/**"/>
        <!-- 此时访问api/的url则不会被拦截 -->
        <mvc:exclude-mapping path="/api/*"/>
        <bean class="com.singerw.interceptor.MyInterceptor01"></bean>
    </mvc:interceptor>
</mvc:interceptors>

<!--配置拦截器-->
<!--你用那个拦截器,拦截了哪些资源?-->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 所有都会拦截,/**包含子目录 -->
        <mvc:mapping path="/**"/>
        <!-- 此时访问api/的url则不会被拦截 -->
        <mvc:exclude-mapping path="/api/*"/>
        <bean class="com.singerw.interceptor.MyInterceptor02"></bean>
    </mvc:interceptor>
</mvc:interceptors>

4、拦截用户是否登录验证模拟

4.1 管理员后端请求拦截器:

关于管理员后端的所有请求都拦截,例如:/admin/getuser

【示例】AdminInterceptor

/**
 * @Author: CodeSleep
 * @Date: 2021/8/23 15:55
 * @Description: //TODO 管理员后端请求拦截器
 */
public class AdminInterceptor implements HandlerInterceptor {
    public AdminInterceptor() {
        System.out.println("AdminInterceptor()构造方法");
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("****************AdminInterceptor_preHandle*****************");
        //判断Httpsession中是否存在用户登录的信息,前提是用户登录业务的时候用户信息做了存储处理。
        if (request.getSession().getAttribute("user") == null) {
            System.out.println("用户未登录,请返回登录!");
            response.sendRedirect(request.getContextPath() + "/back/login.html");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("****************AdminInterceptor_postHandle*****************");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("****************AdminInterceptor_afterCompletion*****************");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

【示例】springmvc-servlet.xml拦截器配置:

springmvc-servlet.xml中配置管理员后端请求拦截器,ArticleController中关于admin的所有请求都会拦截,给*.htmlcomponent下的CSS,JS等开路,不再拦截,采用com.singerw.interceptor.AdminInterceptor拦截器。拦截后返回登录界面,登录后可正常访问。

【配置拦截器1示例】

<!--配置拦截器1-->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- ArticleController中关于admin的所有请求都会拦截,/**包含子目录 -->
        <mvc:mapping path="/admin/**"/>

        <!--给*.html和component下的CSS,JS等开路,不再拦截-->
        <mvc:exclude-mapping path="/back/*.html"/>
        <mvc:exclude-mapping path="/component/**"/>

        <!--AdminInterceptor拦截器-->
        <bean class="com.singerw.interceptor.AdminInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

4.2 管理员后端静态资源拦截器

关于管理员后端的所有静态资源都拦截,例如:/back/index.html等等。

【示例】BackInterceptor

/**
 * @Author: CodeSleep
 * @Date: 2021/8/23 15:55
 * @Description: //TODO 管理员后端访问拦截器
 */
public class BackInterceptor implements HandlerInterceptor {

    public BackInterceptor() {
        System.out.println("BackInterceptor()构造方法");
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("****************BackInterceptor_preHandle*****************");
        //判断Httpsession中是否存在用户登录的信息,前提是用户登录业务的时候用户信息做了存储处理。
        if (request.getSession().getAttribute("user") == null) {
            System.out.println("用户未登录,请返回登录!");
            response.sendRedirect(request.getContextPath() + "/back/login.html");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("****************BackInterceptor_preHandle*****************");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("****************BackInterceptor_preHandle*****************");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

【示例】springmvc-servlet.xml拦截器配置:

springmvc-servlet.xml中配置管理员后端静态资源拦截器,管理员后端资源关于back路径下的所有访问都会拦截,给*.htmlcomponent下的CSS,JS等开路,不再拦截,采用com.singerw.interceptor.BackInterceptor拦截器,拦截后返回登录界面,登录后可正常访问。

【配置拦截器2示例】

<!--配置拦截器2-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--管理员后端资源关于back路径下的所有访问都会拦截,/**包含子目录-->
        <mvc:mapping path="/back/**"/>

        <!--给*.html和component下的CSS,JS等开路,不再拦截-->
        <mvc:exclude-mapping path="/back/login.html"/>
        <mvc:exclude-mapping path="/component/**"/>

        <!--BackInterceptor拦截器-->
        <bean class="com.singerw.interceptor.BackInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

5、SpringMVC拦截器和Servlet中的Filter区别

SpringMVC拦截器:InterceptorServlet:FilterRemark
org.springframework.web.servlet.HandlerInterceptor接口Javax.servlet.Filter接口接口定义位置
基于java的反射机制,是AOP思想的实现属于javaEE标准,基于函数回调,也是AOP思想的实现
Spring配置文件Web.xml中或者@WebFilter配置
拦截器拦截到具体方法的前后,整个请求的生命周期Filter只能在servlet前后起作用,依赖于servlet
Spring的aop实现 和支持Servlet规范和支持
可以使用spring的任何资源,业务对象,数据源访问等,只需要给拦截器注入对象就可以Filter不能直接使用 spring资源
被spring容器调用,容器实例化被tomcat调用Spring拦截器执行晚于过滤器