SpringBoot整合Redis实现购物车功能

目录

项目介绍

开发配置

开发流程

购物车业务流程

开发流程

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;					//购物车id
	private Integer userId;				//用户id
	private Integer productId;			//商品id
	private 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 {

	@Autowired
	private RedisConfig  redisConfig;
	
	@Bean
	public 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 {
	
    @Autowired
    private 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{
    @Autowired
    RedisService redisService;

    @Autowired
    ProductInfoDao productInfoDao;
    
    @Autowired
    private CartServiceDao cartServiceDao;

    /**
     *	添加商品到购物车中
     */
    @Override
    public 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;
    }

    @Override
    public 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;
    }
    
    @Override
    public 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;
    }
    @Override
    public 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
     */
    @Override
    public 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 {

	@Autowired
	private 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

 

 

 

 

 

 

  • 8
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,那我来回答你的问题。在SpringBoot中,实现点赞功能通常会使用Redis进行缓存,可以将点赞数存储到Redis中,每当一个用户进行点赞操作时,就会将点赞数从Redis中读取,进行加1操作,再将结果存储回Redis中。具体实现步骤如下: 1. 首先,在pom.xml文件中添加Redis的依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 2. 在application.properties文件中配置Redis连接信息: ``` spring.redis.host=127.0.0.1 spring.redis.port=6379 ``` 3. 创建一个Redis工具类,用于封装一些Redis操作: ``` @Component public class RedisUtil { @Autowired private StringRedisTemplate redisTemplate; public void increment(String key) { redisTemplate.opsForValue().increment(key); } public String get(String key) { return redisTemplate.opsForValue().get(key); } public void set(String key, String value) { redisTemplate.opsForValue().set(key, value); } } ``` 4. 在点赞接口中,调用RedisUtil中封装的方法,完成点赞功能的实现: ``` @RestController public class LikeController { @Autowired private RedisUtil redisUtil; @PostMapping("/like") public void like(@RequestParam("id") Integer id) { String key = "like:" + id; redisUtil.increment(key); } @GetMapping("/like") public String getLike(@RequestParam("id") Integer id) { String key = "like:" + id; return redisUtil.get(key); } } ``` 以上就是SpringBoot整合Redis实现点赞功能的具体步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值