84分布式电商项目 - Redis存储购物车

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 84分布式电商项目 - Redis存储购物车

判断当前用户是否登陆,如果未登录采用 Cookie 存储,如果登录则采用 Redis 存储。登录后要进行 Cookie 购物车与 Redis 购物车的合并操作,并清除 Cookie 购物车。

获取当前登录人账号

spring-security.xml 更改配置:

去掉

<http pattern="/cart/*.do" security="none"></http>

添加

<http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint">
   <intercept-url pattern="/cart/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY"/><intercept-url pattern="/**" access="ROLE_USER"/>
   <custom-filter position="CAS_FILTER" ref="casAuthenticationFilter" /> 
   <custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
   <custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/> 
 </http>

access="IS_AUTHENTICATED_ANONYMOUSLY"用于设置资源可以在不登陆时可以访问。

此 配 置 与 security="none"的 区 别 在 于 当 用 户 未 登 陆 时 获 取 登 陆 人 账 号 的 值 为anonymousUser ,而 security="none"的话,无论是否登陆都不能获取登录人账号的值。

代码实现:

在 pinyougou-cart-web 的 findCartList 和addGoodsToCartList 方法中,获取用户名

//得到登陆人账号,判断当前是否有人登陆
String username = SecurityContextHolder.getContext().getAuthentication().getName();

测试:当用户未登陆时,username 的值为anonymousUser

远程购物车存取

服务层接口

pinyougou-cart-interface 中 CartService.java 定义方法

/**
   * 需求:查询redis购物车数据
   * @return
   */
  List<Cart> findRedisCartList(String username);
  /**
   * 把购物车列表保存到redis购物车
   * @param cartList
   * @param username
   */
  void saveCartListToRedisCart(List<Cart> cartList, String username);
服务层实现

pinyougou-cart-service 中 CartServiceImpl.java 实现方法

/**
   * 需求:查询redis购物车数据
   * 
   * @return
   */
  public List<Cart> findRedisCartList(String username) {
    // 查询redis服务购物车列表
    List<Cart> cartList = (List<Cart>) redisTemplate.boundHashOps(
        "cartList").get(username);
    // 判断查询购物车数据是否有值
    if (cartList == null) {
      return new ArrayList<Cart>();
    }
    return cartList;
  }
  /**
   * 把购物车列表保存到redis购物车
   *
   * @param cartList
   * @param username
   */
  public void saveCartListToRedisCart(List<Cart> cartList, String username) {
    // TODO Auto-generated method stub
    redisTemplate.boundHashOps("cartList").put(username, cartList);
  }
控制层

修改 CartController.java 的 findCartList 方法

/**
   * 需求:查询购物车列表
   * 
   * @return
   */
  @RequestMapping("/findCartList")
  public List<Cart> findCartList(HttpServletRequest request) {
    // 判断用户此时是否处于登录状态
    // 获取用户名
    String username = SecurityContextHolder.getContext()
        .getAuthentication().getName();
    //定义集合
    List<Cart> cartList = null;
    // 查询cookie购物车数据
    String cartListStr = CookieUtil.getCookieValue(request, "cartList", true);
    // 登录
    if (!username.equals("anonymousUser")) {
      //登录
       cartList = cartService.findRedisCartList(username);    
       return cartList;
    } 
    //未登录
    // 判断集合是否存在值
    if (StringUtils.isBlank(cartListStr)) {
      cartListStr = "[]";
    }
    // 把购物车字符串转换成对象
    cartList = JSON.parseArray(cartListStr, Cart.class);  
    return cartList;
  }

修改 addGoodsToCartList 方法

@RequestMapping("addGoodsToCartList")
  @CrossOrigin(origins="http://item.pinyougou.com",allowCredentials="true")
  public PygResult addGoodsToCartList(String itemId, Integer num,
      HttpServletRequest request, HttpServletResponse response) {
    try {
      itemId = itemId.replace(",", "");
      // 获取用户登录身份信息
      String username = SecurityContextHolder.getContext()
          .getAuthentication().getName();
      // 查询购物车列表
      List<Cart> cartList = this.findCartList(request);
      // 添加购物车
      cartList = cartService.addGoodsToCartList(cartList, Long.parseLong(itemId), num);
      // 判断用户是否处于登录状态
      if (username.equals("anonymousUser")) {
        // 未登录
        CookieUtil.setCookie(request, response, "cartList",
            JSON.toJSONString(cartList), 46800, true);
      } else {
        // 登录
        cartService.saveCartListToRedisCart(cartList, username);
      }
      return new PygResult(true, "购物车添加成功");
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      return new PygResult(false, "购物车添加失败");
    }
  }
跳板页

(1)创建跳板页:pinyougou-cart-web 工程新建 login.html ,页面添加脚本

<script type="text/javascript">
  location.href="cart.html";
</script>

(2)购物车页面链接到跳板页

请<a href="login.html">登录</a>

购物车合并

服务接口层

pinyougou-cart-interface 工程的 CartService.java 定义方法

/**
   * 需求:合并购物车数据
   * @param username
   * @param cartListStr
   */
  List<Cart> mergeCart(String username, String cartListStr);
服务实现层

