谷粒商城实战笔记-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 类分析

主要功能;

  1. preHandle 方法

    • 初始化 UserInfoTo 对象并获取当前用户的会话信息。
    • 如果用户已登录,则设置用户的 ID。
    • 读取客户端的 cookie 以确定是否存在一个临时用户标识 (user-key)。
    • 如果没有找到临时用户标识,则生成一个新的 UUID 作为临时用户标识。
  2. postHandle 方法

    • 如果当前用户没有临时用户标识(即不是通过 cookie 传递过来的),则创建一个带有临时用户标识的 cookie,并将其发送给客户端。
  3. afterCompletion 方法

    • 这个方法在此类中未实现任何具体逻辑。

关键点

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小手追梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值