【Spring】拦截器详解_spring拦截器拦 csdn
文章目录
强制登录的功能,后端程序根据 Session 来判断用户是否登录,但是实现方法是比较麻烦的
- 需要修改每个接口的处理逻辑
 - 需要修改每个接口的返回结果
 - 接口定义修改,前端代码也需要跟着修改
 
有没有更简单的方法,同意拦截所有的请求,并进行 Session 校验呢,这里我们才有一种新的方法——拦截器
快速入门
什么是拦截器?
拦截器是 Spring 框架提供的核心功能之一,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码
- 也就是说,允许开发人员提前预定义一些逻辑,在用户的请求响应前后执行,也可以在用户请求前阻止其运行
 - 在拦截器中,开发人员可以在应用程序中做一些通用性的操作,比如通过拦截器前端发来的请求,判断 
Session中是否有登录用户的信息。如果有就可以放心,如果没有就进行拦截
 
比如我们去银行办理业务,在办理业务前后,就可以加一些拦截操作
- 办理业务之前,先取号,如果带了身份证就取号成功
 - 业务办理结束,给业务办理人员的服务进行评价
 - 这些就是“拦截器”做的工作
 
基本使用
拦截器的使用步骤分为两步
- 定义拦截器
 - 注册配置拦截器
 
定义拦截器
实现 HandlerInterceptor 接口,并重写其所有方法
@Slf4j @Componentpublic class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info(\"LoginInterceptor 目标方法执行前执行...\"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info(\"LoginInterceptor 目标方法执行后执行...\"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info(\"LoginInterceptor 视图渲染完毕后执行,最后执行\"); } }
preHandle()方法:目标方法执行前执行- 返回 
true:继续执行后续操作 - 返回 
false:中断后续操作 
- 返回 
 postHandle()方法:目标方法执行后执行afterCompletion()方法:视图渲染完毕后执行,最后执行(后端开发现在几乎不涉及视图,暂不了解)
注册配置拦截器
实现 webMvcConfigurer 接口,并重写 addInterceptors 方法
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 注册自定义拦截器对象  registry.addInterceptor(loginInterceptor)  .addPathPatterns(\"/**\"); // 设置拦截器拦截的请求路径( /** 为拦截所有请求)  } }
启动服务,试试访问任意请求,观察后端日志
- 可以看到 
preHandle方法执行之后就放行了,开始执行目标方法,目标方法执行完成之后执行postHandle和afterCompletion方法 
我们把拦截器中 preHandle 方法的返回值改为 false,再观察运行结果
- 可以看到,拦截器拦截了请求,没有进行响应
 
拦截器详解
拦截器的入门程序完成之后,接下来我们来介绍拦截器的使用细节。拦截器的使用细节我们主要介绍两个部分:
- 拦截器的拦截路径配置
 - 拦截器实现原理
 
拦截路径
拦截路径是指我们定义的这个拦截器,对哪些请求生效
我们在注册配置拦截器的时候,通过 addPathPatterns() 方法指定要拦截哪些请求。也可以通过 excludePathPatterns() 指定不拦截哪些请求
- 上述代码中,我们的配置是 
/**,表示拦截所有请求 
比如用户登录校验,我们希望可以对除了登录之外所有的路径生效
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { // 自定义拦截器对象 @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 注册自定义拦截器对象  registry.addInterceptor(loginInterceptor)  .addPathPatterns(\"/**\")  .excludePathPatterns(\"user/login\"); // 设置拦截器拦截的请求路径( /** 为拦截所有请求)  } }
常见路径
在拦截器中除了设置 /** 拦截所有资源外,还有一些常见拦截路径设置:
/*/user,/boook,/login,不能匹配 /user/login/**/user,/user/login,/user/reg/book/*/book 下的一级路径/book/addBook,不能匹配 /Book/addBook1,/book/book/**/book 下的任意级路径/book,/book/addBook/,/book/addBook2,不能匹配 /user/login以上拦截器规则可以拦截项目中使用的
URL,包括静态文件(图片文件,JS和CSS等文件)
拦截器执行流程
正常调用顺序:
 
有了拦截器之后,会在调用 Controller 之前进行响应的业务处理,执行的流程为:
- 
添加拦截器之后,执行
Controller的方法之前,请求会被拦截器拦截。执行preHandle()方法,这个方法需要返回一个布尔类型的值- 返回 
true:就表示放行本次操作,继续访问Controller中的方法 - 返回 
false:就表示不会放行本次操作Controller中的方法也不会执行 
 - 返回 
 - 
controller中的方法执行完毕之后,再回过来执行postHandle()方法以及afterCompletion()方法,执行完毕之后,最终给浏览器响应数据 
登录校验
学习拦截器的基本操作之后,接下来我们需要完成最后一步操作:通过拦截器来完成图书管理系统中的登录校验功能
定义拦截器
从 session 中获取用户信息,如果 session 中不存在,则返回 false,并设置 HTTP 状态码为 401,否则返回 true
import com.bite.book.constant.Constants; import com.bite.book.model.UserInfo; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; @Slf4j @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //true 表示放行 false表示拦截  log.info(\"LoginInterceptor preHandle....\"); //获取session, 并且判断session中存储的userinfo信息是否为空  HttpSession session = request.getSession(); UserInfo userInfo = (UserInfo) session.getAttribute(Constants.USER_SESSION_KEY); if (userInfo==null || userInfo.getId()<=0){  //用户未登录  response.setStatus(401);  return false; } return true; } }
http状态码401:Unauthorized
- 未经过认证。指身份验证是必须的,没有提供身份验证或身份验证失败
 - 如果请求已经包含授权凭证,那么
 401状态码表示不接受这些凭证
注册配置拦截器
import com.bite.book.interceptor.LoginInterceptor; import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor)  .addPathPatterns(\"/**\")  .excludePathPatterns(\"/user/login\")  .excludePathPatterns(\"/css/**\")  .excludePathPatterns(\"/js/**\")  .excludePathPatterns(\"/pic/**\")  .excludePathPatterns(\"/**/*.html\") ; } }
删除之前的登录校验代码:
/** * 查询图书列表 */ @RequestMapping(\"/getBookListByPage\") public Result<PageResult<BookInfo>> getBookListByPage(PageRequest pageRequest, HttpSession session){ log.info(\"查询图书列表, 请求参数pageRequest: {}\", pageRequest); // //从session获取用户信息 // //如果用户信息为空, 说明用户未登录 // UserInfo loginUserInfo = (UserInfo) session.getAttribute(Constants.USER_SESSION_KEY); // if (loginUserInfo==null || loginUserInfo.getId()<=0){ // return Result.nologin(); // }  //参数校验, 自己补充  PageResult<BookInfo> bookList = bookService.getBookListByPage(pageRequest); return Result.success(bookList); }


