本文共 14635 字,大约阅读时间需要 48 分钟。
redis是一款开源的、功能强大、支持多种数据类型、高性能的键值对存储数据库。
redis支持的数据类型有:将购物车数据存放到Redis中,可以加快购物车的读写性能,从而提高用户体验,缺点就是Redis数据是存放到内存,相对成本较高。但是这个成本,一般企业都可以接受。
一般情况下购物车功能都是使用session/cookie实现的,也就是将整个购物车数据都存储到session中。这样做的好处就是不用操作数据库就可以实现,同时用户可以不同登录就可以将商品加入到购物车中,缺点就是1. 导致session过于臃肿 2. session数据默认是存储到文件中的,所以操作session是相对比较慢的。
/* Created by IntelliJ IDEA. User: Kalvin Date: 2020/5/13 Time: 14:21*/package com.lianwei.lssg.cache;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;import java.util.Map;import java.util.Set;import java.util.concurrent.TimeUnit;@Componentpublic class JedisClient { @Autowired private StringRedisTemplate redisTemplate; // Key(键),简单的key-value操作 /** * 实现命令:TTL key,以秒为单位,返回给定 key的剩余生存时间(TTL, time to live)。 * * @param key * @return */ public long ttl(String key) { return redisTemplate.getExpire(key); } /** * 实现命令:expire 设置过期时间,单位秒 * * @param key * @return */ public void expire(String key, long timeout) { redisTemplate.expire(key, timeout, TimeUnit.SECONDS); } /** * 实现命令:INCR key,增加key一次 * * @param key * @return */ public long incr(String key, long delta) { return redisTemplate.opsForValue().increment(key, delta); } /** * 实现命令:KEYS pattern,查找所有符合给定模式 pattern的 key */ public Setkeys(String pattern) { return redisTemplate.keys(pattern); } /** * 实现命令:DEL key,删除一个key * * @param key */ public void del(String key) { redisTemplate.delete(key); } // String(字符串) /** * 实现命令:SET key value,设置一个key-value(将字符串值 value关联到 key) * * @param key * @param value */ public void set(String key, String value) { redisTemplate.opsForValue().set(key, value); } /** * 实现命令:SET key value EX seconds,设置key-value和超时时间(秒) * * @param key * @param value * @param timeout * (以秒为单位) */ public void set(String key, String value, long timeout) { redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); } /** * 实现命令:GET key,返回 key所关联的字符串值。 * * @param key * @return value */ public String get(String key) { return (String)redisTemplate.opsForValue().get(key); } // Hash(哈希表) /** * 实现命令:HEXISTS key field,查找哈希表中是否包含指定键值对 key中给定域 field的值 * @param key * @param field * @return */ public Boolean hexists(String key, String field){ return redisTemplate.opsForHash().hasKey(key, field); } /** * 实现命令:HSET key field value,将哈希表 key中的域 field的值设为 value * * @param key * @param field * @param value */ public void hset(String key, String field, Object value) { redisTemplate.opsForHash().put(key, field, value); } /** * 实现命令:HGET key field,返回哈希表 key中给定域 field的值 * * @param key * @param field * @return */ public String hget(String key, String field) { return (String) redisTemplate.opsForHash().get(key, field); } /** * 实现命令:HDEL key field [field ...],删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。 * * @param key * @param fields */ public void hdel(String key, Object... fields) { redisTemplate.opsForHash().delete(key, fields); } /** * 实现命令:HGETALL key,返回哈希表 key中,所有的域和值。 * * @param key * @return */ public Map
在redis数据库中我们使用cart作为filed 以用户名作为key 购物车内容为value
/* Created by IntelliJ IDEA. User: Kalvin Date: 2020/5/12 Time: 17:41*/package com.lianwei.lssg.controller.before;import com.alibaba.fastjson.JSON;import com.lianwei.lssg.cache.JedisClient;import com.lianwei.lssg.entity.LssgCart;import com.lianwei.lssg.entity.LssgCartItem;import com.lianwei.lssg.entity.LssgProduct;import com.lianwei.lssg.service.before.LssgProductService;import org.apache.shiro.SecurityUtils;import org.apache.shiro.subject.Subject;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import javax.annotation.Resource;import java.math.BigDecimal;import java.util.HashMap;import java.util.Map;import java.util.Set;@Controller@RequestMapping("cart")public class CartController { @Resource private JedisClient jedisClient; @Resource private LssgProductService lssgProductService; private static final String REDIS_CART = "cart"; /** * 商品加入到购物车 * */ @RequestMapping("/addProductToCart") @ResponseBody public LssgCart addProductToCart(@RequestParam("productId")Integer productId, @RequestParam(value = "nums",required = false)String nums){ //获取已登录的用户信息 Subject subject = SecurityUtils.getSubject(); String userLoginName = (String)subject.getPrincipal(); LssgProduct lssgProduct = lssgProductService.selectOneProductByProductId(productId); /** * 判断lssgProduct是否为空 * */ String productNumState; if(lssgProduct.getProductNum()<=0){ productNumState = "无货"; }else { productNumState = "有货"; } /** * 存在一个问题:当session超时后因该强制用户进行登入,只有登入成功才能做相应的操作 * */ if(("").equals(userLoginName)){ System.out.println("session超时了"); /*map.put("lssg",false);*/ return null; } Boolean hexists = jedisClient.hexists(REDIS_CART, userLoginName); System.out.println("hexists---->"+hexists); LssgCart lssgCart = null; if(nums==null|| nums.equals("")){ nums = String.valueOf(1); } BigDecimal num =new BigDecimal(nums); if(!hexists){ lssgCart = new LssgCart(); LssgCartItem lssgCartItem = new LssgCartItem(lssgProduct,num,lssgProduct.getProductMallPrice(),productNumState); lssgCartItem.setSubtotalPrice((lssgProduct.getProductMallPrice()).multiply(lssgCartItem.getBuyNum())); MaplssgCartItemMap = new HashMap (); lssgCartItemMap.put(String.valueOf(lssgProduct.getProductId()),lssgCartItem); lssgCart.setCartItems(lssgCartItemMap); lssgCart.setTotalPrice(lssgCartItem.getSubtotalPrice()); }else { lssgCart = JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); if(lssgCart.getCartItems().containsKey(String.valueOf(lssgProduct.getProductId()))){ LssgCartItem lssgCartItem = lssgCart.getCartItems().get(String.valueOf(lssgProduct.getProductId())); //数量 lssgCartItem.setBuyNum(lssgCartItem.getBuyNum().add(num)); //小计+商品的单价(由于是BigDecimal类型所以用他自己封装好的) lssgCartItem.setSubtotalPrice((lssgProduct.getProductMallPrice()).multiply(lssgCartItem.getBuyNum())); lssgCart.getCartItems().put(String.valueOf(lssgProduct.getProductId()),lssgCartItem); }else{ //没买过,先创建新的购物项 LssgCartItem lssgCartItem = new LssgCartItem(lssgProduct,num,lssgProduct.getProductMallPrice(),productNumState); lssgCartItem.setSubtotalPrice((lssgProduct.getProductMallPrice()).multiply(lssgCartItem.getBuyNum())); //存入购物车的Map集合 lssgCart.getCartItems().put(String.valueOf(lssgProduct.getProductId()),lssgCartItem); } //计算总价格,并加入到购物车 BigDecimal sum = new BigDecimal("0.00"); Set ks = lssgCart.getCartItems().keySet(); for(String key: ks){ LssgCartItem lssgCartItem = lssgCart.getCartItems().get(key); sum = sum.add(((lssgCartItem.getLssgProduct().getProductMallPrice()).multiply(lssgCartItem.getBuyNum()))); } lssgCart.setTotalPrice(sum); } jedisClient.hset(REDIS_CART,userLoginName, JSON.toJSONString(lssgCart)); System.out.println("添加成功!"); jedisClient.hget(REDIS_CART,userLoginName); return JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); } /** *购物车信息展示到前台购物车页 * */ @RequestMapping("/fromCartShowProduct") @ResponseBody public LssgCart fromCartShowProduct(){ //获取已登录的用户信息 Subject subject = SecurityUtils.getSubject(); String userLoginName = (String) subject.getPrincipal(); /** * 存在一个问题:当session超时后因该强制用户进行登入,只有登入成功才能做相应的操作 * */ if(("").equals(userLoginName)){ System.out.println("session超时了"); /*map.put("lssg",false);*/ return null; } Boolean hexists = jedisClient.hexists(REDIS_CART, userLoginName); if(hexists){ return JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); } return null; } /** * 实现购物车页面通过+/-/输入 按钮来对商品的数量更新操作 * */ @RequestMapping("/updateCartProductNum") @ResponseBody public LssgCart decCartProductNum(@RequestParam("productId")Integer productId, @RequestParam("nums")String nums){ //获取已登录的用户信息 Subject subject = SecurityUtils.getSubject(); String userLoginName = (String) subject.getPrincipal(); LssgCart lssgCart = JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); Map lssgCartItemMap = lssgCart.getCartItems(); LssgCartItem lssgCartItem = lssgCartItemMap.get(String.valueOf(productId)); //购物项(该商品)原来的小计 BigDecimal oldSubtotalPrice = lssgCartItem.getSubtotalPrice(); System.out.println("oldSubtotalPrice--->"+oldSubtotalPrice); BigDecimal num =new BigDecimal(nums); //更新购买数量 lssgCartItem.setBuyNum(num); //更新小计 lssgCartItem.setSubtotalPrice((lssgCartItem.getBuyNum()).multiply(lssgCartItem.getLssgProduct().getProductMallPrice())); //把购物项放到购物项(map)集合里 lssgCartItemMap.put(String.valueOf(productId),lssgCartItem); lssgCart.setCartItems(lssgCartItemMap); //更新购物车总价 新的购物车总价 = 原来购物车总价 - 原来购物项的小计 + 新的购物项的小计 lssgCart.setTotalPrice(lssgCart.getTotalPrice().subtract(oldSubtotalPrice).add(lssgCartItem.getSubtotalPrice())); //更新购物车到redis jedisClient.hset(REDIS_CART,userLoginName,JSON.toJSONString(lssgCart)); //从redis中取出购物车传到到前台 return JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); } /** * 删除购物车中某一个购物项 * */ @RequestMapping("/delCartProduct") @ResponseBody public LssgCart delCartProduct(@RequestParam("productId")Integer productId, @RequestParam("nums")String nums){ //获取已登录的用户信息 Subject subject = SecurityUtils.getSubject(); String userLoginName = (String) subject.getPrincipal(); LssgCart lssgCart = JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); Map lssgCartItemMap = lssgCart.getCartItems(); LssgCartItem lssgCartItem = lssgCartItemMap.get(String.valueOf(productId)); BigDecimal num =new BigDecimal(nums); System.out.println("num---->"+num); //通过商品id删除该购物项 lssgCartItemMap.remove(String.valueOf(productId)); //更新总价 新的购物车总价 = 原来购物车总价 - 原来购物项的小计 lssgCart.setTotalPrice(lssgCart.getTotalPrice().subtract(((lssgCartItem.getLssgProduct().getProductMallPrice()).multiply(num)))); //更新购物车到redis jedisClient.hset(REDIS_CART,userLoginName,JSON.toJSONString(lssgCart)); //从redis中取出购物车传到到前台 return JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); } /** * 清空购物车 * */ @RequestMapping("/emptyCart") public void emptyCart(){ //获取已登录的用户信息 Subject subject = SecurityUtils.getSubject(); String userLoginName = (String) subject.getPrincipal(); jedisClient.hdel(REDIS_CART,userLoginName); } /** *删除已结算的购物项 * */ @RequestMapping("/delProductByProductIds") @ResponseBody public LssgCart delProductByProductIds(@RequestParam(value="productIds[]")String[] productIds){ //获取已登录的用户信息 Subject subject = SecurityUtils.getSubject(); String userLoginName = (String) subject.getPrincipal(); LssgCart lssgCart = JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); BigDecimal delTotalPrice =new BigDecimal("0.00"); Map lssgCartItemMap = lssgCart.getCartItems(); for(String productId : productIds){ LssgCartItem lssgCartItem = lssgCartItemMap.get(productId); // MySQL数据库中商品加上相对应的库存量 delTotalPrice = delTotalPrice.add(lssgCartItem.getSubtotalPrice()); //通过商品id删除该购物项 lssgCartItemMap.remove(productId); } //更新总价 新的购物车总价 = 原来购物车总价 - 要结算购物项的小计 lssgCart.setTotalPrice(lssgCart.getTotalPrice().subtract(delTotalPrice)); //更新购物车到redis jedisClient.hset(REDIS_CART,userLoginName,JSON.toJSONString(lssgCart)); //从redis中取出购物车传到到前台 return JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); } /** * 统计购物车中的购物项 * */ @RequestMapping("/countCartItme") @ResponseBody public Integer countCartItme(){ //获取已登录的用户信息 Subject subject = SecurityUtils.getSubject(); String userLoginName = (String) subject.getPrincipal(); LssgCart lssgCart = JSON.parseObject(jedisClient.hget(REDIS_CART,userLoginName),LssgCart.class); if(lssgCart==null){ return 0; } return lssgCart.getCartItems().size(); }}
在lssgCartItemMap.put(String.valueOf(lssgProduct.getProductId()),lssgCartItem);中我们把商品ID作为购物项集合lssgCartItemMap的key
转载地址:http://fnuzi.baihongyu.com/