目录

项目介绍

开发配置

开发流程

购物车业务流程

开发流程

1、项目结构

2、数据层(DAO)

3、数据层(POJO、VO)

4、Redis配置层

5、服务层(Service)

6、控制层(Controller)

总结


项目介绍

最近在做一个网上购物商城的项目,而我主要负责该项目的购物车功能模块,购物车模块主要涉及到的功能有添加商品到购物车中,修改购物车中商品的数量,查询购物车中的商品,删除购物车中的商品等。


开发配置

  • Java版本:JDK1.8.0
  • 服务器版本:Tomcat8.5
  • 数据库:Oracle Redis
  • 开发框架:Spring Boot, MyBatis, apache-maven-3.6.1
  • 开发工具:STS4

开发流程

购物车业务流程

开发流程

概要设计

本模块主要分为数据层(DAO)、数据对象(POJO、VO)、Redis配置层、服务层(ServiceImpl)、控制层(Controller)以及前端页面。下面分别介绍各个模块:

1、项目结构

2、数据层(DAO)

Dao层文件主要用于定义购物车中商品的增删改查接口,服务层通过该层调用框架底层的代理从数据库中进行数据操作

CartServiceDao.java中主要定义了5个数据接口,分别对应购物车中的添加商品、删除商品、查询商品、商品数量加1、商品数量减1

package com.chen.dao;import java.util.List;import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;import com.chen.pojo.ShoppingCar;/*** @author Dragon_Kater**/
@Mapper
public interface CartServiceDao {@Insert("insert into cms_shopcar(id,user_id,product_id,product_amount,seller_id) values(#{id},#{userId},#{productId},#{productAmount},#{sellerId})")public int addCart(ShoppingCar shoppingCar);@Select("select * from cms_shopcar where user_id=#{userId}")public List<ShoppingCar> findAllProduct(Integer userId);@Update("update cms_shopcar set product_amount = product_amount + 1 where user_id=#{userId} and product_id=#{productId}")public int productAmountASC(Integer userId, Integer productId);@Update("update cms_shopcar set product_amount = product_amount - 1 where user_id=#{userId} and product_id=#{productId}")public int productAmountDESC(Integer userId, Integer productId);@Delete("delete from cms_shopcar where user_id=#{userId} and product_id=#{productId}")public int delCartProduct(Integer userId, Integer productId);
}

ProductInfoDao.java主要功能是根据商品id从商品表中查询商品的信息

package com.chen.dao;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import com.chen.pojo.ProductInfo;/*** @author Dragon_Kater**/
@Mapper
public interface ProductInfoDao {@Select("select * from os_product where id=#{id}")public ProductInfo findProductById(Integer id);
}

3、数据层(POJO、VO)

ShoppingCar.java主要用于存储购物车信息

package com.chen.pojo;import java.io.Serializable;import lombok.Data;/*** @author Dragon_Kater*/
@Data
public class ShoppingCar implements Serializable {private static final long serialVersionUID = 7123687508750315545L;private Integer id;                    //购物车idprivate Integer userId;              //用户idprivate Integer productId;            //商品idprivate Integer productAmount;        //商品数量private Integer sellerId;         //卖家id
}

ProductInfo.java用于存储商品信息

package com.chen.pojo;import java.io.Serializable;
import java.util.Date;import lombok.Data;/*** @author Dragon_Kater**/
@Data
public class ProductInfo implements Serializable {private static final long serialVersionUID = 3736494058827285316L;private Integer id;// 货号private String name;// 商品名private String brand;// 品牌private Double price;// 价格private String special;// 有无特典private String vendingType;// 类型(现货,预定)private Integer smallCate;// 商品类别private Integer stock;// 库存private String roleName;// 角色名private String workName;// 作品名private String author;// 作者private String facilitators;// 协力制作private String color;// 颜色涂装private String producer;// 生产商private String distributor;// 销售商private String copyright;// 版权private String ratio;// 比例private String box;// 盒private Date registerDate;// 上架日期private Date releaseDate;// 发售日期private String description;// 商品说明private String seller;// 卖家
}

ShoppingCarVo.java用于存储前端页面用户看到的购物车信息

package com.chen.common;import java.io.Serializable;import com.chen.pojo.ShoppingCar;import lombok.Data;/*** @author Dragon_Kater**/
@Data
public class ShoppingCarVo implements Serializable {private static final long serialVersionUID = 2616783859683578863L;private String productName;          //商品名称private String imgUrl;                //商品图片路径private ShoppingCar shoppingCar;    //购物车信息
}

