springmvc拦截器
Posted zs-book1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springmvc拦截器相关的知识,希望对你有一定的参考价值。
在之前学习过滤器Filter,看到拦截器就想到了Filter
Filter的作用:对请求和响应进行过滤
Filter的生命周期:实例化----->初始化------>过滤-------->销毁
原理:基于函数回调;
只能在Web容器中使用,需要在服务器中使用,是一种Servlet规范;
那么拦截器是什么呢?
拦截器:针对处理器(Controller)的拦截器,是基于spring实现的
实现原理:反射;是AOP思想的一种体现;
拦截器的应用场景:
1.权限验证
2.日志记录
3.通用行为
4.性能监控
拦截器的实现:
1.实现HandlerInterceptor,接口源码如下:
package org.springframework.web.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; import org.springframework.web.method.HandlerMethod; 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
可以看到,源码的接口中提供了三个default方法;在jdk8之后,提供了default,接口中的方法使用default修饰后,实现类不是必须实现该方法了,在使用拦截器时,创建类继承拦截器适配器;接口适配:接口A中包含很多的方法,不想全部实现,就提供一个抽象子类B,实现部分方法,继承部分方法;子类C继承子类B可以根据需要重写B中的方法;
创建一个拦截器,进行登录身份验证:如果已经登录,就放行请求,如果没有登录,就拦截请求
//创建一个拦截器,继承HandlerInterceptor适配器 public class MyInterceptor extends HandlerInterceptorAdapter // 登录验证是在请求之前进行验证,因此重写preHandle方法 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception Object user = request.getSession().getAttribute("user"); if (user!=null) return true;//true表示该拦截器放行,false表示不放行 return false;
然后再mvc配置文件中注册该拦截器:
<!--注册拦截器--> <mvc:interceptors> <!--可以写多个拦截器--> <mvc:interceptor> <!--设置拦截路径--> <mvc:mapping path="/**"/> <!--如果是第一次登录请求,要放行--> <mvc:exclude-mapping path="/user/login"/> <bean class="com.zs.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
编写登录后台:
@Controller @RequestMapping("/user") @SessionAttributes("user") public class UserController @RequestMapping("/login") public String login(String username, String password, Model model) // 验证登录信息 if (username.equals("zhangsan") && password.equals("123456")) model.addAttribute("user", username); return "redirect:/view/index.jsp";
编辑前端页面验证拦截器是否生效:
模拟性能监控:
package com.zs.interceptor; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 性能监控,需要计算方法执行的时间,因此要在方法执行前,获取时间,方法执行后再获取时间,两个时间相减 */ public class XingNengInterceptor extends HandlerInterceptorAdapter //线程不同步? // 本地线程局部变量:只能在当前线程中使用,Map, 实现线程同步 ThreadLocal<Long> threadLocal = new ThreadLocal<>(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception long start = System.currentTimeMillis(); threadLocal.set(start); return true; @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception long end = System.currentTimeMillis(); System.out.println(String.format("执行时间:%d",end-threadLocal.get()));
注册拦截器,进行测试;
因为再Web容器中运行时,拦截器是分线程的,每一个登录的用户就开启一个线程,如果直接使用变量,会导致不同线程公用同一个变量,竞争资源,线程不安全,一个线程调用了方法,给变量赋值,方法执行期间,又一个线程执行了方法,就又给变量赋值了,所以使用本地线程局部变量的方法
以上是关于springmvc拦截器的主要内容,如果未能解决你的问题,请参考以下文章