标签:default direct session png 释放 处理 实现 函数 nat
在之前学习过滤器Filter,看到拦截器就想到了Filter
Filter的生命周期:实例化----->初始化------>过滤-------->销毁
只能在Web容器中使用,需要在服务器中使用,是一种Servlet规范;
拦截器的应用场景:
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容器中运行时,拦截器是分线程的,每一个登录的用户就开启一个线程,如果直接使用变量,会导致不同线程公用同一个变量,竞争资源,线程不安全,一个线程调用了方法,给变量赋值,方法执行期间,又一个线程执行了方法,就又给变量赋值了,所以使用本地线程局部变量的方法
标签:default direct session png 释放 处理 实现 函数 nat
原文地址:https://www.cnblogs.com/Zs-book1/p/11329464.html