SpringBoot * 的配置使用介绍
作者:刘婉晴 时间:2021-06-20 07:25:54
1. 配置 *
具体步骤:
编写一自定义 * 类实现接口 HandlerInterceptor
HandlerInterceptor 接口: 可在三处进行拦截——目标方法执行之前、目标方法执行完成、页面渲染以后拦截
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 {
}
}
将 * 注册到容器中,实现 WebMvcConfigurer 中的 addInteraptor,然后将自定义 * 注册到 * 中
指定 * 规则 —— 拦截所有 '/**'
,静态资源也会被拦截
解决静态资源同时被拦截问题:
在
addPathPatterns
中精确指定精确需要拦截资源在
excludePathPatterns
中指定排除静态资源
可在 application.properties 文件中指定静态资源统一前缀,方便排除静态资源
spring.mvc.static-path-pattern=/static/**
2. 一个小 Demo
实现未登录用户不能访问除登录页外其他页面的小Demo
1. 自定义 * 类—LoginInterceptor
自定义登录 * ,实现检测到用户未登录,则拦截用户对其他资源的访问,并返回到登录页面
package com.wanqing.admin.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.Session;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/*
登录检查
*/
@Slf4j // lombok 提供的功能
public class LoginInterceptor implements HandlerInterceptor {
// 目标方法执行之前
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("拦截的路径是{}", request.getRequestURI());
// 登录检查逻辑
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if(loginUser != null){
return true; // 放行
}
// 拦截住,重定向到登录页面
request.setAttribute("msg", "未登录不允许访问");
request.getRequestDispatcher("/").forward(request, response); // 转发到当前请求
return false;
}
// 目标方法执行之后
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
// 页面渲染完成之后
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
2. 将 * 注册到容器中
通过下列方法,将 * 注册到容器中,并配置好要拦截的路径和要放行的路径。本次 demo 中若未登录则所有路径都拦截,只放行登录页面
package com.wanqing.admin.config;
import com.wanqing.admin.interceptor.LoginInterceptor;
import lombok.extern.slf4j.Slf4j;
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 AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 在 * 的注册中心里,添加 Login *
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") //所有请求都被拦截,静态资源也被拦截
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); // 放行的请求
}
}
3. 原理分析
1. 根据当前请求,找到HandlerExecutionChainand,即得到可以处理请求的 Handler,以及 Handler 的所有 *
处理器执行链 :
2. 先顺序执行所有 * 的preHandle
方法
如果返回为true执行下一个 * 的
preHandle
;若为 false,直接倒叙执行所有已经执行了的 * 的
afterCompletion
方法
Step into:
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
* 方法执行 源码分析:
HandlerExecutionChain.class
—— 顺序执行所有 * 的preHandle
方法
for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
—— 倒叙执行所有已经执行了的 * 的 afterCompletion
方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var7) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var7);
}
}
}
3. 如果任何一个 * 返回 false,直接跳出不执行目标方法
4. 所有 * 都返回 true,执行目标方法
5. 目标方法执行后,倒叙执行所有 * 的 postHandle 方法
6. 前面的步骤有任何异常都会直接触发 afterCompletion 方法
7. 页面成果渲染完成之后,也会倒叙触发 afterCompletion 方法
图解:
来源:https://blog.csdn.net/liuwanqing233333/article/details/127235421