Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十九(购物车)

Posted 蓝盒子itbluebox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十九(购物车)相关的知识,希望对你有一定的参考价值。

Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十九(购物车)

1.搭建购物车服务

业务分析

在需求描述中,不管用户是否登录,都需要实现加入购物车功能,
那么已登录和未登录下,购物车数据应该存放在哪里呢?

  • 未登录购物车

用户如果未登录,将数据保存在服务端存在一些问题:

无法确定用户身份,需要借助与客户端存储识别身份
服务端数据存储压力增加,而且可能是无效数据

那么我们应该用把数据保存在客户端,这样每个用户保存自己的数据,
就不存在身份识别的问题了,而且也解决了服务端数据存储压力问题。

不过大家可能会担心Redis存储空间问题,我们可以效仿淘宝,限制购物车最多只能添加99件商品,或者更少。

2.购物车功能分析

2.1.需求

需求描述:

  • 用户可以在登录状态下将商品添加到购物车
    • 放入数据库
    • 放入redis(采用)
  • 用户可以在未登录状态下将商品添加到购物车
    • 放入localstorage
  • 用户可以使用购物车一起结算下单
  • 用户可以查询自己的购物车
  • 用户可以在购物车中可以修改购买商品的数量。
  • 用户可以在购物车中删除商品。
  • 在购物车中展示商品优惠信息
  • 提示购物车商品价格变化

2.2.流程图:


这幅图主要描述了两个功能:新增商品到购物车、查询购物车。

新增商品:

  • 判断是否登录
    • 是:则添加商品到后台Redis中
    • 否:则添加商品到本地的Localstorage

无论哪种新增,完成后都需要查询购物车列表:

  • 判断是否登录
    • 否:直接查询localstorage中数据并展示
    • 是:已登录,则需要先看本地是否有数据,
      • 有:需要提交到后台添加到redis,合并数据,而后查询
      • 否:直接去后台查询redis,而后返回

3.未登录购物车

3.1.准备

3.1.1购物车的数据结构

首先分析一下未登录购物车的数据结构。

我们看下页面展示需要什么数据:


因此每一个购物车信息,都是一个对象,包含:

{
    skuId:2131241,
    title:"小米6",
    image:"",
    price:190000,
    num:1,
    ownSpec:"{"机身颜色":"陶瓷黑尊享版","内存":"6GB","机身存储":"128GB"}"
}

另外,购物车中不止一条数据,因此最终会是对象的数组。即:

[
    {...},{...},{...}
]

3.1.2.web本地存储

知道了数据结构,下一个问题,就是如何保存购物车数据。前面我们分析过,可以使用Localstorage来实现。Localstorage是web本地存储的一种,那么,什么是web本地存储呢?

什么是web本地存储?


web本地存储主要有两种方式:

  • LocalStorage:localStorage 方法存储的数据没有时间限制。第二天、第二周或下一年之后,数据依然可用。
  • SessionStorage:sessionStorage 方法针对一个 session 进行数据存储。当用户关闭浏览器窗口后,数据会被删除。

LocalStorage的用法

语法非常简单:

localStorage.setItem("key","value"); // 存储数据
localStorage.getItem("key"); // 获取数据
localStorage.removeItem("key"); // 删除数据

ss = JSON.stringify({age:12,sex:"male"})
'{"age":12,"sex":"male"}'
localStorage.setItem("name",ss)
undefined
localStorage.getItem("name")
'{"age":12,"sex":"male"}'

注意:localStorage和SessionStorage都只能保存字符串

不过,在我们的common.js中,已经对localStorage进行了简单的封装:


示例:

ly.store.set("aa",{age:14,sex:"male"})
undefined
ly.store.get("aa")
{age: 14, sex: 'male'}

3.1.3.获取num

添加购物车需要知道购物的数量,所以我们需要获取数量大小。我们在Vue中定义num,保存数量:

然后将num与页面的input框绑定,同时给+-的按钮绑定事件:

编写事件:

3.2.添加购物车

3.2.1.点击事件

我们看下商品详情页:


现在点击加入购物车会跳转到购物车成功页面。

不过我们不这么做,我们绑定点击事件,然后实现添加购物车功能。


addCart方法中判断用户的登录状态:

3.2.2.获取数量,添加购物车

addCart(){
    // 判断登录状态
    ly.http.get("/auth/verify")
        .then(resp => {

    })
        .catch(() => {
        // 未登录,添加到localstorage
        // 1、查询本地购物车
        const carts = ly.store.get("carts") || [];
        let cart = carts.find(c => c.skuId === this.sku.id);
        // 2、判断是否存在
        if(cart){
            // 3、存在,改数量
            cart.num += this.num;
        }else {
            // 4、不存在,新增
            cart = {
                skuId: this.sku.id,
                title: this.sku.title,
                image: this.images[0],
                price: this.sku.price,
                num: this.num,
                ownSpec: JSON.stringify(this.sku.ownSpec)
            };
            carts.push(cart);
        }
        // 把carts写回localstorage
        ly.store.set("carts", carts);

        // 跳转
        window.location.href = "http://www.leyou.com/cart.html";
    });
}

结果:


添加完成后,页面会跳转到购物车结算页面:cart.html

3.3.查询购物车

3.3.1.校验用户登录

因为会多次校验用户登录状态,因此我们封装一个校验的方法:

在common.js中:

3.3.2.查询购物车

页面加载时,就应该去查询购物车。cart.html中

