在系统中,经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中。当然不仅仅这些,所以需要一种机制,拦截用户的请求,在请求的前后添加处理逻辑。
SpringBoot 提供了 Interceptor 拦截器机制,用于请求的预处理和后处理。在 SpringBoot 中定义一个拦截器有两种方法:第一种是实现 HandlerInterceptor 接口,或者继承实现了 HandlerInterceptor 接口的类(例如:HandlerInterceptorAdapter);第二种方法时实现 Spring 的 WebRequestInterceptor 接口,或者继承实现了 WebRequestInterceptor 接口的类。这些拦截器都是在Handler的执行周期内进行拦截操作的。
1、HandlerInterceptor接口首先来看看 HandlerInterceptor 接口的源码:
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
如果要实现 HandlerInterceptor 接口,就要实现其三个方法,分别是:preHandle、postHandle、afterCompletion。
(1)preHandle 方法在执行 Handler 方法之前执行。该方法返回值为 Boolean 类型,如果返回false,表示拦截请求,不在向下执行。而如果返回 true,表示放行,程序继续向下进行(如果后面没有其他 Interceptor,就会直接执行 Controller 方法)。所以,此方法可以对请求进行判断,决定程序是否继续执行,或者进行一些前置初始化操作及对请求做预处理。
(2)postHandle 方法在执行 Handler 之后,返回 ModelAndView 之前执行。由于该方法会在前端控制器(DispatcherServlet)进行返回视图渲染之前被调用,所以此方法多被用于统一处理返回的视图,例如将公用的模型数据(例如导航栏菜单)添加到视图,或者根据其他情况制定公用的视图。
(3)afterCompletion 方法在执行完Handler之后执行。由于是在 Controller 方法执行完毕后执行该方法,所以该方法适合进行统一的异常或者日志处理操作。
2、使用拦截器实现用户登录校验相关博文:
《JSP/Servlet实现简单的登录校验》
《SpringMVC使用拦截器(Interceptor)实现用户登录校验》
《SpringBoot拦截器的配置并实现用户登录校验》
下面通过一个示例来使用拦截器完成登录控制,具体为拦截用户的请求,判断用户是否已经登录,如果用户没有登录,则跳转到 login 页面,如果用户已经登录,则放行。执行结果如下图:
登录失败,提示失败信息:
登录成功,进入首页:
(1)创建项目
创建 SpringBoot 项目,项目结构如下图:
(2)添加依赖
使用Maven添加依赖文件,在 pom.xml 文件中,添加需要的依赖:
org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-thymeleaf
(3)创建拦截器
创建 com.pjb.interceptor 包,创建登录拦截器(LoginInterceptor.java),并实现HandlerInterceptor接口,实现其三个方法。这里主要以preHandle方法为主。
package com.pjb.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginInterceptor implements HandlerInterceptor
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
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 {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) throws Exception {
}
}
(4)创建配置类
创建 com.pjb.config 包,并创建 WebMvcConfig 类,实现 WebMvcConfigurer 接口;重写 addViewControllers 方法和 addInterceptors 方法;使用 @Configuration 注解,标注该类为配置类。
了解WebMvcConfigurer配置接口的详解:
《SpringBoot中的WebMvcConfigurer配置接口的详解》
package com.pjb.config;
import com.pjb.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer
{
@Override
public void addViewControllers(ViewControllerRegistry registry)
{
registry.addViewController("/toIndexPage").setViewName("/index");
registry.addViewController("/").setViewName("/index");
}
@Override
public void addInterceptors(InterceptorRegistry registry)
{
//注册Interceptor拦截器
InterceptorRegistration registration = registry.addInterceptor(new LoginInterceptor());
registration.addPathPatterns("*.html", //html静态资源
"*.js", //js静态资源
"*.css" //css静态资源
);
}
}
(5)创建控制器
创建 com.pjb.controller 包,创建登录控制器(LoginController.java),编写登录与登出方法。
package com.pjb.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
@Controller
public class LoginController
{
@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("pan_junbiao的博客") && 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";
}
}
(6)创建视图
创建用户登录页面(Login.html)。
用户登录
.txtBox{
padding: 3px;
width: 250px;
font-size: 16px;
}
请输入登录信息
创建首页(index.html)。
首页
首页
当前Session中保存的登录人名称:
您好,欢迎访问 pan_junbiao的博客!
博客地址:https://blog.csdn.net/pan_junbiao
注销



