拦截器原理:
拦截器的原理很简单,是 AOP 的一种实现,专门拦截对动态资源的后台请求,即拦截对控制层的请求。使用场景比较多的是判断用户是否有权限请求后台,更拔高一层的使用场景也有,比如拦截器可以结合 websocket 一起使用,用来拦截 websocket 请求,然后做相应的处理等等。
注册拦截器
步骤01 创建一个spring boot项目,添加spring-boot-starter-web依赖
步骤02 创建拦截器实现HandlerInterceptor接口
package xintianweng;
import org.apache.catalina.filters.ExpiresFilter;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletResponse;
/**
* 创建一个拦截器
* @author 信天翁
* 2021/3/29 10:00 下午
**/
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler){
System.out.println("MyInterceptor>>>preHandle");
return true;
}
public void postHandle(HttpServletRequest request, ExpiresFilter.XHttpServletResponse response, Object handler, ModelAndView modelAndView){
System.out.println("MyInterceptor>>>postHandle");
}
public void afterCompletion(HttpServletRequest request, ExpiresFilter.XHttpServletResponse response, Object handler,Exception ex){
System.out.println("MyInterceptor>>>afterCompletion");
}
}
拦截器中的方法将按preHandle➡️Controller➡️postHandle➡️afterCompletion的顺序执行。
注意,只有当preHandle方法返回true时后面的方法才会执行。
当拦截器链内存在多个拦截器时,postHandler在拦截器链内的所有拦截器返回成功时才会调用,而afterCompletion只有preHandle返回true才调用,但若拦截器链内的第一个拦截器的preHandle方法返回false,则后面的方法都不会执行。
步骤03 配置拦截器。定义配置类进行拦截器的配置
package xintianweng;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 配置拦截器
* @author 信天翁
* 2021/3/29 10:00 下午
**/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/hello");
}
}
preHandle(……) 方法:该方法的执行时机是,当某个 url 已经匹配到对应的 Controller 中的某个方法,且在这个方法执行之前。所以 preHandle(……) 方法可以决定是否将请求放行,这是通过返回值来决定的,返回 true 则放行,返回 false 则不会向后执行。
postHandle(……) 方法:该方法的执行时机是,当某个 url 已经匹配到对应的 Controller 中的某个方法,且在执行完了该方法,但是在 DispatcherServlet 视图渲染之前。所以在这个方法中有个 ModelAndView 参数,可以在此做一些修改动作。
afterCompletion(……) 方法:顾名思义,该方法是在整个请求处理完成后(包括视图渲染)执行,这时做一些资源的清理工作,这个方法只有在 preHandle(……) 被成功执行后并且返回 true 才会被执行。
自定义类实现WebMvcConfigurer接口,实现接口中的addInterceptors方法。其中,
addPathPatterns是用来表示拦截路径。
excludePathPatterns是用来表示排除的路径。
templates下创建hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
spring boot !
</body>
</html>
执行springboot启动类,控制台输出如下:
MyInterceptor>>>>preHandle
HELLO SPRING BOOT!
MyInterceptor>>>>postHandle
MyInterceptor>>>>afterCompletion
总结:
①:首先会在拦截到Controller中的“/hello”时先执行preHandle里的逻辑。输出“MyInterceptor>>>>preHandle”
②:然后执行“/hello”对应映射的方法逻辑,输出“HELLO SPRING BOOT!”
③:成功执行“/hello”对应映射的方法逻辑,然后在 DispatcherServlet 视图渲染之前执行postHandle方法里的逻辑。
④:整个请求结束后,然后在这里执行一些其他辅助逻辑,包括资源清理等。
拦截器处理静态资源被拦截的问题
spring boot 2.0以后废弃了WebMvcConfigurerAdapter,但是WebMvcConfigurationSupport 又会导致默认的静态资源被拦截
手动放开静态资源拦截:(和上面的手动配置拦截器一样,在原来的>addInterceptors方法外,还需要重写addResourceHandlers,将资源放开)
protected void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
super.addResourceHandlers(registry);
}
网友评论