文章目录
SpringMVC拦截器
1. 拦截器介绍
- SpringMVC提供的拦截器类似于Servlet-api中的过滤器
- 可以对进入控制器的
请求
进行拦截实现相关的预处理
- 可以对控制器的
响应
进行拦截实现相关的相关后处理
- 将拦截器按照一定的顺序联结成一条链,这条链称为
拦截器链
(InterceptorChain)。在访问被拦截的方法和字段时,拦截器就会按照其之前定义的顺序被调用- 拦截器是
AOP思想
的具体应用
1.1 拦截器实现的接口
拦截器实现HandlerInterceptor接口
HandlerInterceptor接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
- HandlerInterceptor中的三个方法:
方法名 | 说明 |
---|---|
preHandle() | 方法将在请求处理之前进行调用,如果返回true 就执行下一个拦截器,如果为false 就不执行下一个拦截器。 |
postHandle() | 在请求处理方法执行后才被调用,前提是preHandle()方法返回true。它会在DispatcherServlet进行视图返回渲染之前调用,所以我们可以在这个方法中对controller处理之后的ModelAndView对象进行操作。 |
afterCompletion() | 在整个请求结束后执行,做清理工作,前提是preHandle()返回值为true |
-
拦截器执行顺序
如果有多个拦截器,则在xml里配置在前的先执行,配置在后的后执行。
拦截器中方法执行顺序是:
preHandle()—>目标资源—->postHandle()——>afterCompletion()
1.2 拦截器与过滤器的区别
区别 | 过滤器Filter | 拦截器 |
---|---|---|
使用范围 | 是Servlet规范的一部分,所有的web项目 都可以使用 | 是springmvc框架自己的,只有使用 了springmvc框架 的工程才能用。 |
拦截范围 | 在url-pattern中配置了/*后,可以对所有要访问的资源进行拦截 | 只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会拦截的 |
配置文件 | web.xml | SpringMVC配置文件spring-servt.xml |
2. 自定义拦截器
①
创建拦截器
类实现HandlerInterceptor接口
②在springMVC配置文件配置拦截器
③测试拦截器的拦截效果
2.1 创建拦截器
创建一个拦截器,实现 HandlerInterceptor接口
2.2 配置拦截器
在spring-servlet.xml配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- /**可以拦截路径不管多少层 -->
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="com.xiaoqing.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
3. 拦截器控制用户授权访问案例
案例:模拟用户登录和注销功能,用户只能访问登录页面,登录成功才能访问欢迎页面,否则访问不了
(此案例没有密码验证功能,只需要提供用户名密码就可以登陆,主要验证未授权访问)
- 创建用户登录页面和欢迎页面,将页面放在
webapp/WEB-INF/jsp
中,这些才能实现通过控制器的方法访问而不是直接访问- 登陆页面提交表单的登陆信息。需要在
controller
中处理。拦截用户请求,判断用户是否登陆。如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面
流程图:
- 未配置拦截器前:
- 配置拦截器后
3.1 WEB-INF目录下资源的访问
- WEB-INF目录下的资源
浏览器不能直接访问
,需要访问controller方法
,由方法通过视图解析器
的解析才能访问WEB-INF下的资源 - 与前端控制器不同的是,在前端控制器配置那里,我们在web.xml里配置了拦截所有的客户端请求,统一交由前端控制器dispatcherServlet来处理,如果访问的是对应的controller方法,则交由controller方法处理,如果是静态资源,则交由tomcat默认的servlet来处理。
通过上面的图片可知webapp下面包括css,imgs等资源和WEB-INF目录。除了WEB-INF下面的资源,其他的都可以在浏览器输入特定的地址来访问。WEB-INF则必须由controller经视图解析器解析后来访问
。
3.2 创建首页面
在
webapp
下创建index.jsp
<%--
Created by IntelliJ IDEA.
User: c
Date: 2023/1/8
Time: 0:30
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/login.css">
<title>Document</title>
</head>
<body>
<form class="login">
<p>Index</p>
<p><a href="${pageContext.request.contextPath}/user/loginPage">登陆页面</a></p>
<p><a href="${pageContext.request.contextPath}/user/successPage">欢迎页面</a></li>
</form>
</body>
</html>
3.3 创建登录页面和欢迎页面
在
webapp/WEB-INF
下创建login.jsp
和success.jsp
WEB-INF下的jsp不能通过浏览器直接访问,需要通过controller方法访问
- login.jsp
<%--
Created by IntelliJ IDEA.
User: c
Date: 2023/1/8
Time: 0:16
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/login.css">
<title>Document</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/login" method="post" class="login">
<p>Login</p>
<input type="text" placeholder="用户名" name="username">
<input type="password" placeholder="密码" name="password">
<input type="submit" class="btn" value="登 录">
</form>
</body>
</html>
- success.jsp
<%--
Created by IntelliJ IDEA.
User: c
Date: 2023/1/8
Time: 0:24
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/login.css">
<title>Document</title>
</head>
<body>
<form class="login">
<p>Welcome</p>
<p>欢迎${username}!!!</p>
<h3><a href="${pageContext.request.contextPath}/user/logout">注销登陆</a></h3>
</form>
</body>
</html>
3.4 创建控制器类
创建
UserController,处理和响应用户请求
- UserController
@Controller
@RequestMapping("/user")
public class UserController {
//跳转到登陆页面
@RequestMapping("/loginPage")
public String loginPage(){
System.out.println("---------登陆页面");
return "login";
}
//跳转到欢迎页面
@RequestMapping("/successPage")
public String successPage(){
System.out.println("---------欢迎页面");
return "success";
}
//用户登陆
@RequestMapping("/login")
public String login(String username, String password, HttpSession session){
System.out.println("---------用户登陆");
System.out.println("username:" + username);
System.out.println("password:" + password);
//向session中传值
session.setAttribute("username",username);
return "success";
}
//用户注销
@RequestMapping("/logout")
public String logout(HttpSession session){
System.out.println("---------用户注销");
//设置session过期
session.invalidate();
return "login";
}
}
3.5 配置视图解析器
在
spring-servlet.xm
l配置视图解析器
<!--配置视图解析器器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
3.6 程序测试(未配置拦截器之前)
(1)首页面-登陆页面-提交登陆信息(tom 123456)-欢迎页面
(2)未退出浏览器-首页面-欢迎页面
(3)关闭浏览器-首页面-欢迎页面
测试结果:
未配置拦截器之前,未登录的用户可以访问到登陆成功才能访问到的页面
3.7 创建拦截器
创建一个拦截器,
拦截用户请求,判断用户是否已经登陆,确定是否放行
public class LoginInterceptor implements HandlerInterceptor {
//预处理
//在执行Controller方法之前来执行的
//用于用户认证校验、用户权限校验
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//得到请求的url
String url = request.getRequestURI();
//判断是否是公开地址
//实际开发中需要公开地址配置在配置文件中
if(url.contains("login")){
//如果是公开地址则放行
return true;
}
//判断用户身份在session中是否存在
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username");
//如果用户身份在session中存在放行
if(username != null){
return true;
}
//执行到这里拦截,跳转到登陆页面,用户进行身份认证
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
//如果返回false表示拦截不继续执行handler,如果返回true表示放行
return false;
}
//后处理
//在执行Controller方法之后返回modelAndView之前来执行
//如果需要向页面提供一些公用的数据或配置一些视图信息,使用此方法实现从modelAndView入手
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("---------postHandle");
}
//完成对页面的渲染之后执行此方法
//作系统统一异常处理,进行方法执行性能监控,在preHandle中设置一个时间点,
// 在afterCompletion设置一个时间,两个时间点的差就是执行时长
//实现系统统一日志记录
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
System.out.println("---------afterCompletion");
}
}
3.8 配置拦截器
在
spring-servlet.xml
配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- /**可以拦截路径不管多少层 -->
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="com.xiaoqing.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
3.9 程序测试(配置拦截器之后)
(1)首页面-登陆页面(提交登陆数据tom 123456)-欢迎页面
(2)未退出浏览器-首页面-欢迎页面
(3)注销用户-首页面-欢迎页面(跳转到登陆页面)
(4)退出浏览器-首页面-欢迎页面(跳转到登陆页面)
测试结果:
用户在已登陆的情况下可以访问到欢迎页面,如果未登陆、注销、退出浏览器不能访问到欢迎页面