目录
1.什么是拦截器?
2.拦截器的使用
2.1定义拦截器
2.2 注册配置拦截器
3.拦截器详解
3.1 拦截路径
3.2 拦截器的执行流程
4. 使用拦截器实现登录校验
4.1 定义拦截器
4.2 注册配置拦截器
1.什么是拦截器?
拦截器是Spring框架提供的核心功能之⼀, 主要用来拦截用户的请求, 在指定⽅法前后, 根据业务需要执行预先设定的代码.
也就是说, 允许开发人员提前预定义一些逻辑, 在用户的请求响应前后执行. 也可以在用户请求前阻止其执行.
在拦截器当中,开发人员可以在应用程序中做一些通用性的操作, 比如通过拦截器来拦截前端发来的请求, 判断Session中是否有登录用户的信息. 如果有就可以放行, 如果没有就进行拦截.
比如我们去银行办理业务,在办理业务前后, 就可以加一些拦截操作
办理业务之前, 先取号, 如果带身份证了就取号成功
业务办理结束, 给业务办理人员的服务进行评价.
这些就是"拦截器"做的工作.
2.拦截器的使用
拦截器的使用步骤分为两步:
1.定义拦截器
2.注册配置拦截器
2.1定义拦截器
定义拦截器: 实现 HandlerInterceptor 接口, 并重写其所有方法
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Slf4j
public class LoginInterceptorTest 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 的区别:
preHandle方法的返回值会影响目标方法的执行流程:
-
返回true:表示继续执行目标方法。如果preHandle方法返回true,则目标方法会继执行,整个请求处理流程会继续进行。
-
返回false:表示中断目标方法的执行。如果preHandle方法返回false,则目标方法不会被执行,整个请求处理流程会被中断,后续的处理器方法和拦截器方法不会被执行。
总结
preHandle() 方法: 目标方法执行前执行. 返回true: 继续执行后续操作; 返回false: 中断后续操作.
postHandle() 方法: 目标方法执行后执行
afterCompletion() 方法: 视图渲染完毕后执行,最后执行(后端开发现在几乎不涉及视图,暂不了解)
2.2 注册配置拦截器
注册配置拦截器: 实现WebMvcConfigurer接口, 并重写addInterceptors方法
@Configuration
public class WebConfigTest implements WebMvcConfigurer {
//自定义的拦截器对象
@Autowired
private LoginInterceptorTest loginInterceptorTest;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册自定义的拦截器对象
registry.addInterceptor(loginInterceptorTest)
.addPathPatterns("/**"); //设置拦截器的请求路径, (/**表示拦截所有请求)
}
}
在图书管理系统中引入上述拦截器的代码
在图书管理系统中点击登录按钮:
此时拦截器代码的日志记录如下:
可以看到 preHandle 方法执行之后就放行了, 开始执行目标方法, 目标方法执行完成之后执行
postHandle 和 afterCompletion 方法.
我们把拦截器中 preHandle 方法的返回值改为 false, 再观察运行结果
可以看到, 拦截器拦截了请求, 没有进行响应.
3.拦截器详解
拦截器的入门程序完成之后,接下来我们来介绍拦截器的使用细节。拦截器的使用细节我们主要介绍两个部分:
1.拦截器的拦截路径配置
2.拦截器实现原理
3.1 拦截路径
拦截路径是指我们定义的这个拦截器, 对哪些请求生效.
我们在注册配置拦截器的时候,通过 addPathPatterns() 方法指定要拦截哪些请求. 也可以通过excludePathPatterns() 指定不拦截哪些请求.
上述代码中,我们配置的是 / ** ,表示拦截所有的请求.
比如用户登录校验,我们希望可以对除了登录之外所有的路径生效.
@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") //排除掉不需要拦截的路径
;
}
}
在拦截器中除了可以设置 / ** 拦截所有资源外,还有一些常见拦截路径设置:
以上拦截规则可以拦截此项目中的使用URL, 包括静态文件(图片文件, JS和CSS等文件).
3.2 拦截器的执行流程
正常的调用顺序:
有了拦截器之后,会在调用 Controller 之前进行相应的业务处理,执行的流程如下图
1.添加拦截器后,执行 Controller 的方法之前, 请求会先被拦截器拦截住. 执行 preHandle() 方法,
这个方法需要返回一个布尔类型的值. 如果返回 true, 就表示放行本次操作, 继续访问 Controller 中的方法. 如果返回 false , 则不会放行 (Controller 中的方法也不会执行).
2. Controller 当中的方法执行完毕后,再回过来执行 postHandle() 这个方法以及afterCompletion() 方法,执行完毕之后,最终给浏览器响应数据.
4. 使用拦截器实现登录校验
学习拦截器的基本操作之后,接下来我们需要完成最后一步操作: 通过拦截器来完成图书管理系统中的登录校验功能
4.1 定义拦截器
从 session 中获取用户信息,如果 session 中不存在, 则返回 false, 并设置 http 状态码为 401, 否则返回 true.
import com.example.com.constant.Constants;
import com.example.com.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;
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
/**
* 请求处理前执行的逻辑
* true : 表示放行, 不进行拦截
* false: 表示拦截, 不进行下一步处理
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("LoginInterceptor priHandle.....");
//获取session 并且判断session中存储的userInfo信息是否为空
HttpSession session = request.getSession();
// getSession(true): session存在就返回, 不存在就创建一个新的session返回 默认是true
// getSession(false): session存在就返回, 不存在就返回空
UserInfo userInfo = (UserInfo) session.getAttribute(Constants.USER_SESSION_KEY);
if(userInfo == null || userInfo.getId() <= 0) {
//用户未登录
response.setStatus(401);
return false;
}
return true;
}
}
4.2 注册配置拦截器
import com.example.com.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") //排除掉不需要拦截的路径
;
}
}
也可以改写成:
import com.example.com.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;
import java.util.Arrays;
import java.util.List;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
private List<String> excludePaths = Arrays.asList(
"/user/login",
"/css/**",
"/js/**",
"/pic/**",
"/**/*.html"
);
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludePaths) //排除掉不需要拦截的路径
;
}
}
以上代码在项目中的位置: