session的使用
客户端首次向服务器发送请求,服务器会检查是否包含有效的session ID 没有则会新创建一个session对象,并分配一个唯一的session id
这个id会通过cookie或者url重写(即将session id附加到url后面)的方式返回给客户端
后续客户端发送请求都会将这个id发送给服务端,服务端再根据这个session id来查找对应的httpsession对象。 如果找到了就用这个session。如果id无效,或者已过期,被销毁,即便客户端发送了session id,服务器也可能不会使用该session,而是重新创建等处理
登录 拦截器的设置
package com.hmdp.utils;
import com.hmdp.dto.UserDTO; import com.hmdp.entity.User; import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor { //实现HandlerInterceptor接口 //接口有三个方法,需要实现两个方法 //preHandle
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取session
HttpSession session = request.getSession();
//2.获取session中的用户
Object user = session.getAttribute("user");
//3.判断用户是否存在
if (user == null) {
//4.不存在 拦截
response.setStatus(401);
return false;
}
//5.存在 保存用户信息到ThreadLocal
UserHolder.saveUser((UserDTO) user); //TODO threadlocal这里存放用户信息有什么用
//6.放行
return true;
}
//afterHandle
@Override //TODO这里的afterCompletion怎么是请求结束后就把用户移除了,那后面不是还要靠这个来证明当前那个用户处于登录状态吗
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//移除用户
UserHolder.removeUser();
}
}
问题一,threadlocal存储用户信息的作用是?
通常http的每次请求由一个独立的线程处理。
方便获取用户数据不用重复从session那里解析得到用户数据。
有线程隔离和便携访问的功能。
从 ThreadLocal 获取比反复查询Session更高效、更简洁。
💡 补充说明:
Session 是服务端会话管理机制,存储的是全局用户状态(如登录态)。
ThreadLocal 是请求级别的临时存储,仅用于在当前请求链中共享数据,与用户是否登录无关。
问题二,为什么在 afterCompletion 中移除用户?
防止数据污染,比如说一次请求结束后然后另外一个请求如果是同一个线程,那么它的数据仍然保存着上一次请求用户的数据。
内存泄漏: ThreadLocal 中存储的对象会一直占用内存,直到线程销毁(而线程池中的线程可能长期存活)。
用户的登录状态不依赖 ThreadLocal
用户的登录状态由 HttpSession 维护,只要Session未过期,用户依然处于登录状态。
每次新请求到达时, preHandle 方法会重新从Session中读取用户信息并存入 ThreadLocal ,因此移除操作不会影响用户登录状态。
补充说明:
afterCompletion 的触发时机:在视图渲染完成后执行(无论请求成功或异常),确保清理逻辑一定会执行。
与登录状态无关:用户的登录状态由 Session 维护, ThreadLocal 只是临时缓存,移除它不会影响用户是否已登录。