Autenticación ThreadLocal, carrito de compras

¿Cuál es el papel de ThreadLocal?
ThreadLocal es una buena idea para resolver el problema de seguridad de los subprocesos, ya que resuelve el conflicto del acceso concurrente a las variables proporcionando una copia de variable independiente para cada subproceso. En muchos casos, ThreadLocal es más simple y conveniente que usar directamente el mecanismo de sincronización sincronizada para resolver problemas de seguridad de subprocesos, y el programa resultante tiene una mayor simultaneidad.

¿Cuál es el escenario de aplicación de ThreadLocal?
En la programación multiproceso de Java, para garantizar el acceso seguro a las variables compartidas por varios subprocesos, la sincronización se utiliza generalmente para garantizar que solo un subproceso opere en variables compartidas a la vez. En este caso, puede poner la variable de clase en el objeto de tipo ThreadLocal, para que la variable tenga una copia independiente en cada hilo, y no habrá fenómeno de que un hilo lea la variable y sea modificado por otro hilo. El escenario de uso más común de ThreadLocal es resolver la conexión de la base de datos, la administración de sesiones, etc. A continuación se enumeran algunos escenarios

Inserte la descripción de la imagen aquí
De esta forma, podemos obtener datos de los usuarios a través de ThreadLocal en cualquier lugar.

Análisis de demanda:
* Este es un escenario de carrito de compras. Puede agregar un carrito de compras cuando el usuario no ha iniciado sesión, y también puede agregar un carrito de compras después de iniciar sesión.
* El navegador tiene una cookie: user-key, que identifica la identidad del usuario, y vence en un mes.
* Si usa la función de carrito de compras de jd por primera vez, se le dará una identidad de usuario temporal.
* El navegador guardará más tarde y tráigala con usted cada vez que visite Esta cookie
*
* Sesión de inicio de sesión Sí
* Sin inicio de sesión, hágalo de acuerdo con la clave de usuario en la cookie
* Primera vez: Si no hay un usuario temporal, ayude a crear un usuario temporal - > Utilice el interceptor
* @return para
introducir dependencia:

<!--        引入redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!--        整合Spring Session完成session共享问题 微服务自治,就不放在common里了-->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

Modificar la información de configuración de plication.yml

  #配置Redis缓存
  spring:
	  redis:
	    host: 81.68.112.20
	    port: 6379
  #整合Spring Session 指定session是存到redis里
	  session:
	    store-type: redis

Primero crea un interceptor

**
 * @author 孟享广
 * @date 2021-02-03 3:01 下午
 * @description 在执行目标方法之前,判断用户的登录状态,并封装传递给controller的目标请求
 */
public class CartInterceptor implements HandlerInterceptor {
    
    

    //ThreadLocal 同一线程上信息共享
    public static ThreadLocal<UserInfoTo> threadLocal = new ThreadLocal<>();

    /**
     * 在目标方法执行之前
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    

        UserInfoTo userInfoTo = new UserInfoTo();
        HttpSession session = request.getSession();
        MemberResVo memberResVo = (MemberResVo) session.getAttribute(AuthServiceConstant.LOGIN_USER);
        if (memberResVo != null) {
    
    
            //说明用户登录了
            userInfoTo.setUserId(memberResVo.getId());
        }

        //只要有user-key 就赶紧取出value
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
    
    
            //有cookie 可能是临时用户,但是此方法针对登录用户
            for (Cookie cookie : cookies) {
    
    
                String name = cookie.getName();
                if (name.equals(CartServiceConstant.TEMP_USER_COOKIE_NAME)) {
    
    
                    userInfoTo.setUserKey(cookie.getValue());
                    //执行到这,说明是临时用户
                    userInfoTo.setTempUser(true);
                }
            }
        }

        //如果没有登录 就准备临时set一个cookie,首先设置To的userKey
        if (StringUtils.isEmpty(userInfoTo.getUserKey())) {
    
    
            String uuid = UUID.randomUUID().toString();
            userInfoTo.setUserKey(uuid);
        }

        //目标方法执行前,放入 threadLocal
        threadLocal.set(userInfoTo);

        //只要来到目标方法都放行 无条件放行
        return true;
    }

    /**
     * 业务执行之后,让浏览器保存cookie
     * 分配临时用户,让浏览器保存
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    

        UserInfoTo userInfoTo = threadLocal.get();
        //如果没有临时用户,一定要保存一个临时用户
        if (!userInfoTo.isTempUser()) {
    
    
            //不是临时用户
            Cookie cookie = new Cookie(CartServiceConstant.TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey());
            //设置cookie作用域
            cookie.setDomain("gulimall.com");
            //cookie的过期时间
            cookie.setMaxAge(CartServiceConstant.TEMP_USER_COOKIE_TIMEOUT);
            response.addCookie(cookie);
        }
    }
}

Obtenga datos de usuario a través de ThreadLocal en Controller.

    /**
     * 浏览器有一个cookie:user-key:标识用户身份  一个月过期
     * 假如是第一次登录,都会给一个临时身份
     * 浏览器保存以后,每次访问都会带上这个cookie
     */
    @GetMapping("/cart.html")
    public String cartListPage(Map<String, Cart> map) throws ExecutionException, InterruptedException {
    
    

        //1 快速得到用户信息,ThreadLocal获取用户信息
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        System.out.println(userInfoTo);
        return "cartList";
    }

Supongo que te gusta

Origin blog.csdn.net/u014496893/article/details/114014944
Recomendado
Clasificación