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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
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;
  }


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
18天前
|
缓存 NoSQL 搜索推荐
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
本文介绍了如何通过Lua脚本在Redis中实现分布式锁的原子性操作,避免并发问题。首先讲解了Lua脚本的基本概念及其在Redis中的使用方法,包括通过`eval`指令执行Lua脚本和通过`script load`指令缓存脚本。接着详细展示了如何用Lua脚本实现加锁、解锁及可重入锁的功能,确保同一线程可以多次获取锁而不发生死锁。最后,通过代码示例演示了如何在实际业务中调用这些Lua脚本,确保锁操作的原子性和安全性。
48 6
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
|
19天前
|
NoSQL Java 中间件
【📕分布式锁通关指南 02】基于Redis实现的分布式锁
本文介绍了从单机锁到分布式锁的演变,重点探讨了使用Redis实现分布式锁的方法。分布式锁用于控制分布式系统中多个实例对共享资源的同步访问,需满足互斥性、可重入性、锁超时防死锁和锁释放正确防误删等特性。文章通过具体示例展示了如何利用Redis的`setnx`命令实现加锁,并分析了简化版分布式锁存在的问题,如锁超时和误删。为了解决这些问题,文中提出了设置锁过期时间和在解锁前验证持有锁的线程身份的优化方案。最后指出,尽管当前设计已解决部分问题,但仍存在进一步优化的空间,将在后续章节继续探讨。
459 131
【📕分布式锁通关指南 02】基于Redis实现的分布式锁
|
23天前
|
NoSQL Java Redis
Springboot使用Redis实现分布式锁
通过这些步骤和示例,您可以系统地了解如何在Spring Boot中使用Redis实现分布式锁,并在实际项目中应用。希望这些内容对您的学习和工作有所帮助。
152 83
|
1月前
|
安全 开发工具 git
git分布式版本控制系统及在码云上创建项目并pull和push
通过本文的介绍,我们详细讲解了Git的基本概念和工作流程,并展示了如何在码云上创建项目及进行pull和push操作。Git作为一种分布式版本控制系统,为开发者提供了强大的工具来管理代码变更和协作开发。希望本文能帮助您更好地理解和使用Git及码云,提高开发效率和代码质量。
38 16
|
1月前
|
安全 开发工具 git
git分布式版本控制系统及在码云上创建项目并pull和push
通过本文的介绍,我们详细讲解了Git的基本概念和工作流程,并展示了如何在码云上创建项目及进行pull和push操作。Git作为一种分布式版本控制系统,为开发者提供了强大的工具来管理代码变更和协作开发。希望本文能帮助您更好地理解和使用Git及码云,提高开发效率和代码质量。
48 18
|
1月前
|
缓存 NoSQL 中间件
Redis,分布式缓存演化之路
本文介绍了基于Redis的分布式缓存演化,探讨了分布式锁和缓存一致性问题及其解决方案。首先分析了本地缓存和分布式缓存的区别与优劣,接着深入讲解了分布式远程缓存带来的并发、缓存失效(穿透、雪崩、击穿)等问题及应对策略。文章还详细描述了如何使用Redis实现分布式锁,确保高并发场景下的数据一致性和系统稳定性。最后,通过双写模式和失效模式讨论了缓存一致性问题,并提出了多种解决方案,如引入Canal中间件等。希望这些内容能为读者在设计分布式缓存系统时提供有价值的参考。感谢您的阅读!
130 6
Redis,分布式缓存演化之路
|
2月前
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
164 36
|
3月前
|
存储 消息中间件 监控
Redis Stream:实时数据流的处理与存储
通过上述分析和具体操作示例,您可以更好地理解和应用 Redis Stream,满足各种实时数据处理需求。
126 14
|
3月前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
218 26
|
3月前
|
存储 NoSQL Java
使用lock4j-redis-template-spring-boot-starter实现redis分布式锁
通过使用 `lock4j-redis-template-spring-boot-starter`,我们可以轻松实现 Redis 分布式锁,从而解决分布式系统中多个实例并发访问共享资源的问题。合理配置和使用分布式锁,可以有效提高系统的稳定性和数据的一致性。希望本文对你在实际项目中使用 Redis 分布式锁有所帮助。
250 5