本节主要内容的是:
- 实现点击购物车访问后台服务时,判断是否有登录用户,注意购物车整合了
Spring Session
,所以能获取登录后的session中的用户信息。如果没有登录,则会生成一个user_key
,用来标识用户,user-k
ey在后台生成,以cookie
的形式保存在浏览器中,后续浏览器发出请求都会携带这个user-key
,后台就能识别出这个临时用户。 - 开发一个拦截器,在请求到达
controller
之前,实现用户识别的逻辑,把用户信息存储在ThreadLocal
中,最后拦截响应,在response
对象中创建cookie
。
拦截器识别用户身份
下面的代码实现了如下逻辑:
- 实现点击购物车访问后台服务时,判断是否有登录用户,注意购物车整合了
Spring Session
,所以能获取登录后的session中的用户信息 - 如果没有登录,则会生成一个
user_key
,用来标识用户 user-k
ey在后台生成,以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
类分析
主要功能;
-
preHandle
方法:- 初始化
UserInfoTo
对象并获取当前用户的会话信息。 - 如果用户已登录,则设置用户的 ID。
- 读取客户端的 cookie 以确定是否存在一个临时用户标识 (
user-key
)。 - 如果没有找到临时用户标识,则生成一个新的 UUID 作为临时用户标识。
- 初始化
-
postHandle
方法:- 如果当前用户没有临时用户标识(即不是通过 cookie 传递过来的),则创建一个带有临时用户标识的 cookie,并将其发送给客户端。
-
afterCompletion
方法:- 这个方法在此类中未实现任何具体逻辑。
关键点
- ThreadLocal 的使用:
toThreadLocal
是一个ThreadLocal
变量,用于存储当前线程的UserInfoTo
对象。这样可以确保每个线程处理请求时都能访问到正确的用户信息。 - 用户会话管理:通过读取会话(
HttpSession
)和 cookie 来确定用户的身份。如果用户已登录,使用其 ID;否则使用临时用户标识。 - 临时用户标识:通过
Cookie
存储临时用户标识,使得即使用户未登录也能追踪其行为(例如添加商品到购物车)。
CartInterceptor
主要负责在请求处理过程中管理用户的会话信息,并确保即使在用户未登录的情况下,也能够正确地处理购物车相关的操作。
通过使用 ThreadLocal
和 Cookie
,它可以有效地维护每个用户的上下文信息,并且保证了数据的一致性和安全性。