1、什么是拦截器?

SpringMVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。

  • 过滤器
    • servlet规范中的一部分,任何java web工程都可以使用
    • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
  • 拦截器
    • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
    • 拦截器只会拦截访问的控制器方法, 访问的是jsp/html/css/image/js是不会进行拦截的

2、创建并配置拦截器

1,创建类实现HandlerInterceptor接口

  1. public class MyInterceptor implements HandlerInterceptor {
  2. }

2,实现方法

     //在handler方法执行之前被调用    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        //返回值代表是否放行
        return true;
    }

     //目标方法执行之后
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

    //页面渲染以后
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
  • preHandle方法会在Handler方法执行之前执行,可以在其中进行一些前置的判断或者处理。
  • postHandle方法会在Handler方法执行之后执行,可对域中的数据修改,以及要跳转的页面
  • afterCompletion方法会在最后执行,此时已经没有办法对域中的数据进行修改,也没有办法修改要跳转的页面,我们在这方法中一般进行一些·资源的释放。

3,配置拦截器

 <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>     <!--配置拦截器需要连接的路径-->
            <!--配置拦截器不需要连接的路径-->
<!--            <mvc:exclude-mapping path="/"/>     -->
            <bean class="interceptor.MyInterceptor"/>   <!--配置拦截器对象注入bean-->
        </mvc:interceptor>
    </mvc:interceptors>

拦截路径:
/test/* 这种会拦截下面这种路径 /test/add /test/delete
但是拦截不了多级路径的情况,例如: /test/add/abc /test/add/sdd

/test/** 这种可以拦截多级,以及单级路径。

总而言之:/只能拦截单级路径,不能拦截子路径,而/*单级和多级路径都能拦截。

3、案例-登陆状态拦截器

1,需求
我们的接口需要做用户登录状态的校验。
如果用户没有登录,则跳转到登录页面;只有在登录的情况下才可以正常访问我们的接口。

2,分析

  • 怎么判断是否登录?
  • 很多接口都要去写判断的代码,难道要在每一个Handler中写判断逻辑?
  • 登陆接口是否应该进行拦截?
  • 静态资源是否要进行拦截?

3,代码实现
项目结构
Snipaste_2021-08-04_07-45-02.jpg

表单

<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/login" method="post">
    <input type="text" name="name"><br>
    <input type="password" name="password"><br>
    <input type="submit">
</form>
</body>
</html>

成功页面

<%--
  Created by IntelliJ IDEA.
  User: 27837
  Date: 2021/8/3
  Time: 10:33
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
登录成功
Session为${sessionScope.get("session")}
</body>
</html>

配置文件

<?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:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--自动扫描包:让指定包下的注解生效,由IOC容器统一管理-->
    <context:component-scan base-package="controller"/>
    <!--让SpringMVC不处理静态资源-->
    <mvc:default-servlet-handler/>
    <!--配置支持注解驱动-->
    <mvc:annotation-driven >
        <!--解决响应乱码-->
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="utf-8"/>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>     <!--配置拦截器需要连接的路径-->
            <!--配置拦截器不需要连接的路径-->
            <mvc:exclude-mapping path="/WEB-INF/jsp/**"/>
            <mvc:exclude-mapping path="/static/**"/>
            <mvc:exclude-mapping path="/login"/>
            <bean class="interceptor.MyInterceptor"/>   <!--配置拦截器对象注入bean-->
        </mvc:interceptor>
    </mvc:interceptors>

</beans>

控制器

package controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;

import javax.servlet.http.HttpServletRequest;

@Controller
@SessionAttributes("session")
public class TestController {

    @RequestMapping("/login")
    public String login(String name,String password, Model model){
        System.out.println(name);
        System.out.println(password);
        if (name.equals("张三")&&password.equals("123")){
            System.out.println("成功");
            model.addAttribute("session","OK");
            return "success";
        }
        else
            System.out.println("失败");
        return "forward:/static/form.html";
    }

    @RequestMapping("/success")
    public String success(){
        return "success";
    }
}

拦截器

package interceptor;


import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取Session
        HttpSession httpSession=request.getSession();
        String session = (String) httpSession.getAttribute("session");//强制转换
        //判断是否为空
        if (StringUtils.isEmpty(session)){
            //为空,未登录,重定向跳转到登录页面
            response.sendRedirect("/static/form.html");
        }
        else {
            //不为空,已登录
            return true;
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

     }
}

4、多个拦截器执行流程

拦截器的顺序与拦截器的名字无关,主要决定于配置文件中的顺序
13-拦截器 - 图2