JsonResult.java用于封装后台处理的数据,后台将处理后的数据封装到Json对象中,返回给前端处理

package com.chen.common;import java.io.Serializable;import lombok.Data;/*** @author Dragon_Kater**/
@Data
public class JsonResult implements Serializable {private static final long serialVersionUID = 2944384082936622509L;private Integer state = 1;private String message = "ok";private Object data;public JsonResult() { }public JsonResult(String message) { this.message = message;}public JsonResult(Object data) {this.data = data;}public JsonResult(Throwable t){this.state = 0;this.message = t.getMessage();}
}

4、Redis配置层 

RedisConfig.java用于存储从配置文件中读取到的Redis参数

package com.chen.redis;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import lombok.Data;/*** @author Dragon_Kater**/
@Component
@ConfigurationProperties(prefix = "redis")  //读取配置文件中redis相关参数
@Data
public class RedisConfig {private String host;private int port;private int timeout;private int poolMaxIdle;private int poolMaxWait;
}

RedisPoolFactory.java用于配置JedisPool相关信息

package com.chen.redis;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;/*** @author Dragon_Kater**/
@Configuration
public class RedisPoolFactory {@Autowiredprivate RedisConfig  redisConfig;@Beanpublic JedisPool jedisFactoryPool() {JedisPoolConfig config = new JedisPoolConfig();config.setMaxIdle(redisConfig.getPoolMaxIdle());config.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);config.setTestOnBorrow(true); JedisPool jp = new JedisPool(config, "127.0.0.1", 6379, redisConfig.getTimeout(), null, 0);return jp;}
}

Redis文件夹下的KeyPrefix.java、CartPrefix.java、BasePrefix.java主要用于生成存入Redis中的唯一键,防止存入重复的键

5、服务层(Service)

RedisService.java用于从Redis中存数据、取数据、根据键判断对应的值是否存在等功能

