1. 简 介
SpringMVC 中的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
拦截器是 AOP 思想的具体应用,开发者可自定义一些拦截器来实现特定的功能。
过滤器
- Servlet 规范中的一部分,任何 java web 工程都可以使用
- 在 url-pattern 中配置了 /* 之后,可以对所有要访问的资源进行拦截
拦截器
- 拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能使用
- 拦截器只会拦截控制器层面的方法,如果访问的是 jsp/html/css/image/js 等资源,是不会拦截的
2. 自定义拦截器
自定义拦截器,必须实现 HandlerInterceptor 接口。
2.1 新建 module
下面新建一个 module ,名称为 03-interceptor-springmvc,实际操作一下。
这里,使用 idea 建立 module 的过程省略,下面给出主要的文件内容。
web.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置DispatcherServlet:这个是SpringMVC的核心,请求分发器,也是前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatcherServlet要绑定Spring的配置文件,通过初始化参数方式指定配置文件的位置,进行关联-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<!--启动级别为1,数字越小,启动越早-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被SpringMVC拦截-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置SpringMVC的乱码过滤-->
<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>
</web-app>
index.jsp 文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
Hello,SpringMVC
</body>
</html>
applicationContext.xml 文件
<?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
https://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">
<!--自动扫描包-->
<context:component-scan base-package="com.yuhuofei.controller"/>
<!--让SpringMVC不处理静态资源-->
<mvc:default-servlet-handler/>
<!--支持注解驱动-->
<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="/**"/>
<bean class="com.yuhuofei.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
TestController.java 文件
package com.yuhuofei.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description
* @ClassName TestController
* @Author yuhuofei
* @Date 2022/7/17 19:55
* @Version 1.0
*/
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/getData")
public String getData(){
String test = "SpringMVC-Interceptor";
return test;
}
}
MyInterceptor.java 文件
package com.yuhuofei.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description
* @ClassName MyInterceptor
* @Author yuhuofei
* @Date 2022/7/17 20:29
* @Version 1.0
*/
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//return true:当前拦截器放行,执行后续的程序
//return false:当前拦截器拦截,不执行后续的程序
System.out.println("=======处理前=======");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("=======处理后=======");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("=======清理=======");
}
}
父 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springmvc-study</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>01-hello-springmvc</module>
<module>02-annotation-springmvc</module>
<module>03-interceptor-springmvc</module>
</modules>
<dependencies>
<!--添加springmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
<!--添加junit依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--添加Servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--添加JSP依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!--添加JSTL表达式的依赖-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
子 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springmvc-study</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>03-interceptor-springmvc</artifactId>
</project>
整个 module 的目录结构如下图所示
2.2 测试
配置好 tomcat 服务器,然后启动,测试一下。
测试的结果,如下图所示
3. 拦截器应用示例
下面以登录一个网站的简单示例,演示拦截器的使用。
3.1 代码编写
在上面的 module 中,增加以下文件(有的是新增,有的是修改,这里全部内容给出)
新建一个 LoginInterceptor.java 类,作为拦截器
package com.yuhuofei.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @Description
* @ClassName LoginInterceptor
* @Author yuhuofei
* @Date 2022/7/17 21:41
* @Version 1.0
*/
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
//允许登录接口放行
if (request.getRequestURI().contains("login")){
return true;
}
//session中的用户信息不为空,登录成功
if (session.getAttribute("userInfo") != null){
return true;
}
//不符合条件的,认为没有登录,返回登录首页
request.getRequestDispatcher("/index.jsp").forward(request,response);
return false;
}
}
新建一个 LoginController.java 文件,编写登录的接口逻辑
package com.yuhuofei.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
/**
* @Description
* @ClassName LoginController
* @Author yuhuofei
* @Date 2022/7/17 21:42
* @Version 1.0
*/
@Controller
@RequestMapping("/user")
public class LoginController {
@PostMapping("/login")
public String login(HttpSession session, String userName, String passWord, Model model) {
session.setAttribute("userInfo", userName);
model.addAttribute("userName", userName);
return "main";
}
@GetMapping("/main")
public String main(Model model, HttpSession session) {
String userName = (String) session.getAttribute("userInfo");
model.addAttribute("userName", userName);
return "main";
}
@GetMapping("/loginOut")
public String loginOut(HttpSession session) {
session.removeAttribute("userInfo");
return "redirect:/index.jsp";
}
}
新建一个 main.jsp 文件,作为登录成功后的展示页
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功页面</title>
</head>
<body>
<h1>${userName} 用户,恭喜您,登录成功!</h1>
<p>
这个页面可以自定义展示的内容
</p>
<p>
<a href="${pageContext.request.contextPath}/user/loginOut">退出登录</a>
</p>
</body>
</html>
更改 index.jsp 的内容,如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录首页</title>
</head>
<body>
<h1>
登录首页
</h1>
<form action="${pageContext.request.contextPath}/user/login" method="post">
用户名: <input type="text" name="userName"/>
密码:<input type="text" name="passWord"/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
applicationContext.xml 文件中,新增拦截器的配置
<?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
https://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">
<!--自动扫描包-->
<context:component-scan base-package="com.yuhuofei.controller"/>
<!--让SpringMVC不处理静态资源-->
<mvc:default-servlet-handler/>
<!--支持注解驱动-->
<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="/**"/>
<bean class="com.yuhuofei.interceptor.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!--包括这个请求下面的所有请求-->
<mvc:mapping path="/user/**"/>
<bean class="com.yuhuofei.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
3.2 测试
启动 tomcat 服务器,然后测试流程,测试结果如下图所示
- 登录首页
- 登录成功页
- 退出登录