1.做了啥,咋做的
标题写的ThreadLocal,阅读它的源码会发现,他就是一个线程Thread 对象作为键的实现了map接口的类。
之前我们说了分布式session解决方案springsession 其实就是把session保存到 redis中,这里在拦截器的预处理中取到session,判断是否包含用户信息,
从而确定是否登录,若是没登录可以让跳转到登录页面,也可以就保存到离线购物车,之前京东还有离线购物车,但是现在好像没有了
这里为什么要用threadlocal对象呢,因为 拦截器与对应拦截方法是属于同一个线程的,我们每次访问方法之前,通过拦截器获取到用户信息,根据当前线程就自然
获取到当前线程的用户信息了,适用于并发场景,并发场景时一个用户对应一个请求线程,也就保存对应的用户信息,存取比较方便
2.核心代码
拦截器代码
package com.atguigu.gulimall.cart.interceptor;
import com.atguigu.common.constant.CartConstant;
import com.atguigu.common.entity.MemberEntity;
import com.atguigu.gulimall.cart.vo.UserInfoTo;
import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.LinkedHashMap;
import java.util.UUID;
/**
* @author rengang
* @version 1.0
* @date 2021/5/7 1:34
*/
@Component
public class CartInterceptor implements HandlerInterceptor {
public static ThreadLocal<UserInfoTo> threadLocal = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
LinkedHashMap loginUser = (LinkedHashMap)session.getAttribute("loginUser");
// MemberEntity memberEntity = BeanUtils.mapToBean(loginUser, MemberEntity.class);
UserInfoTo userInfoTo = new UserInfoTo();
if(loginUser != null){
userInfoTo.setUserId(Long.parseLong(loginUser.get("id").toString()));
}
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length > 0){
for (int i = 0; i < cookies.length; i++) {
if(CartConstant.TEMP_USER_COOKIE_NAME.equals(cookies[i].getName())){
userInfoTo.setUserKey(cookies[i].getValue());
}
}
}
threadLocal.set(userInfoTo);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
UserInfoTo userInfoTo = threadLocal.get();
if(userInfoTo.getUserKey()==null || userInfoTo.getUserKey().equals("")){
userInfoTo.setUserKey(UUID.randomUUID().toString());
}
Cookie cookie = new Cookie(CartConstant.TEMP_USER_COOKIE_NAME,userInfoTo.getUserKey());
cookie.setDomain("gulimall.com");
cookie.setMaxAge(CartConstant.TEMP_USER_COOKIE_EXPIRE_TIME);
response.addCookie(cookie);
}
}
webmvc配置中添加拦截器
package com.atguigu.gulimall.cart.config;
import com.atguigu.gulimall.cart.interceptor.CartInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author rengang
* @version 1.0
* @date 2021/4/11 18:38
*/
@Configuration
public class GulimallWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CartInterceptor()).addPathPatterns("/**");
}
}
针对session的配置,
首先,添加@EnableRedisHttpSession 注解,启用springsession,然后还有配置文件中session的保存方式改为redis中,
以及浏览器端以cookie形式保存的cookie的域名,名称,过期时间等设置 这里前面springsesion部分有说过,就不多讲了
package com.atguigu.gulimall.cart.config;
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
/**
* @author rengang
* @version 1.0
* @date 2021/4/26 23:47
*/
@EnableRedisHttpSession
@Configuration
public class GulimallSessionConfig {
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericFastJsonRedisSerializer();
}
@Bean
public CookieSerializer cookieSerializer(){
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("gulimallSession");
serializer.setDomainName("gulimall.com");
return serializer;
}
}
pom中添加的依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
controller中测试
package com.atguigu.gulimall.cart.controller;
import com.atguigu.gulimall.cart.interceptor.CartInterceptor;
import com.atguigu.gulimall.cart.vo.UserInfoTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author rengang
* @version 1.0
* @date 2021/5/7 2:36
*/
@Controller
public class CartController {
@RequestMapping("/cart.html")
public String cartListPage(){
UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
System.out.println(userInfoTo);
return "cartList";
}
}
结果成功获取到登录的用户信息