springboot拦截器保存登录信息(ThreadLocal)

1.ThreadLocal

  • 是什么
    从名字我们就可以看到ThreadLocal 叫做本地线程变量,意思是说,ThreadLocal 中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的,ThreadLocal 为变量在每个线程中创建了一个副本,这样每个线程都可以访问自己内部的副本变量。
    1、在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
    2、线程间数据隔离
    3、进行事务操作,用于存储线程事务信息。
    4、数据库连接,Session会话管理。
  • 内部实现
    创建了ThreadLocalMap用来保存数据
static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
}

内部继承弱引用,当map为空时会被gc回收

  • 四种引用类型
    – 强引用:除非为null,内存不足也不会进行回收
    – 弱引用:内存不足时GC会将其回收
    – 软应用:无论是否有用,GC时会将其回收
    – 虚引用:近似于没有引用,用于跟踪对象被垃圾回收器回收的活动
@Component
public class HostHolder {

    private ThreadLocal<User> users = new ThreadLocal<>();

    public User getUser() {
        return users.get();
    }

    public void setUser(User user) {
        users.set(user);
    }

    public void clear() {
        users.remove();
    }
}

用ThreadLocal保存user数据

2.创建cookie工具类获取cookie信息

public class CookieUtil {

    public static String getValue(HttpServletRequest request, String name) {
        if (request == null || name == null) {
            throw new IllegalArgumentException("参数为空!");
        }
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(name)) {
                return cookie.getValue();
            }
        }
        return null;
    }
}

3.编写拦截器

@Component
public class LoginTicketInterceptor implements HandlerInterceptor {

    @Autowired
    private UserService userService;

    @Autowired
    private HostHolder hostHolder;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //查询ticket是否有效
        String ticket = CookieUtil.getValue(request, "ticket");
        if (ticket != null) {
            //查询凭证
            LoginTicket loginTicket = userService.findLoginTicket(ticket);
            //检查凭证是否有效
            if (loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())) {
                //根据凭证查询用户
                User user = userService.findUserById(loginTicket.getUserId());
                //在本次请求中持有用户
                hostHolder.setUser(user);
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        User user = hostHolder.getUser();
        if (user != null && modelAndView != null) {
            modelAndView.addObject("loginUser", user);
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        hostHolder.clear();
    }
}
  • preHandle()方法 - 用于在将请求发送到控制器之前执行操作。此方法应返回true,以将响应返回给客户端。
  • postHandle()方法 - 用于在将响应发送到客户端之前执行操作。
  • afterCompletion()方法 - 用于在完成请求和响应后执行操作。

4.在config中注册拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private LoginTicketInterceptor loginTicketInterceptor;
    //注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginTicketInterceptor)
                .excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg");
    }
}

静态资源无需拦截

5.在模板中写入

点击看gitee源码!

你可能感兴趣的:(springboot,spring,boot,java)