企业级项目分享:购物车模块(一)2021-06-08

购物车模块

前言

上周 ‘事多’(懒)没更新,落下的进度后续会更新,现在更新下目前的进度

购物车数据2种形态

  • 登录态:保存到服务器端的redis中
  • 没登录:保存在浏览器端 localStorage 中

1.搭建购物车服务

1.1步骤一:创建changgou4-service-cart 项目

1.2步骤二:修改pom.xml文件,添加坐标

<dependencies>
    <!--自定义项目-->
    <dependency>
        <groupId>com.czxy.changgou</groupId>
        <artifactId>changgou4-common-auth</artifactId>
    </dependency>
    <dependency>
        <groupId>com.czxy.changgou</groupId>
        <artifactId>changgou4-pojo</artifactId>
    </dependency>
    <!--web起步依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--redis-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </dependency>
    <!-- nacos 客户端 -->
    <dependency>
        <groupId>com.alibaba.nacos</groupId>
        <artifactId>nacos-client</artifactId>
    </dependency>

    <!-- nacos 服务发现 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <!-- openfeign 远程调用 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

    <!--swagger2-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
    </dependency>

    <!--fastjson-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
    </dependency>

</dependencies>

1.3步骤三:创建yml文件

#端口号
server:
  port: 8095
spring:
  application:
    name: cart-service
  redis:
    host: 127.0.0.1
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848   #nacos服务地址
#自定义内容
sc:
  jwt:
    secret: # 登录校验的密钥
    pubKeyPath:  # 公钥地址
    priKeyPath:  # 私钥地址
    expire: 360 # 过期时间,单位分钟

1.4步骤四:拷贝JWT配合类 + Swagger + Redis

在这里插入图片描述

1.5步骤五:启动类

package com.czxy.changgou4;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;


@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class CartApplication {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(CartApplication.class,args);
    }
}

2.添加到购物车

2.1 整体分析

在这里插入图片描述

2.2接口

POST http://localhost:10010/cart-service/carts
{
    
    
    "skuid": 2600242,
    "count": 5,
    "checked": true
}

2.3后端:分析

在这里插入图片描述

2.4后端实现:JavaBean

在这里插入图片描述

  • 购物车列表项对象:CartItem (某一件商品的购买情况:商品、购买数量 等)
package com.czxy.changgou4.cart;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;


@Data
public class CartItem {
    
    
    private Integer skuid;
    private Integer spuid;
    @JsonProperty("goods_name")
    private String goodsName;
    private Double price;
    private Integer count;//购买数量
    private Boolean checked;
    private String midlogo;
    @JsonProperty("spec_info")
    private String specInfo;

}
  • 购物车对象:Cart
package com.czxy.changgou4.cart;

import lombok.Data;

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


@Data
public class Cart {
    
    

    private Map<Integer , CartItem > data = new HashMap<>();
    private Double total;

    public Double getTotal() {
    
    
        double sum = 0.0;
        for (CartItem cartItem : data.values()) {
    
    
            //只统计勾选的价格
            if(cartItem.getChecked()){
    
    
                sum += ( cartItem.getPrice() * cartItem.getCount());
            }
        }
        return sum;
    }

    public void addCart(CartItem cartItem) {
    
    
        CartItem temp = data.get(cartItem.getSkuid());
        if(temp == null) {
    
    
            data.put( cartItem.getSkuid() , cartItem);
        } else {
    
    
            temp.setCount( cartItem.getCount() + temp.getCount() );
        }
    }


    public void updateCart(Integer skuid, Integer count , Boolean checked) {
    
    
        CartItem temp = data.get(skuid);
        if(temp != null) {
    
    
            temp.setCount( count );
            temp.setChecked(checked);
        }
    }

    public void deleteCart(Integer skuid) {
    
    
        data.remove( skuid );
    }

}
  • 购物车专门定制的对象
    在这里插入图片描述
    CartCategory
package com.czxy.changgou4.vo;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

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


@Data
public class CartCategory {
    
    

    private Integer id;

    @JsonProperty("cat_name")
    private String catName;

    @JsonProperty("parent_id")
    private Integer parentId;

    @JsonProperty("is_parent")
    private Boolean isParent;

    //当前分类具有的所有孩子
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private List<CartCategory> children = new ArrayList<>();

}

CartSpecificationOption

package com.czxy.changgou4.vo;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;


@Data
public class CartSpecificationOption {
    
    

    private Integer id;

    @JsonProperty("spec_id")
    private Integer specId;                //外键,规格ID

    private CartSpecification specification; //外键对应对象

    @JsonProperty("option_name")
    private String optionName;             //选项名称

}

CartSpecification

package com.czxy.changgou4.vo;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;


@Data
public class CartSpecification {
    
    

