再说拦截器
之前,先讲讲过滤器
,想必我们对过滤器是非常熟悉的,在Servlet里面的web.xml里面的
。那么许多人老是被这两个东西搞得晕头转向的。这里我举个例子说明他俩的区别:
就好比在一堆沙子中淘出金子,把沙子过滤掉
小结
过滤器
就是直接pass大多数的,留下一部分的精英
拦截器
就是想尽办法在从这些精英中在阻拦你前进,甚至是不让你继续通过,能通过的一定是最强的。
在web开发中,拦截器是经常用到的功能。它可以帮我们验证是否登陆、过滤静态资源等。
在Spring中的拦截器分为了两种:
HandlerInterceptor是springMVC项目中的拦截器,它拦截的目标是请求的地址,
比MethodInterceptor先执行。
实现一个HandlerInterceptor拦截器可以直接实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。
这两种方法殊途同归,其实HandlerInterceptorAdapter也就是声明了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 {
}
}
preHandler:
目标方法执行完成之前一般而言,我们的登录拦截操做,等相关的拦截操做都可以定义在preHandler方法里面。
MethodInterceptor
是AOP项目中的拦截器,它拦截的目标是方法。
实现MethodInterceptor拦截器大致也分为两种,一种是实现MethodInterceptor接口,另一种利用AspectJ的注解或配置。
让我们看看MethodInterceptor的源码:
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation var1) throws Throwable;
}
这里我着重使用以下HandlerInterceptor
老规矩,还是使用之前Thymeleaf阶段的一个登录进行演示
【前置工作】
controller层跳转逻辑
// 去登陆页
@GetMapping(value = {"/", "/login"})
public String loginPage() {
return "login";
}
// 登录请求
@PostMapping(value = "/login")
public String main(User user, HttpSession session, Model model) {
// 这块可以写一些数据库账号密码的逻辑操作
// ...
// 如果密码账号无误,ok登录 把登录信息放到Session作用域中
// 这里只做非空判断
if (!StringUtils.isEmpty(user.getUsername()) && user.getPassword().equalsIgnoreCase("123456")) {
// 保存登陆成功的用户
session.setAttribute("loginUser", user);
return "redirect:/main.html";
} else {
model.addAttribute("msg", "账号密码错误");
return "login";
}
}
// 解决表单重复提交 重定向
@GetMapping("/main.html")
public String mainPage(HttpSession session, Model model) {
// 拦截器里面进行登陆的拦截判断操做
return "main";
}
【步骤一】
编写一个LoginInterceptor类
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// logback日志输出获取拦截的URI
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;
}
@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 {}
}
【步骤二】
将拦截器注入并配置拦截规则
@Configuration
public class MyConfig implements WebMvcConfigurer {
/**
* 配置拦截规则与注入拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPattern 添加拦截规则 /** 拦截所有包括静态资源
// excludePathPattern 排除拦截规则 所以我们需要放开静态资源的拦截
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/")
.excludePathPatterns("/login")
.excludePathPatterns("/css/**","/fonts/**","/images/**","/js/**");
}
}
说明
:如果我们在addInterceptors的方法里面使用addPathPattern
添加拦截路径的时候,使用/**
的方式进行拦截请求,那么这也就将静态资源也拦截掉了,所以我们可以通过excludePathPattern
来排除想放行的资源
【拦截效果】