package com.chen.service;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.alibaba.fastjson.JSON;
import com.chen.redis.KeyPrefix;import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;/*** redis服务* @author Dragon_Kater*/
@Service
public class RedisService {@Autowiredprivate JedisPool jedisPool;/***  从redis连接池获取redis实例* @param prefix* @param key* @param clazz* @param <T>* @return*/public <T> T get(KeyPrefix prefix,String key, Class<T> clazz){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();//对key增加前缀,可用于分类,避免key重复String realKey = prefix.getPrefix() + key;String str = jedis.get(realKey);T t = stringToBean(str,clazz);return t;}finally {returnToPool(jedis);}}/***     存储对象* @param prefix* @param key* @param value* @param <T>* @return*/public <T> Boolean set(KeyPrefix prefix,String key,T value){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String str = beanToString(value);if (str == null || str.length() <=0){return false;}String realKey = prefix.getPrefix() + key;int seconds = prefix.expireSeconds(); //获取过期时间if (seconds <= 0 ){jedis.set(realKey,str);}else {jedis.setex(realKey,seconds,str);}return true;}finally {returnToPool(jedis);}}/***  删除* @param prefix* @param key* @return*/public boolean delete(KeyPrefix prefix,String key){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realKey = prefix.getPrefix() + key;long ret = jedis.del(realKey);return ret>0;}finally {returnToPool(jedis);}}/***     判断key是否存在* @param prefix* @param key  用户id* @param <T>* @return*/public <T> boolean exists(KeyPrefix prefix,String key){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realKey = prefix.getPrefix() + key;return jedis.exists(realKey);}finally {returnToPool(jedis);}}/***  判断key对应的value是否存在* @param prefix* @param key  用户id* @param field 商品id* @return*/public boolean existsValue(KeyPrefix prefix,String key,String field){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realkey = prefix.getPrefix() + key;Boolean result = jedis.hexists(realkey,field);return result;}finally {returnToPool(jedis);}}/***     增加值* @param prefix* @param key* @param <T>* @return*/public <T> Long incr(KeyPrefix prefix,String key){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realKey = prefix.getPrefix()+key;return jedis.incr(realKey);}finally {returnToPool(jedis);}}/***   减少值* @param prefix* @param key* @param <T>* @return*/public <T> Long decr(KeyPrefix prefix,String key){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realKey = prefix.getPrefix()+key;return jedis.decr(realKey);}finally {returnToPool(jedis);}}/***   返回指定字段的值* @param prefix* @param key* @param filed* @param <T>* @return*/public <T> String hget(KeyPrefix prefix,String key,String filed){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realKey = prefix.getPrefix()+key;return jedis.hget(realKey,filed);}finally {returnToPool(jedis);}}/**** @param prefix* @param key* @param field* @param value* @param <T>* @return*/public<T> Long hset(KeyPrefix prefix,String key,String field,String value){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realKey = prefix.getPrefix()+key;return jedis.hset(realKey,field,value);}finally {returnToPool(jedis);}}/***     获取列表数值* @param prefix* @param key* @return*/@SuppressWarnings("resource")public List<String> hvals(KeyPrefix prefix,String key){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realKey = prefix.getPrefix()+key;return jedis.hvals(realKey);}finally {returnToPool(jedis);}}/***     删除值* @param prefix* @param key* @param field* @return*/@SuppressWarnings("resource")public Long hdel(KeyPrefix prefix,String key,String field){Jedis jedis = new Jedis();try {jedis = jedisPool.getResource();String realKey = prefix.getPrefix()+key;return jedis.hdel(realKey,field);}finally {returnToPool(jedis);}}public static <T> String beanToString(T value){if (value ==null){return null;}Class<?> clazz = value.getClass();if (clazz ==int.class || clazz ==Integer.class){return String.valueOf(value);}else if(clazz ==long.class || clazz == Long.class){return String.valueOf(value);}else if (clazz ==String.class){return (String) value;}else{return JSON.toJSONString(value);}}// 将string类型转换为实体类@SuppressWarnings("unchecked")public static <T> T stringToBean(String str,Class<T> clazz){if (str == null || str.length() <=0 || clazz==null){return null;}if (clazz ==int.class || clazz == Integer.class){return (T) Integer.valueOf(str);}else if(clazz == long.class || clazz ==Long.class){return (T) Long.valueOf(str);}else if (clazz == String.class){return (T) str;}else {return JSON.toJavaObject(JSON.parseObject(str),clazz);}}private void returnToPool(Jedis jedis){if(jedis != null){jedis.close();}}
}

CartServiceImpl.java 用于实现具体的购物车业务

package com.chen.service;import java.util.LinkedList;
import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chen.common.ShoppingCarVo;
import com.chen.dao.CartServiceDao;
import com.chen.dao.ProductInfoDao;
import com.chen.pojo.ProductInfo;
import com.chen.pojo.ShoppingCar;
import com.chen.redis.CartPrefix;/*** @author Dragon_Kater**/
@Service
public class CartServiceImpl implements CartServiceDao{@AutowiredRedisService redisService;@AutowiredProductInfoDao productInfoDao;@Autowiredprivate CartServiceDao cartServiceDao;/***  添加商品到购物车中*/@Overridepublic int addCart(ShoppingCar shoppingCar) {String userId = String.valueOf(shoppingCar.getUserId());String productId = String.valueOf(shoppingCar.getProductId());//key为 userId_cart,校验是否已存在Boolean exists = redisService.existsValue(CartPrefix.getCartList,userId,productId);if (exists){//获取现有的购物车中的数据String json = redisService.hget(CartPrefix.getCartList,userId,productId);if(json != null) {//转换为java实体类ShoppingCarVo shoppingCarVo = JSON.toJavaObject(JSONObject.parseObject(json),ShoppingCarVo.class);int num = shoppingCarVo.getShoppingCar().getProductAmount()+shoppingCar.getProductAmount();ShoppingCar shoppingCarNew = shoppingCarVo.getShoppingCar();shoppingCarNew.setProductAmount(num);shoppingCarVo.setShoppingCar(shoppingCarNew);redisService.hset(CartPrefix.getCartList,userId,productId,JSON.toJSON(shoppingCarVo).toString());} else {return 0;}return 1;}//根据商品id获取商品int id = shoppingCar.getProductId();ProductInfo productInfo = productInfoDao.findProductById(id);if(productInfo == null) {return 0;}//将数据封装到ShoppingCarVo对象中ShoppingCarVo shoppingCarVo = new ShoppingCarVo();shoppingCarVo.setShoppingCar(shoppingCar);shoppingCarVo.setImgUrl(null);shoppingCarVo.setProductName(productInfo.getName());//将ShoppingCarVo对象存放到Redis中redisService.hset(CartPrefix.getCartList,userId,productId,JSON.toJSON(shoppingCarVo).toString());return 1;}@Overridepublic List<ShoppingCar> findAllProduct(Integer userId){return cartServiceDao.findAllProduct(userId);}/***  展示购物车* @param userId 用户id* @return*/public List<ShoppingCarVo> findAllProducts(Integer userId) {String userID = String.valueOf(userId);List<ShoppingCarVo> cartList = new LinkedList<ShoppingCarVo>();//从Redis缓存中取数据List<String> jsonList = redisService.hvals(CartPrefix.getCartList,userID);if(jsonList != null) {for(String json : jsonList) {//将字符串对象转换成ShoppingCarVo对象ShoppingCarVo shoppingCarVo = JSON.toJavaObject(JSONObject.parseObject(json),ShoppingCarVo.class);cartList.add(shoppingCarVo);}} else {List<ShoppingCar> list = findAllProduct(userId);for (ShoppingCar shoppingCar : list) {Integer productId = shoppingCar.getProductId();ProductInfo productInfo = productInfoDao.findProductById(productId);String productName = productInfo.getName();String imgUrl = null;ShoppingCarVo shoppingCarVo = new ShoppingCarVo();shoppingCarVo.setShoppingCar(shoppingCar);shoppingCarVo.setProductName(productName);shoppingCarVo.setImgUrl(imgUrl);cartList.add(shoppingCarVo);}}return cartList;}@Overridepublic int productAmountASC(Integer userId, Integer productId) {String userID = String.valueOf(userId);String productID = String.valueOf(productId);String json = redisService.hget(CartPrefix.getCartList,userID,productID);if(json == null) {return 0;}ShoppingCarVo shoppingCarVo = JSON.toJavaObject(JSONObject.parseObject(json),ShoppingCarVo.class);int num = shoppingCarVo.getShoppingCar().getProductAmount() + 1;ShoppingCar shoppingCar = shoppingCarVo.getShoppingCar();shoppingCar.setProductAmount(num);shoppingCarVo.setShoppingCar(shoppingCar);redisService.hset(CartPrefix.getCartList,userID,productID,JSON.toJSON(shoppingCarVo).toString());return 1;}@Overridepublic int productAmountDESC(Integer userId, Integer productId) {String userID = String.valueOf(userId);String productID = String.valueOf(productId);String json = redisService.hget(CartPrefix.getCartList,userID,productID);if(json == null) {return 0;}ShoppingCarVo shoppingCarVo = JSON.toJavaObject(JSONObject.parseObject(json),ShoppingCarVo.class);int num = shoppingCarVo.getShoppingCar().getProductAmount() - 1;ShoppingCar shoppingCar = shoppingCarVo.getShoppingCar();shoppingCar.setProductAmount(num);shoppingCarVo.setShoppingCar(shoppingCar);redisService.hset(CartPrefix.getCartList,userID,productID,JSON.toJSON(shoppingCarVo).toString());return 1;}/***  删除商品* @param userId* @param productId* @return*/@Overridepublic int delCartProduct(Integer userId, Integer productId) {String userID = String.valueOf(userId);String productID = String.valueOf(productId);redisService.hdel(CartPrefix.getCartList,userID,productID);return 1;}}

6、控制层(Controller)

ShoppingCarController.java用于处理前端请求

package com.chen.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.chen.common.JsonResult;
import com.chen.pojo.ShoppingCar;
import com.chen.service.CartServiceImpl;/*** @author Dragon_Kate**/
@RestController
@RequestMapping("/shoppingcar/")
public class ShoppingCarController {@Autowiredprivate CartServiceImpl cartServiceImpl;@RequestMapping("doAddProduct")public JsonResult doAddProduct(ShoppingCar shoppingCar) {cartServiceImpl.addCart(shoppingCar);return new JsonResult("添加成功");}@RequestMapping("doFindAllProduct")public JsonResult doFindAllProduct(Integer userId) {return new JsonResult(cartServiceImpl.findAllProducts(userId));}@RequestMapping("doAddProductNum")public JsonResult doAddProductNum(Integer userId, Integer productId) {cartServiceImpl.productAmountASC(userId, productId);return new JsonResult("修改成功");}@RequestMapping("doReduceProductNum")public JsonResult doReduceProductNum(Integer userId, Integer productId) {cartServiceImpl.productAmountDESC(userId, productId);return new JsonResult("修改成功");}@RequestMapping("doDeleteProduct")public JsonResult doDeleteProduct(Integer userId, Integer productId) {cartServiceImpl.delCartProduct(userId, productId);return new JsonResult("删除成功");}
}

总结

本人也是在探索学习阶段,有什么问题可以互相交流讨论。当一个人沉迷于代码的世界时,会忘记这个世界,在做购物车的时候,中间也出现过多次BUG,通过不断的调试BUG,可以学到很多东西,尤其是当你成功解决了BUG之后,你对知识的掌握会更加牢靠,最后,需要源码的可以联系博主,联系方式:chendikai1314@163.com

SpringBoot整合Redis实现购物车功能相关推荐