pinyougou-cart-service 工程 CartServiceImpl.java 实现方法

/**
   * 需求:合并购物车数据
   * 
   * @param username
   * @param cartListStr
   */
  public List<Cart> mergeCart(String username, String cartListStr) {
    // 根据用户名查询所有购物车数据
    List<Cart> cartList1 = (List<Cart>) redisTemplate.boundHashOps("cartList").get(username);
    // 把cookie购物车数据转换集合
    List<Cart> cartList2 = JSON.parseArray(cartListStr, Cart.class);
    //循环redis购物车
    for (Cart cart : cartList2) {
      //获取当前商家列表
      List<TbOrderItem> orderItemList = cart.getOrderItemList();
      //循环
      for (TbOrderItem tbOrderItem : orderItemList) {
        //返回合并后redis购物车集合
        cartList1 = this.addGoodsToCartList(cartList1, tbOrderItem.getItemId(), tbOrderItem.getNum());
      }
    }
    return cartList1;
  }
控制层

修改 pinyougou-cart-web 工程 CartController 类的 findCartList 方法

/**
   * 需求:查询购物车列表
   * 
   * @return
   */
  @RequestMapping("/findCartList")
  public List<Cart> findCartList(HttpServletRequest request) {
    // 判断用户此时是否处于登录状态
    // 获取用户名
    String username = SecurityContextHolder.getContext()
        .getAuthentication().getName();
    //定义集合
    List<Cart> cartList = null;
    // 查询cookie购物车数据
    String cartListStr = CookieUtil.getCookieValue(request, "cartList", true);
    // 登录
    if (!username.equals("anonymousUser")) {
      //判断cookie购物车不为空,合并
      if(StringUtils.isNotBlank(cartListStr)){
        //合并购物车
        cartList =  cartService.mergeCart(username,cartListStr);
      }
      //登录
       cartList = cartService.findRedisCartList(username);    
       return cartList;
    } 
    //未登录
    // 判断集合是否存在值
    if (StringUtils.isBlank(cartListStr)) {
      cartListStr = "[]";
    }
    // 把购物车字符串转换成对象
    cartList = JSON.parseArray(cartListStr, Cart.class);  
    return cartList;
  }


目录
相关文章
|
2月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
214 2
|
2月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
128 6
|
3月前
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
1月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
107 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
27天前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
3月前
|
NoSQL Redis
Lua脚本协助Redis分布式锁实现命令的原子性
利用Lua脚本确保Redis操作的原子性是分布式锁安全性的关键所在,可以大幅减少由于网络分区、客户端故障等导致的锁无法正确释放的情况,从而在分布式系统中保证数据操作的安全性和一致性。在将这些概念应用于生产环境前,建议深入理解Redis事务与Lua脚本的工作原理以及分布式锁的可能问题和解决方案。
147 8
|
3月前
|
存储 缓存 NoSQL
Redis 核心知识与项目实践解析
本文围绕 Redis 展开,涵盖其在项目中的应用(热点数据缓存、存储业务数据、实现分布式锁)、基础数据类型(string 等 5 种)、持久化策略(RDB、AOF 及混合持久化)、过期策略(惰性 + 定期删除)、淘汰策略(8 种分类)。 还介绍了集群方案(主从复制、哨兵、Cluster 分片)及主从同步机制,分片集群数据存储的哈希槽算法。对比了 Redis 与 Memcached 的区别,说明了内存用完的情况及与 MySQL 数据一致性的保证方案。 此外,详解了缓存穿透、击穿、雪崩的概念及解决办法,如何保证 Redis 中是热点数据,Redis 分布式锁的实现及问题解决,以及项目中分布式锁
|
4月前
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
1119 7
|
5月前
|
NoSQL 算法 安全
redis分布式锁在高并发场景下的方案设计与性能提升
本文探讨了Redis分布式锁在主从架构下失效的问题及其解决方案。首先通过CAP理论分析,Redis遵循AP原则,导致锁可能失效。针对此问题,提出两种解决方案:Zookeeper分布式锁(追求CP一致性)和Redlock算法(基于多个Redis实例提升可靠性)。文章还讨论了可能遇到的“坑”,如加从节点引发超卖问题、建议Redis节点数为奇数以及持久化策略对锁的影响。最后,从性能优化角度出发,介绍了减少锁粒度和分段锁的策略,并结合实际场景(如下单重复提交、支付与取消订单冲突)展示了分布式锁的应用方法。
382 3
|
5月前
|
存储 NoSQL Java
从扣减库存场景来讲讲redis分布式锁中的那些“坑”
本文从一个简单的库存扣减场景出发,深入分析了高并发下的超卖问题,并逐步优化解决方案。首先通过本地锁解决单机并发问题,但集群环境下失效;接着引入Redis分布式锁,利用SETNX命令实现加锁,但仍存在死锁、锁过期等隐患。文章详细探讨了通过设置唯一标识、续命机制等方法完善锁的可靠性,并最终引出Redisson工具,其内置的锁续命和原子性操作极大简化了分布式锁的实现。最后,作者剖析了Redisson源码,揭示其实现原理,并预告后续关于主从架构下分布式锁的应用与性能优化内容。
259 0

热门文章

最新文章