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
代码语言:javascript复制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
代码语言:javascript复制<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.tyschool.smvc003.utils.HIDemo"></bean>
</mvc:interceptor>
</mvc:interceptors>
2.2.3、编写控制器
HIController.java
代码语言:javascript复制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
代码语言:javascript复制<%@ 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()
代码语言:javascript复制public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行到了这里:preHandle");
return true;
}
作用:
如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回 true。
如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
调用:
按拦截器定义的顺序调用,只要配置都会调用
3.2.2、postHandle()
代码语言:javascript复制public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("执行到了这里:postHandle");
}
作用:
在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求 request 进行处理。
调用:
按拦截器定义逆序调用,在拦截器链内所有拦截器返回成功调用
3.2.3、afterCompletion()
代码语言:javascript复制public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("执行到了这里:afterCompletion");
}
作用:
在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
调用:
按拦截器定义逆序调用,只有 preHandle 返回 true 才调用。
3.3、拦截器配置说明
代码语言:javascript复制<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
代码语言:javascript复制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、多拦截器配置
代码语言:javascript复制<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
执行结果:
代码语言:javascript复制执行到了这里:preHandle
拦截器2:执行到了这里:preHandle
这是controller
拦截器2:执行到了这里:postHandle
执行到了这里:postHandle
拦截器2:执行到了这里:afterCompletion
执行到了这里:afterCompletion
4.4、多拦截器执行流程图
4.5、修改拦截器
修改拦截器2
代码语言:javascript复制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
执行结果:
代码语言:javascript复制执行到了这里:preHandle
拦截器2:执行到了这里:preHandle
执行到了这里:afterCompletion
5、用户登录验证(准备)
5.1、需求
输入项目的url地址后,验证是否已经登录,登录后就直接放行,如果没有登录转到登录页面。
5.2、项目分析
一个登录页面,一个登录成功页面
一个控制器完成登录,并将正确的用户数据保存到session中,如果输入错误,在次回到登录页面。
输入url地址,通过拦截器判断,用户是否登录(如果登录,放行进入到登录成功页面;如果未登录,跳转到登录页面。)。
5.3、创建一个新的项目
通过maven创建项目smvc004
5.3.1、导入jar包
pom.xml
代码语言:javascript复制 <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
代码语言:javascript复制<?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
代码语言:javascript复制<?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
代码语言:javascript复制<%@ 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
代码语言:javascript复制<%@ 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
代码语言:javascript复制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
代码语言:javascript复制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、配置拦截器
代码语言:javascript复制<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