  1. Springboot整合redis(lettuce)

    springboot 整合redis(lettuce) 首先确保电脑上装了redis.最好能用redisDesktop查看一下数据情况 redis是一款非常流行的Nosql数据库.redis的功能非常 ...

  2. springboot整合redis,推荐整合和使用案例(2021版)

    背景:手下新人在初次使用springboot整合redis,大部分人习惯从网上检索到一份配置,然后不知其所以然的复制粘贴到项目中,网上搜索到的配置良莠不齐但又万变不离其宗.由于springboot最大 ...

  3. springboot整合redis实现分布式锁思想

    思路 所有响应获取锁的线程都先尝试往redis中创建一个缓存数据,所有线程的key必须相同.使用的是redis的setnx命令.就只有一个线程能够创建成功,创建成功的线程就成功获取锁. 没有获取锁的线 ...

  4. SpringBoot整合Redis 之 StringRedisTemplate、RedisTemplate 基础

    SpringBoot 整合 Redis 环境准备 引入依赖 配置文件 StringRedisTemplate 基本使用 Key 常用操作 String 常用操作 List 常用操作 Set 常用操作 ...

  5. SpringBoot整合Redis - @Cacheable 和 RedisTemplate

    对之前网站做了一些很简单的优化,给用户列表加了一个分页功能. 分页就更好考虑加载速度,如果换一页就要等几秒,那体验感是非常差的. 因此想到了加一个redis缓存. springboot整合redis有 ...

