谷粒商城实战笔记-239-商城业务-购物车-ThreadLocal用户身份鉴别
文章目录
- 拦截器识别用户身份
- Interceptor(拦截器)原理简介
- `CartInterceptor` 类分析
本节主要内容的是:
- 实现点击购物车访问后台服务时,判断是否有登录用户,注意购物车整合了
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<>();@Overridepublic 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-keyString 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;}/*** 业务执行之后,分配临时用户来浏览器保存*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {//获取当前用户的值UserInfoTo userInfoTo = toThreadLocal.get();//如果没有临时用户一定保存一个临时用户if (!userInfoTo.getTempUser()) {//创建一个cookieCookie cookie = new Cookie(TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey());//扩大作用域cookie.setDomain("gulimall.com");//设置过期时间cookie.setMaxAge(TEMP_USER_COOKIE_TIMEOUT);response.addCookie(cookie);}}@Overridepublic 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 类分析
主要功能;
-
preHandle方法:- 初始化
UserInfoTo对象并获取当前用户的会话信息。 - 如果用户已登录,则设置用户的 ID。
- 读取客户端的 cookie 以确定是否存在一个临时用户标识 (
user-key)。 - 如果没有找到临时用户标识,则生成一个新的 UUID 作为临时用户标识。
- 初始化
-
postHandle方法:- 如果当前用户没有临时用户标识(即不是通过 cookie 传递过来的),则创建一个带有临时用户标识的 cookie,并将其发送给客户端。
-
afterCompletion方法:- 这个方法在此类中未实现任何具体逻辑。
关键点
- ThreadLocal 的使用:
toThreadLocal是一个ThreadLocal变量,用于存储当前线程的UserInfoTo对象。这样可以确保每个线程处理请求时都能访问到正确的用户信息。 - 用户会话管理:通过读取会话(
HttpSession)和 cookie 来确定用户的身份。如果用户已登录,使用其 ID;否则使用临时用户标识。 - 临时用户标识:通过
Cookie存储临时用户标识,使得即使用户未登录也能追踪其行为(例如添加商品到购物车)。
CartInterceptor 主要负责在请求处理过程中管理用户的会话信息,并确保即使在用户未登录的情况下,也能够正确地处理购物车相关的操作。
通过使用 ThreadLocal 和 Cookie,它可以有效地维护每个用户的上下文信息,并且保证了数据的一致性和安全性。
