购物车常见实现方式

1、实现方式⼀:存储到数据库性能存在瓶颈
2、实现方式⼆:前端本地存储-localstoragesessionstoragelocalstorage在浏览器中存储key/value 对,没有过期时间。sessionstorage在浏览器中存储 key/value 对,在关闭会话窗⼝后将会删除这些数据。
3、实现方式三:后端存储到缓存如redis可以开启AOF持久化防⽌重启丢失(推荐)

购物⻋数据结构介绍

⼀个购物车里面,存在多个购物项,所以购物车结构是⼀个双层Map:
Map<String,Map<String,String>>
第⼀层Map,Key是⽤户id
第⼆层Map,Key是购物⻋中商品id,值是购物⻋数据

相关VO类和数据准备

VideoDO

@Data
@NoArgsConstructor
@AllArgsConstructor
public class VideoDO {

    private int id;

    private String title;

    private String img;

    private int price;

CartItemVO

public class CartItemVO {
    /**
     * 商品id
     */
    private 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

import java.util.List;

public class CartVO {

    /**
     * 购物项
     */
    private List<CartItemVO> cartItems;


    /**
     * 购物车总价格
     */
    private Integer totalAmount;



    /**
     * 总价格
     * @return
     */
    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;
    }
}

数据源层
import net.xdclass.xdclassredis.model.VideoDO;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.Map;

@Repository
public class VideoDao {

    private static Map<Integer,VideoDO> map = new HashMap<>();

    static {
        map.put(1, new VideoDO(1,"工业级PaaS云平台+SpringCloudAlibaba 综合项目实战(完结)","https://xdclass.net",1099));
        map.put(2,new VideoDO(2,"玩转新版高性能RabbitMQ容器化分布式集群实战","https://xdclass.net",79));
        map.put(3,new VideoDO(3,"新版后端提效神器MybatisPlus+SwaggerUI3.X+Lombok","https://xdclass.net",49));
        map.put(4,new VideoDO(4,"玩转Nginx分布式架构实战教程 零基础到高级","https://xdclass.net",49));
        map.put(5,new VideoDO(5,"ssm新版SpringBoot2.3/spring5/mybatis3","https://xdclass.net",49));
        map.put(6,new VideoDO(6,"新一代微服务全家桶AlibabaCloud+SpringCloud实战","https://xdclass.net",59));
    }


    /**
     * 模拟从数据库找
     * @param videoId
     * @return
     */
    public VideoDO findDetailById(int videoId) {
        return map.get(videoId);
    }
}

json⼯具类
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonUtil {


    private static final ObjectMapper MAPPER = new ObjectMapper();


    /**
     * 把对象转字符串
     * @param data
     * @return
     */
    public static String objectToJson(Object data){
        try {

            return MAPPER.writeValueAsString(data);

        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }


    /**
     * json字符串转对象
     * @param jsonData
     * @param beanType
     * @param <T>
     * @return
     */
    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;


    }

}

添加购物车接口、查看我的购物车、清空购物车
import net.xdclass.xdclassredis.dao.VideoDao;
import net.xdclass.xdclassredis.model.VideoDO;
import net.xdclass.xdclassredis.util.JsonData;
import net.xdclass.xdclassredis.util.JsonUtil;
import net.xdclass.xdclassredis.vo.CartItemVO;
import net.xdclass.xdclassredis.vo.CartVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("api/v1/cart")
public class CartController {



    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private VideoDao videoDao;

    @RequestMapping("add")
    public JsonData addCart(int videoId,int buyNum){

        //获取购物车
        BoundHashOperations<String,Object,Object> myCart = getMyCartOps();

        Object cacheObj = myCart.get(videoId+"");

        String result = "";
        if(cacheObj!=null){
            result = (String)cacheObj;
        }


        //购物车没这个商品
        if(cacheObj == null){

            CartItemVO cartItem = new CartItemVO();
            VideoDO videoDO = videoDao.findDetailById(videoId);

            cartItem.setBuyNum(buyNum);
            cartItem.setPrice(videoDO.getPrice());
            cartItem.setProductId(videoDO.getId());
            cartItem.setProductImg(videoDO.getImg());
            cartItem.setProductTitle(videoDO.getTitle());

            myCart.put(videoId+"",JsonUtil.objectToJson(cartItem));

        }else {
          //增加商品购买数量
            CartItemVO cartItemVO = JsonUtil.jsonToPojo(result,CartItemVO.class);
            cartItemVO.setBuyNum(cartItemVO.getBuyNum()+buyNum);

            myCart.put(videoId+"",JsonUtil.objectToJson(cartItemVO));
        }


        return JsonData.buildSuccess();


    }


    /**
     * 查看我的购物车
     */
    @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();
    }




    /**
     * 抽取我的购物车通用方法
     * @return
     */
    private BoundHashOperations<String,Object,Object> getMyCartOps(){

        String key = getCartKey();

        return redisTemplate.boundHashOps(key);
    }


    private String getCartKey(){

        //用户的id,从拦截器获取
        int userId = 88;
        String cartKey = String.format("video:cart:%s",userId);
        return cartKey;

    }


}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