    private Integer id;

    @JsonProperty("spec_name")
    private String specName;                    //规格名称

    private Integer categoryId;                     //分类外键
    private CartCategory category;                      //分类外键对应对象


    private List<CartSpecificationOption> options;      //一个规格,具有多个规格选项

}

CartOneSkuResult

package com.czxy.changgou4.vo;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.Date;
import java.util.List;
import java.util.Map;


@Data
public class CartOneSkuResult {
    
    

    private Integer skuid;
    private Integer spuid;
    @JsonProperty("goods_name")
    private String goodsName;
    private Double price;
    @JsonProperty("on_sale_date")
    private Date onSaleDate;
    @JsonProperty("comment_count")
    private Integer commentCount;
    @JsonProperty("comment_level")
    private Integer commentLevel;
    @JsonProperty("cat1_info")
    private CartCategory cat1Info;
    @JsonProperty("cat2_info")
    private CartCategory cat2Info;
    @JsonProperty("cat3_info")
    private CartCategory cat3Info;
    private Map<String, String> logo;
    private List<Map> photos;
    private String description;
    private String aftersale;
    private Integer stock;
    @JsonProperty("spec_list")
    private List<CartSpecification> specList;
    // id_list:'规格ID:选项ID|规格ID:选项ID|...',
    // id_txt:'规格名称:选项名称|规格名称:选项名称|...'
    @JsonProperty("spec_info")
    private Map<String, String> specInfo;
    @JsonProperty("sku_list")
    private List<Map<String, String>> skuList;

}

2.5后端实现

在这里插入图片描述

步骤一:创建CartVo,用于封装请求参数

package com.czxy.changgou4.vo;

import lombok.Data;

@Data
public class CartVo {
    
    

    private Integer skuid ;     //"SKUID",
    private Integer count;      //"购买数量"
    private Boolean checked;    //"购买数量"

}

步骤二:创建SkuClient,用于查询详情

package com.czxy.changgou4.feign;

import com.czxy.changgou4.vo.BaseResult;
import com.czxy.changgou4.vo.OneSkuResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;


@FeignClient(value="changgou4-web-service",path = "/sku")
public interface SkuClient {
    
    

    @GetMapping("/goods/{skuid}")
    public BaseResult<OneSkuResult> findSkuById(@PathVariable("skuid") Integer skuid);

}

步骤三:创建CartService接口,用于完成添加业务逻辑

package com.czxy.changgou4.service;

import com.czxy.changgou4.pojo.User;
import com.czxy.changgou4.vo.CartVo;


public interface CartService {
    
    

    /**
     * 给指定用户添加商品
     * @param user
     * @param cartVo
     */
    public void addCart(User user , CartVo cartVo);
}

步骤四:创建CartService实现类

package com.czxy.changgou4.service.impl;

import com.alibaba.fastjson.JSON;
import com.czxy.changgou4.cart.Cart;
import com.czxy.changgou4.cart.CartItem;
import com.czxy.changgou4.feign.SkuClient;
import com.czxy.changgou4.pojo.User;
import com.czxy.changgou4.service.CartService;
import com.czxy.changgou4.vo.BaseResult;
import com.czxy.changgou4.vo.CartOneSkuResult;
import com.czxy.changgou4.vo.CartVo;
import com.czxy.changgou4.vo.OneSkuResult;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;


@Service
@Transactional
public class CartServiceImpl implements CartService {
    
    

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private SkuClient skuClient;


    @Override
    public void addCart(User user, CartVo cartVo) {
    
    
        //1 获得购物车
        Cart cart;
        String key = "cart" + user.getId();
        String cartStr = stringRedisTemplate.opsForValue().get(key);
        // 处理是否有购物车,没有创建,有转换(jsonStr --> java对象 )
        if(cartStr != null){
    
    
            //如果有,将json字符串转换购物车对象
            cart = JSON.parseObject( cartStr , Cart.class);

        } else {
    
    
            //如果没有创建一个
            cart = new Cart();
        }

        //2 保存商品
        // 2.1 确定购物买商品
        BaseResult<CartOneSkuResult> entity = skuClient.findSkuById(cartVo.getSkuid());
        CartOneSkuResult oneSkuResult = entity.getData();

        // * 将OneSkuResult 转换成 CartItem
        CartItem cartItem = new CartItem();
        cartItem.setSkuid( oneSkuResult.getSkuid() );
        cartItem.setSpuid( oneSkuResult.getSpuid() );
        cartItem.setGoodsName( oneSkuResult.getGoodsName() );
        cartItem.setPrice( oneSkuResult.getPrice() );
        cartItem.setCount( cartVo.getCount() );        //购买数量,用户传递的
        cartItem.setChecked(true);
        cartItem.setMidlogo( oneSkuResult.getLogo().get("biglogo"));
        cartItem.setSpecInfo( JSON.toJSONString( oneSkuResult.getSpecInfo() ) );   //将对象转换json字符串

        // 2.2 添加到购物车
        cart.addCart( cartItem );

        System.out.println(JSON.toJSONString(cart) );
        //3 保存购物车
        stringRedisTemplate.opsForValue().set( key , JSON.toJSONString(cart) );

    }
}

