拦截器
文章目录
- 拦截器
- 官方文档介绍
- 拦截器如何实现
- 拦截器的代码实现
- 登陆拦截器
- 鉴权拦截器
- 拦截器添加到拦截列表
- 业务逻辑处理Controller
- 流程顺序
- 模拟登陆拦截
- 配置登陆拦截器
- 添加登陆拦截器
- controller层
- HTML页面
官方文档介绍
所有实现都支持处理程序拦截器,当您要将特定功能应用于某些请求(例如,检查主体)时,这些拦截器非常有用。拦截器必须使用三种方法从包中实现,这些方法应提供足够的灵活性来执行各种预处理和后处理:HandlerMapping
HandlerInterceptor
org.springframework.web.servlet
-
preHandle(..)
:在运行实际处理程序之前, -
postHandle(..)
:运行处理程序后 -
afterCompletion(..)
:完成请求后
拦截器如何实现
实现一个自己的拦截器,需要实现HandlerInterceptor接口。接口内的三个核心方法如下:
- preHandle():该方法在业务处理器处理请求之前调用。主要用来进行一些前置初始化操作或者是对当前请求的预处理,也可以进行一些判断来决定请求是否要继续下去,该方法的返回值类型位boolean值,如果返回位false,就表示当前请求结束,如果返回为true,那么就会继续调用下一个Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。
- postHandle():这个方法在当前请求进行处理之后,也就是Controller方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView 对象进行操作。
- afterCompletion():在postHandle执行之后执行,发生异常也会执行。该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
拦截器的代码实现
登陆拦截器
public class LogInterceptor extends HandlerInterceptorAdapter {
//在执行Controller方法之前来执行的
//用于用户认证校验、用户权限校验
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
long startTime = System.currentTimeMillis();
System.out.println("\n-------- LogInterception.preHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("Start Time: " + System.currentTimeMillis());
request.setAttribute("startTime", startTime);
return true;
}
//在执行Controller方法之后返回modelAndView之前来执行
//如果需要向页面提供一些公用的数据或配置一些视图信息,使用此方法实现从modelAndView入手
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, //
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("\n-------- LogInterception.postHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
// You can add attributes in the modelAndView
// and use that in the view page
}
//完成对页面的渲染之后执行此方法
//作系统统一异常处理,进行方法执行性能监控,在preHandle中设置一个时间点,在afterCompletion设置一个时间,两个时间 点的差就是执行时长
//实现系统统一日志记录
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, //
Object handler, Exception ex) throws Exception {
System.out.println("\n-------- LogInterception.afterCompletion --- ");
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("End Time: " + endTime);
System.out.println("Time Taken: " + (endTime - startTime));
}
}
鉴权拦截器
public class AdminInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("\n-------- AdminInterceptor.preHandle --- ");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, //
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("\n-------- AdminInterceptor.postHandle --- ");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, //
Object handler, Exception ex) throws Exception {
System.out.println("\n-------- AdminInterceptor.afterCompletion --- ");
}
}
拦截器添加到拦截列表
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// LogInterceptor apply to all URLs.
// LogInterceptor应用于所有url。
registry.addInterceptor(new LogInterceptor());
// 这个拦截器应用于/admin/*这样的URL
// Exclude /admin/oldLogin
registry.addInterceptor(new AdminInterceptor())//
.addPathPatterns("/admin/*");
}
}
业务逻辑处理Controller
@Controller
public class InterceptorTestController {
@RequestMapping(value = { "/", "/test" })
public String test(Model model) {
System.out.println("\n-------- MainController --- ");
System.out.println(" ** You are in Controller ** ");
return "test";
}
@RequestMapping(value = { "/admin/login" })
public String login(Model model) {
System.out.println("\n-------- MainController.login --- ");
System.out.println(" ** You are in Controller ** ");
return "login";
}
}
流程顺序
模拟登陆拦截
配置登陆拦截器
public class LoginInterceptor2 implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法在控制器的处理请求方法调用之前执行");
String uri = request.getRequestURI();
//判断当前请求地址是否登录地址
if(uri.contains("login") || uri.contains("toLoginPage"))
{
//直接放行
return true;
}
else
{
//判断用户是否登录
if(request.getSession().getAttribute("userName")!=null)
//说明已经登录,放行
return true;
else
//没有登录,重定向到登录界面
response.sendRedirect(request.getContextPath() + "/toLoginPage");
}
//默认拦截
return false;
}
@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方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行");
}
}
添加登陆拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry)
{
registry.addViewController("/toIndexPage").setViewName("/index");
registry.addViewController("/").setViewName("/index");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor2())
.addPathPatterns("/**") //所有路径都被拦截
.excludePathPatterns( //添加不拦截路径
"/toLoginPage", //登录页面
"/login", //登录请求
"/**/*.html", //html静态资源
"/**/*.js", //js静态资源
"/**/*.css" //css静态资源
);
}
}
controller层
@Controller
public class UserController {
/**
* 登录页面
*/
@RequestMapping("/toLoginPage")
public String toLoginPage()
{
//跳转至登录页面
return "login.html";
}
/**
* 登录
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(Model model, HttpServletRequest request, String userName, String password)
{
//验证登录信息
if (userName.equals("xiaoqi") && password.equals("123456"))
{
//验证成功,记录Session信息
request.getSession().setAttribute("userName", userName);
//重定向到首页
return "redirect:toIndexPage";
}
else
{
model.addAttribute("errorMsg", "账号或密码错误!");
}
//跳转至登录页面
return toLoginPage();
}
/**
* 登出
*/
@RequestMapping(value = "/logout")
public String logout(HttpServletRequest request)
{
//销毁session对象
request.getSession().invalidate();
//重定向到登录页面
return "redirect:toLoginPage";
}
}
HTML页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<div align="center">请输入登录信息
<form name="Mfrom" method="post" action="/login" onsubmit="SubmitLogin()">
<table>
<tr>
<td>用户姓名:</td>
<td><input type="text" name="userName" value="xiaoqi" class="txtBox" /></td>
</tr>
<tr>
<td>登录密码:</td>
<td><input type="password" name="password" value="123456" class="txtBox"/></td>
</tr>
<!-- 以下是提交、取消按钮 -->
<tr>
<td>
<input type="submit" value="登录" />
</td>
<td>
<input type="reset" value="取消" />
</td>
</tr>
</table>
<p style="color:red" th:text="${errorMsg}"></p>
</form>
</div>
</body>
<script>
//提交登录
function SubmitLogin() {
//判断用户名是否为空
if (!Mfrom.userName.value) {
alert("请输入用户姓名!");
Mfrom.userName.focus();
return false;
}
//判断密码是否为空
if (!Mfrom.password.value) {
alert("请输入登录密码!");
Mfrom.password.focus();
return false;
}
return true;
}
</script>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
<meta name="author" content="pan_junbiao的博客">
</head>
<body>
<h1>首页</h1>
<p>当前Session中保存的登录人名称:<span th:text="${session.userName}"/></p>
<a href="logout" onclick="return confirm('确定注销吗?');">注销</a>
</body>
</html>
代码参考于https://o7planning.org/11689/spring-boot-interceptor