  6. springboot整合redis案例——点赞取消点赞

    目录 springboot与缓存 JSR-107 Spring缓存抽象 重要概念和缓存注解 springboot整合redis 案例一:Redis是实现点赞.取消点赞 一.Redis 缓存设计及实现 ...

  7. SpringBoot整合redis实现发布订阅模式

    Redis的发布订阅模式 发布订阅(Pub/Sub):目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式:订阅者(如客户端)以事件订阅的方式表达出它有兴趣接 ...

  8. 商城项目(二)整合Redis实现缓存功能

    整合Redis实现缓存功能 环境搭建 Redis 版本:5.0.4 SpringBoot整合Redis 添加项目依赖 <!--redis依赖配置--> <dependency> ...

  9. SpringBoot整合Redis并实现Redis工具类

    Redis 是用 C 语言开发的一款开源的.高性能的键值对存储数据库.它采用 BSD 协议,为了适应不同场景下的存储需求,提供了多种键值对类型,到目前为止 Redis 数据库支持5种数据类型,分别是S ...

最新文章

  1. OC从plist文件中获取数据
  2. centos 6.5下KVM环境搭建
  3. [Hadoop in China 2011] 何鹏:Hadoop在海量网页搜索中应用分析
  4. 使用CSS完美实现垂直居中的方法
  5. java finally 抛出异常_java抛出异常与finally实例解析
  6. Python学习笔记:Day13 提升开发效率
  7. 酷客多基金在济南大学成立“酷客多奖助学金“
  8. SRS流媒体服务器——Edge集群搭建
  9. js list 合并_VIM学习笔记 脚本-列表(Script-List)
  10. Bootstrap表格表单
  11. 【李宏毅2020 ML/DL】P60-61 Unsupervised Learning - Deep Generative Model
  12. 大数据技术原理与应用----大数据概述
  13. 制作Mobi电子书目录
  14. Linux logviewer的功能,基于终端的日志工具logview
  15. java 自定义泛型方法_Java中自定义泛型方法的使用
  16. jersey 过滤_Jersey的Filter详解
  17. 法定节假日加班没给三薪是不是犯法的
  18. [学习SLAM]数学中的几何变换-向量叉乘/旋转轴、旋转角度和旋转矩阵/坐标系变换
  19. 计算机应用团队,【计算机应用论文】团队合作学习下计算机应用论文(共3025字)...
  20. cairo裁剪使用分析

热门文章

  1. Unity灯光、烘焙小结(二)sikiedu光照烘焙教程
  2. qq登录不了,显示00001
  3. 从万得下载A股数据保存到mongodb
  4. 前端vue开发连续签到功能
  5. 【VUE】源码分析 - 数据劫持的基本原理
  6. 教您用数学课件制作工具画椭圆
  7. android倒计时dialog,倒计时,dialog上显示倒计时,如果不点击dialog,倒计时结束后自动跳转...
  8. Unity命令模式, 实现撤销/反撤销
  9. 女性健康APP开发市场分析
  10. 宝宝的成长脚印10/23