共计 10287 个字符,预计需要花费 26 分钟才能阅读完成。
1、拦截器概述
1.1、什么是拦截器
SpringMVC 的处理器拦截器,类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
1.2、过滤器与拦截器
** 过滤器:** 是一个程序,它与 Servlet 或 JSP 页面运行在服务器上。它是随你的 web 应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的 web 应用停止或重新部署的时候才销毁。
过滤器是 Servlet 中的内容,任何 javaweb 项目都可以使用。
拦截器:
使用 AOP 的思想,用于在某个方法或字段被访问之前或之后,进行拦截。加入某些操作。比如日志,权限,安全等。
拦截器是 springMVC 框架中的内容,只有在 springMVC 框架中才能使用。
1.3、过滤器与拦截器区别
拦截器是核心动态代理的,过滤器是核心函数回调。
拦截器不依赖于 Servlet 容器,过滤器依赖于 Servlet 容器。
拦截器可以在方法前后,异常前后等调用,过滤器只能在请求前和请求后各调用一次。
拦截器利用依赖注入,因此在 Spring 框架程序中,优先过滤器。
1.4、拦截器的执行流程
1.5、应用场景
权限检查:进入处理器检测是否登录,如果没有直接返回到登录页面。
日志记录:记录请求信息的日志。
性能监控:程序执行中有的时间断执行较慢,可以通过拦截器记录处理器开始时间,在记录处理完后结束时间,得到我们的最终操作时间。
2、自定义拦截器
2.1、HandlerInterceptor 接口
要想自定义拦截器,我们要去实现 HandlerInterceptor 接口。这样我们所定义 的类就是拦截器类。
2.2、实现拦截
2.2.1、编写拦截器
HIDemo.java
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HIDemo implements HandlerInterceptor {@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");
}
}
2.2.2、拦截器配置
springmvc.xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.tyschool.smvc003.utils.HIDemo"></bean>
</mvc:interceptor>
</mvc:interceptors>
2.2.3、编写控制器
HIController.java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller("hIController")
public class HIController {@RequestMapping("/testHI")
public String testHI(){System.out.println("这是 controller");
return "success";
}
}
2.2.4、编写页面
index1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="testHI">HIDemo</a>
</body>
</html>
2.2.5、测试
http://localhost:8080/smvc003/index1.jsp
3、拦截器详解
3.1、拦截器放行
放行是指:如果有下一个拦截器就执行下一个,如果拦截器处于拦截器链(拦截器里的拦截器)的最后一个,则执行控制器中的方法。
3.2、拦截器中的方法
3.2.1、preHandle()
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("执行到了这里:preHandle");
return true;
}
作用:
如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回 true。
如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
调用:
按拦截器定义的顺序调用,只要配置都会调用
3.2.2、postHandle()
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("执行到了这里:postHandle");
}
作用:
在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求 request 进行处理。
调用:
按拦截器定义逆序调用,在拦截器链内所有拦截器返回成功调用
3.2.3、afterCompletion()
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("执行到了这里:afterCompletion");
}
作用:
在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
调用:
按拦截器定义逆序调用,只有 preHandle 返回 true 才调用。
3.3、拦截器配置说明
<mvc:interceptors>
<mvc:interceptor>
<!-- 用于指定拦截的 url-->
<mvc:mapping path="/**"/>
<!-- 用于指定排队的 url-->
<mvc:exclude-mapping path="">
<bean class="com.tyschool.smvc003.utils.HIDemo"></bean>
</mvc:interceptor>
</mvc:interceptors>
4、多拦截器
4.1、编写拦截器
编写拦截器 2
HIDemo1.java
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HIDemo1 implements HandlerInterceptor {@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("拦截器 2:执行到了这里:preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("拦截器 2:执行到了这里:postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("拦截器 2:执行到了这里:afterCompletion");
}
}
4.2、多拦截器配置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.tyschool.smvc003.utils.HIDemo"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.tyschool.smvc003.utils.HIDemo1"></bean>
</mvc:interceptor>
</mvc:interceptors>
4.3、测试
http://localhost:8080/smvc003/index1.jsp
执行结果:
执行到了这里:preHandle
拦截器 2:执行到了这里:preHandle
这是 controller
拦截器 2:执行到了这里:postHandle
执行到了这里:postHandle
拦截器 2:执行到了这里:afterCompletion
执行到了这里:afterCompletion
4.4、多拦截器执行流程图
4.5、修改拦截器
修改拦截器 2
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("拦截器 2:执行到了这里:preHandle");
return false;
}
4.6、测试
http://localhost:8080/smvc003/index1.jsp
执行结果:
执行到了这里:preHandle
拦截器 2:执行到了这里:preHandle
执行到了这里:afterCompletion
5、用户登录验证(准备)
5.1、需求
输入项目的 url 地址后,验证是否已经登录,登录后就直接放行,如果没有登录转到登录页面。
5.2、项目分析
一个登录页面,一个登录成功页面
一个控制器完成登录,并将正确的用户数据保存到 session 中,如果输入错误,在次回到登录页面。
输入 url 地址,通过拦截器判断,用户是否登录(如果登录,放行进入到登录成功页面;如果未登录,跳转到登录页面。)。
5.3、创建一个新的项目
通过 maven 创建项目 smvc004
5.3.1、导入 jar 包
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
5.3.2、配置 web.xml
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>Archetype Created Web Application</display-name>
<!-- 配置 SpringMVC 核心, 前置控制器 DispatcherServlet -->
<servlet>
<servlet-name>SpringMVCDispathcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,用来读取 springmvc.xml 文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc.xml</param-value>
</init-param>
<!-- 配置 servlet 的对象的创建时间点:应用加载时创建。取值只能是非 0 正整数,表示启动顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 前置控制器,映射所有地址 -->
<servlet-mapping>
<servlet-name>SpringMVCDispathcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
5.3.3、配置 springmvc.xml
springmvc.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<mvc:annotation-driven />
<!-- 配置扫描器,扫描注解 -->
<context:component-scan base-package="com.tyschool.smvc002"></context:component-scan>
<!-- 配置视图解析器,配置前缀和后缀 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
6、用户登录验证(开发)
6.1、编写页面
/pages/login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title> 登录界面 </title>
</head>
<body>
<form action="${pageContext.request.contextPath}/loginIn" method="post">
username:<input type="text" name="username"/>
password:<input type="password" name="password"/>
<input type="submit" 登录 />
</form>
</body>
</html>
/pages/login-win.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title> 登录成功 </title>
</head>
<body>
${sessionScope.get("username")}: 欢迎到来天易 IT 学院!<a href="${pageContext.request.contextPath}/loginOut"> 退出 </a><br/>
</body>
</html>
6.2、编写控制器
LoginController.java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller("loginController")
public class LoginController {// 进入登录页面
@RequestMapping("/loginIndex")
public String loginIndex(){return "login";
}
// 用户名:admin 密码为:admin, 登录成功
@RequestMapping("/loginIn")
public String loginIn(HttpSession session, String username, String password){// 判断用户名密码是否为:admin
if("admin".equals(username)&&"admin".equals(password)){// 登录成功,存入 session
session.setAttribute("username",username);
return "login-win";
}else{return "redirect:/pages/login.jsp";
}
}
// 用户退出
@RequestMapping("/loginOut")
public String loginOut(HttpSession session){session.invalidate();
return "login";
}
}
6.3、编写拦截器
LoginInterceptor.java
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 LoginInterceptor implements HandlerInterceptor {@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取 session 对象
HttpSession session=request.getSession();
// 判断 session 中是否存在用户,存在继续判断,不存在往下走
if(session.getAttribute("username")!=null){// 存在用户时,如果是退出链接,继续执行 Controller 里的内容
if(request.getRequestURI().indexOf("loginOut")>=0){return true;
}else {// 如果不是退出链接,跳转到登录成功页面
request.getRequestDispatcher("/pages/login-win.jsp").forward(request, response);
return true;
}
}
// 如果链接是 loginIndex 和 loginIn, 继续执行他的 Controller
if(request.getRequestURI().indexOf("loginIndex")>=0||request.getRequestURI().indexOf("loginIn")>=0){return true;
}else {// 如果不是跳转到登录页面
request.getRequestDispatcher("/pages/login.jsp").forward(request, response);
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 {}}
6.4、配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.tyschool.smvc004.utils.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
6.5、测试
http://localhost:8080/smvc003/loginIndex