搜索
您的当前位置:首页正文

谷粒商城实战笔记-239-商城业务-购物车-ThreadLocal用户身份鉴别

来源:步旅网


本节主要内容的是:

  • 实现点击购物车访问后台服务时,判断是否有登录用户,注意购物车整合了Spring Session,所以能获取登录后的session中的用户信息。如果没有登录,则会生成一个user_key,用来标识用户,user-key在后台生成,以cookie的形式保存在浏览器中,后续浏览器发出请求都会携带这个user-key,后台就能识别出这个临时用户。
  • 开发一个拦截器,在请求到达controller之前,实现用户识别的逻辑,把用户信息存储在ThreadLocal中,最后拦截响应,在response对象中创建cookie

拦截器识别用户身份

下面的代码实现了如下逻辑:

  • 实现点击购物车访问后台服务时,判断是否有登录用户,注意购物车整合了Spring Session,所以能获取登录后的session中的用户信息
  • 如果没有登录,则会生成一个user_key,用来标识用户
  • user-key在后台生成,以cookie的形式保存在浏览器中,后续浏览器发出请求都会携带这个user-key,后台就能识别出这个临时用户
  • 如果用户登录了,就会从redis中获取用户信息,存入cookie
  • 把用户信息存入ThreadLocal对象,以便在这个请求的其他对象中使用用户信息
/**
 * @Description: 在执行目标方法之前,判断用户的登录状态.并封装传递给controller目标请求
 **/
public class CartInterceptor implements HandlerInterceptor {


    public static ThreadLocal<UserInfoTo> toThreadLocal = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        UserInfoTo userInfoTo = new UserInfoTo();

        HttpSession session = request.getSession();
        //获得当前登录用户的信息
        MemberResponseVo memberResponseVo = (MemberResponseVo) session.getAttribute(LOGIN_USER);

        if (memberResponseVo != null) {
            //用户登录了
            userInfoTo.setUserId(memberResponseVo.getId());
        }

        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                //user-key
                String name = cookie.getName();
                if (name.equals(TEMP_USER_COOKIE_NAME)) {
                    userInfoTo.setUserKey(cookie.getValue());
                    //标记为已是临时用户
                    userInfoTo.setTempUser(true);
                }
            }
        }

        //如果没有临时用户一定分配一个临时用户
        if (StringUtils.isEmpty(userInfoTo.getUserKey())) {
            String uuid = UUID.randomUUID().toString();
            userInfoTo.setUserKey(uuid);
        }

        //目标方法执行之前
        toThreadLocal.set(userInfoTo);
        return true;
    }


    /**
     * 业务执行之后,分配临时用户来浏览器保存
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        //获取当前用户的值
        UserInfoTo userInfoTo = toThreadLocal.get();

        //如果没有临时用户一定保存一个临时用户
        if (!userInfoTo.getTempUser()) {
            //创建一个cookie
            Cookie cookie = new Cookie(TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey());
            //扩大作用域
            cookie.setDomain("gulimall.com");
            //设置过期时间
            cookie.setMaxAge(TEMP_USER_COOKIE_TIMEOUT);
            response.addCookie(cookie);
        }

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

定义了一个名为 CartInterceptor 的类,它实现了 HandlerInterceptor 接口,该接口是 Spring MVC 中用于拦截请求处理过程的一种机制。

CartInterceptor 主要用于处理与购物车相关的逻辑,特别是在处理用户会话信息方面。

Interceptor(拦截器)原理简介

在 Spring MVC 中,HandlerInterceptor 接口提供了一种在控制器方法执行前后添加逻辑的方法。通常,拦截器可以用来做一些横切关注点的事情,例如认证、授权、记录日志等。HandlerInterceptor 定义了三个方法:

  • preHandle:在控制器方法执行前调用,可以用来做一些预处理工作,如验证用户身份等。
  • postHandle:在控制器方法执行后,但在视图渲染之前调用,可以用来修改模型数据或添加响应头等。
  • afterCompletion:在整个请求处理完成之后调用,即在视图渲染之后调用,可以用来释放资源或记录异常等。

CartInterceptor 类分析

主要功能;

关键点

  • ThreadLocal 的使用:toThreadLocal 是一个 ThreadLocal 变量,用于存储当前线程的 UserInfoTo 对象。这样可以确保每个线程处理请求时都能访问到正确的用户信息。
  • 用户会话管理:通过读取会话(HttpSession)和 cookie 来确定用户的身份。如果用户已登录,使用其 ID;否则使用临时用户标识。
  • 临时用户标识:通过 Cookie 存储临时用户标识,使得即使用户未登录也能追踪其行为(例如添加商品到购物车)。

CartInterceptor 主要负责在请求处理过程中管理用户的会话信息,并确保即使在用户未登录的情况下,也能够正确地处理购物车相关的操作。

通过使用 ThreadLocalCookie,它可以有效地维护每个用户的上下文信息,并且保证了数据的一致性和安全性。

因篇幅问题不能全部显示,请点此查看更多更全内容

Top