var cartVm = new Vue({
    el: "#cartApp",
    data: {
        ly,
        carts: [],// 购物车数据
    },
    created() {
        this.loadCarts();
    },
    methods: {
        loadCarts() {
            // 先判断登录状态
            ly.verifyUser()
                .then(() => {
                    // 已登录

                })
                .catch(() => {
                    // 未登录
                    this.carts = ly.store.get("carts") || [];
                    this.selected = this.carts;
                })
                }
    }
    components: {
        shortcut: () => import("/js/pages/shortcut.js")
    }
})

刷新页面,查看控制台Vue实例:

3.5.2.渲染到页面

接下来,我们在页面中展示carts的数据:

页面位置:


修改后:

要注意,价格的展示需要进行格式化,这里使用的是我们在common.js中定义的formatPrice方法:


效果:

3.6.修改数量

我们给页面的 +-绑定点击事件,修改num 的值:

两个事件:

increment(c) {
    c.num++;
    ly.verifyUser()
        .then(() => {
            // TODO 已登录,向后台发起请求
        })
        .catch(() => {
            // 未登录,直接操作本地数据
            ly.store.set("carts", this.carts);
    })
},
decrement(c) {
    if (c.num <= 1) {
        return;
    }
    c.num--;
    this.verifyUser()
        .then(() => {
        // TODO 已登录,向后台发起请求
        })
        .catch(() => {
            // 未登录,直接操作本地数据
            ly.store.set("carts", this.carts);
        })
},

3.7.删除商品

给删除按钮绑定事件:

点击事件中删除商品:

deleteCart(i) {
    ly.verifyUser()
        .then(() => {
            // 已登录
        })
        .catch(() => {
            // 未登录
            this.carts.splice(i, 1);
            ly.store.set("carts", this.carts);
        })
}

3.8.选中商品

在页面中,每个购物车商品左侧,都有一个复选框,用户可以选择部分商品进行下单,而不一定是全部:

我们定义一个变量,记录所有被选中的商品:

3.8.1.选中一个

我们给商品前面的复选框与selected绑定,并且指定其值为当前购物车商品:

3.8.2.初始化全选

我们在加载完成购物车查询后,初始化全选:

3.8.4.总价格

然后编写一个计算属性,计算出选中商品总价格:

computed: {
    totalPrice() {
        return this.selected.map(c => c.num * c.price).reduce((p1, p2) => p1 + p2, 0);
    }
} 

在页面中展示总价格:


效果:

4.已登录购物车

4.1.购物车的微服务

4.1.1.创建购物车的微服务



4.1.2.pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.service</groupId>
    <artifactId>ly-cart</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>


</project>

4.1.3.配置文件


server:
  port: 8088
spring:
  application:
    name: cart-service
  redis:
    host: 192.168.206.66
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 5
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
    instance-id: ${eureka.instance.ip-address}.${server.port}
    lease-renewal-interval-in-seconds: 3
    lease-expiration-duration-in-seconds: 10

4.1.4.启动类


@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LyCartApplication {

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

4.1.5.添加到网关的路由当中

5.已登录购物车

接下来,我们完成已登录购物车。

在刚才的未登录购物车编写时,我们已经预留好了编写代码的位置,逻辑也基本一致。

5.1.添加登录校验

购物车系统只负责登录状态的购物车处理,因此需要添加登录校验,我们通过JWT鉴权即可实现。

5.1.1.引入JWT相关依赖

我们引入之前写的鉴权工具:ly-auth-common

		<dependency>
            <groupId>com.leyou.auth</groupId>
            <artifactId>ly-auth-common</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

5.1.2.配置公钥

ly:
  jwt:
    pubKeyPath: C:\\\\Users\\\\ZHENG\\\\Desktop\\\\leyou_msgrs\\\\rsa\\\\rsa.pub # 公钥地址
    cookieName: LY_TOKEN # cookie的名称

5.1.3.加载公钥


package com.leyou.cart.config;
import com.leyou.auth.utils.RsaUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.annotation.PostConstruct;
import java.security.PublicKey;

@Data
@ConfigurationProperties(prefix = "ly.jwt")
@Slf4j
public class JwtProperties {

    private String pubKeyPath;// 公钥

    private PublicKey publicKey; // 公钥

    private String cookieName;
    @PostConstruct
    public void init(){
        try {
            // 获取公钥和私钥
            this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
        } catch (Exception e) {
            log.error("初始化公钥失败!", e);
            throw new RuntimeException();
        }
    }
}

5.1.4.编写过滤器

引入依赖:

  <dependency>
      <groupId>com.leyou.common</groupId>
      <artifactId>ly-common</artifactId>
      <version>1.0.0-SNAPSHOT</version>
</dependency>

代码:

因为很多接口都需要进行登录,我们直接编写SpringMVC拦截器,进行统一登录校验。同时,我们还要把解析得到的用户信息保存起来,以便后续的接口可以使用。

package com.leyou.interceptor;

import com.leyou.auth.entity

以上是关于Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十九(购物车)的主要内容,如果未能解决你的问题,请参考以下文章

IDEA SpringBoot 项目打包成jar包

JavaEE 之 SpringBoot

面试-科大讯飞日常实习面试

(超详解)SpringBoot高级部分-自动配置+监听机制+监控+项目部署

Java项目:超市进销存系统设计和实现(java+Springboot+ssm+mysql+jsp+maven)

SpringBoot核心注解应用