步骤五:创建CartController


package com.czxy.changgou4.controller;

import com.czxy.changgou4.config.JwtProperties;
import com.czxy.changgou4.pojo.User;
import com.czxy.changgou4.service.CartService;
import com.czxy.changgou4.utils.JwtUtils;
import com.czxy.changgou4.vo.BaseResult;
import com.czxy.changgou4.vo.CartVo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;


@RestController
@RequestMapping("/carts")
public class CartController {
    
    

    @Resource
    private CartService cartService;

    @Resource
    private HttpServletRequest request;

    @Resource
    private JwtProperties jwtProperties;

    @PostMapping
    public BaseResult addCart(@RequestBody CartVo cartVo){
    
    

        //1 获得用户信息
        // 1.1 获得token
        String token = request.getHeader("Authorization");
        // 1.2 解析token
        User loginUser = null;
        try {
    
    
            loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User.class);
        } catch (Exception e) {
    
    
            return BaseResult.error("token失效或未登录");
        }

        //2 添加操作
        cartService.addCart( loginUser , cartVo );

        //3 提示
        return BaseResult.ok("添加成功");


    }

}

步骤六:测试

在这里插入图片描述

2.6前端实现:购买数量

步骤一:修改 api.js ,完成“添加到购物车”方法

在这里插入图片描述

//添加到购物车
  addToCart : ( params ) => {
    
    
    return axios.post("/cart-service/carts", params )
  },

步骤二:修改Goods.vue,给“加入购物车”绑定点击事件 addToCartFn

在这里插入图片描述

<input type="submit" value="" class="add_btn" @click.prevent="addToCartFn"  />

步骤三:修改Goods.vue,完成addToCartFn功能

  • 未登录:保存到sessionStorage
  • 登录:保存到redis
  • 待完善功能:用户登录时,将sessionStorage保存的商品信息合并到redis中
async addToCartFn(){
    
    
      //获得登录标识
      let token = sessionStorage.getItem("token");
      if(token != null){
    
    
        //登录:发送ajax进行添加
        let newGoods = {
    
    
          skuid: this.$route.query.id,
          count:this.buyCount
        };
        //登录状态下的添加商品到购物车操作
        let {
    
    data} = await this.$request.addToCart(newGoods)
        if(data.code == 20000){
    
    
          //location.href = "flow1"
          this.$router.push('flow1')
        } else {
    
    
          alert(data.data.errmsg);
        }
        return;
      }

      //未登录:在浏览器保存
      //1 准备添加物品数据
      var newGoods = {
    
    
        skuid: this.goodsInfo.skuid,
        goods_name:this.goodsInfo.goods_name,
        price:this.goodsInfo.price,
        count:this.buyCount,
        checked:true,
        midlogo:this.goodsInfo.logo.smlogo,
        spec_info: JSON.stringify(this.goodsInfo.spec_info)
      };
      //2 维护数据:本地已经存储信息 和 新添加信息 合并
      var cartStr = localStorage.getItem("cart");
      var cart;
      if(cartStr == null) {
    
    
        // 2.1 第一次添加,直接已数组方式添加
        cart = [newGoods];
      } else {
    
    
        //判断是否存在(将字符串转换数组、依次遍历)
        cart = JSON.parse(cartStr);
        //是否为新物品,默认为新的
        let isNew = true;

        cart.forEach( g => {
    
    
          //已有数据的id 和 新物品id 是否一样
          if(g.skuid == newGoods.skuid){
    
    
            //不是新物品
            isNew = false;
            // 2.3 已有,重复,先获得对应,修改数量
            g.count += parseInt(newGoods.count);
          }
        });

        if(isNew == true){
    
    
          // 2.2 已有,不重复,先获得数组,后追加
          cart.push(newGoods);
        }

      }
      //3 存放到浏览器
      var cartStr = JSON.stringify(cart);
      localStorage.setItem("cart" , cartStr );
      //4 跳转页面
      location.href = "flow1"
    }

步骤四:编写flow1页面

在这里插入图片描述

<template>
  <div>购物车</div>
</template>

<script>
export default {
      
      

}
</script>

<style>

</style>

感谢宁看到这里,你的三连就是我更新的动力 冲冲冲!!!!!!

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/LiGuanLink/article/details/117705664