设计者联盟官网南昌网优化seo公司
我们平时在网上购物,一般都会有购物车,支持买多件商品,每个商品可以买不同数量。
购物车常见实现方式:
(1)、存储到数据库:性能存在瓶颈。
(2)、后端存储到缓存如redis:支持高性能处理,可以开启AOF持久化防止重启丢失。
购物车数据结构介绍:
购物车结构是一个双层Map,Map<String,Map<String,String>>,第一层Map,Key是用户id;第二层Map,Key是购物车中商品id,值是购物车数据。
所以今天我们使用redis的Hash结构来实现购物车,包括添加、查看和清空!
首先我们要准备相关类和数据准备。
VideoDO类:
public class VideoDO {private int id;private String title;private String img;private int price;public VideoDO() {}public VideoDO(int id, String title, String img, int price) {this.id = id;this.title = title;this.img = img;this.price = price;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getImg() {return img;}public void setImg(String img) {this.img = img;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}
}
CartItemVO类(购物项):
public class CartItemVO {//商品idprivate Integer productId;//购买数量private Integer buyNum;//商品标题private String productTitle;//图片private String productImg;//商品单价private int price ;//总价格,单价+数量private int totalPrice;public int getProductId() {return productId;}public void setProductId(int productId) {this.productId = productId;}public Integer getBuyNum() {return buyNum;}public void setBuyNum(Integer buyNum) {this.buyNum = buyNum;}public String getProductTitle() {return productTitle;}public void setProductTitle(String productTitle) {this.productTitle = productTitle;}public String getProductImg() {return productImg;}public void setProductImg(String productImg) {this.productImg = productImg;}/*** 商品单价 * 购买数量* @return*/public int getTotalPrice() {return this.price*this.buyNum;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public void setTotalPrice(int totalPrice) {this.totalPrice = totalPrice;}
}
CartVO类(购物车):
public class CartVO {//购物项private List<CartItemVO> cartItems;//购物车总价格private Integer totalAmount;//总价格public int getTotalAmount() {return cartItems.stream().mapToInt(CartItemVO::getTotalPrice).sum();}public List<CartItemVO> getCartItems() {return cartItems;}public void setCartItems(List<CartItemVO> cartItems) {this.cartItems = cartItems;}
}
数据源层(这里我们为了方便实现,我们省略service层):
@Repository
public class VideoDao {private static Map<Integer, VideoDO> map = new HashMap<>();static {map.put(1,new VideoDO(1,"综合项目实战","hhhh",1000));map.put(2,new VideoDO(2,"RabbitMQ实战","llll",479));map.put(3,new VideoDO(3,"Java基础","xxxx",449));map.put(4,new VideoDO(4,"玩转Nginx","yyyy",549));map.put(5,new VideoDO(5,"ssm课程","oooo",649));map.put(6,new VideoDO(6,"SpringCloud实战","zzzz",559));}// 模拟从数据库找public VideoDO findDetailById(int videoId) {return map.get(videoId);}
}
json工具类:
public class JsonUtil {// 定义jackson对象private static final ObjectMapper MAPPER = new ObjectMapper();/*** 将对象转换成json字符串。* @return*/public static String objectToJson(Object data) {try {String string = MAPPER.writeValueAsString(data);return string;} catch (Exception e) {e.printStackTrace();}return null;}/*** 将json结果集转化为对象* @param jsonData json数据* @param beanType 对象中的object类型* @return* @param <T>*/public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {try {T t = MAPPER.readValue(jsonData, beanType);return t;} catch (Exception e) {e.printStackTrace();}return null;}
}
准备工作做好啦,下面我们来实现添加购物车接口的开发:
@RestController
@RequestMapping("/api/v1/cart")
public class CartController {@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate VideoDao videoDao;@RequestMapping("add")//一般我们添加购物车需要商品的id和购买的数量public JsonData addCart(int videoId,int buyNum){//获取购物车BoundHashOperations<String, Object, Object> myCart = getMyCartOps();//+“”是为了将videoId变成字符串Object cacheObj = myCart.get(videoId+"");//购物车没有这个商品if(cacheObj == null){CartItemVO cartItemVO = new CartItemVO();VideoDO videoDO = videoDao.findDetailById(videoId);cartItemVO.setBuyNum(buyNum);cartItemVO.setProductId(videoId);cartItemVO.setPrice(videoDO.getPrice());cartItemVO.setProductImg(videoDO.getImg());cartItemVO.setProductTitle(videoDO.getTitle());myCart.put(videoId+"", JsonUtil.objectToJson(cartItemVO));}else {//购物车有这个商品,增加商品购买数量String result = (String) cacheObj;CartItemVO cartItemVO = JsonUtil.jsonToPojo(result, CartItemVO.class);cartItemVO.setBuyNum(cartItemVO.getBuyNum()+buyNum);myCart.put(videoId+"", JsonUtil.objectToJson(cartItemVO));}return JsonData.buildSuccess();}// 抽取我的购物车通用方法private BoundHashOperations<String,Object,Object> getMyCartOps(){String key = getCartKey();return redisTemplate.boundHashOps(key);}//获取购物车的keyprivate String getCartKey(){//用户的id,一般从拦截器获取,这里为了方便,写死即可,每个用户不一样int userId = 66;String cartKey = String.format("video:cart:%s",userId);return cartKey;}
}
我们去浏览器输入http://localhost:8080/api/v1/cart/add?videoId=1&buyNum=2,我们可以去redis可视化查看到视频商品id是1的,购买数量是2件,总价格是2000。
我们再次访问http://localhost:8080/api/v1/cart/add?videoId=1&buyNum=2这个网址,视频商品id是1的,购买数量变成4件,总价格变成4000。
下面我们就来实现查看我的购物车接口开发:
/*** 查看我的购物车* @return*/@RequestMapping("myCart")public JsonData getMyCart(){//获取购物车BoundHashOperations<String, Object, Object> myCart = getMyCartOps();List<Object> itemList = myCart.values();List<CartItemVO> cartItemVOList = new ArrayList<>();for(Object item : itemList){CartItemVO cartItemVO = JsonUtil.jsonToPojo((String) item,CartItemVO.class);cartItemVOList.add(cartItemVO);}CartVO cartVO = new CartVO();cartVO.setCartItems(cartItemVOList);return JsonData.buildSuccess(cartVO);}
当我们去访问该接口时,就可以查询到我的购物车有什么商品。
最后我们来开发一下清空购物车:
/*** 清空我的购物车* @return*/@RequestMapping("clear")public JsonData clear(){String key = getCartKey();redisTemplate.delete(key);return JsonData.buildSuccess();}
清空购物车之后查看我的购物车就是空的。