springboot+vue实现在线书店(图书商城)系统

131 阅读8分钟

今天教大家如何设计一个图书商城 , 基于目前主流的技术:前端vue,后端springboot。

同时还带来的项目的部署教程

 

视频演示

www.bilibili.com/video/BV15D…

 

图片演示

 

 

一. 系统概述

商城是一款比较庞大的系统,需要有商品中心,库存中心,订单中心,收货地址和运费管理。先看下我们要实现的商城有哪些功能:

  • 商品分类管理。

  • 商品管理。

  • 库存管理。

  • 订单管理。 

  • 评价管理。

  • 用户管理。

  • 运费和运费模板管理。

  • 系统公告管理。

  • 首页轮播图管理。

  • 用户购物车。

 

二. 核心功能实现思想

库存系统的设计

库存最大的问题就是超卖,也就是说有多个人同时并发下单,库存需要保持一致性,不会扣减到小于0的情况。普通的设计就是加一个全局锁。每个人下单都需要等待上一个人下单完成。

这样严重影响效率。这里我们库存的设计流程如下:

  1. 首先我们将库存分为 数据库库存 和 销售库存。 数据库库存就是存储到数据库的商品库存值,销售库存就是用户下单,页面所在的库存值。

  2. 后台管理上架商品时,会设置一个初始库存,我们将初始库存存储到数据库库存 和 销售库存 。

3.当用户下单时,不是直接扣减的数据库库存,而是通过redis的 decrement 方法,对销售库存进行扣减。但是redis的扣减操作这里还不是一个原子性操作,需要先从redis查出库存,然后进行decrment操作。这两步操作我们用reddsion的分布式锁来控制原子性,同时,我们将加锁的维度控制到了商品id。这样大大提高了并发效率。

  1. 库存扣减后,我们又通过redis消费队列,实现了对数据库库存的同步。这样保持了redis库存和数据库库存的一致性。

  2. 后台我们设计的是对商品只能加加库存,和减少库存的操作,而不是直接修改库存值。如果你直接修改库存值,就有可能会导致库存数据不一致,难以跟踪。

  3. 我们还设计了库存的扣减,新增日志,方便对库存进行跟踪管理。

 

库存扣减的部分代码: ``/**`

     ``* 扣减库存(使用Redisson分布式锁)

     ``* @param productId 商品ID

     ``* @param quantity 扣减数量

     ``* @return true-扣减成功,false-扣减失败(库存不足)

     ``*/

    ``public boolean deductInventory(String productId, ``int quantity) {

        ``String lockKey = ``"lock:inventory:" + productId;

        ``String inventoryKey = ``"inventory:" + productId;

 

        ``RLock lock = redissonClient.getLock(lockKey);

 

        ``try {

            ``// 尝试加锁,最多等待10秒,锁过期时间30秒

            ``boolean locked = lock.tryLock(``10``, ``30``, TimeUnit.SECONDS);

            ``if (locked) {

                ``String stock = (String) redisTemplate.opsForValue().get(inventoryKey);

                ``if``(StringUtils.isEmpty(stock)){

                    ``return false``;

                ``}

                ``if (Integer.parseInt(stock) < quantity) {

                    ``return false``;

                ``}

                ``// 扣减库存

                ``redisTemplate.opsForValue().decrement(inventoryKey, quantity);

                ``return true``;

            ``}

            ``return false``;

        ``} ``catch (InterruptedException e) {

            ``Thread.currentThread().interrupt();

            ``return false``;

        ``} ``finally {

            ``// 释放锁

            ``if (lock.isHeldByCurrentThread()) {

                ``lock.unlock();

            ``}

        ``}

    ``}

 

    ``/**

     ``* 设置商品库存

     ``* @param productId 商品ID

     ``* @param quantity 库存数量

     ``*/

    ``public void setInventory(String productId, ``int quantity) {

        ``String inventoryKey = ``"inventory:" + productId;

        ``redisTemplate.opsForValue().set(inventoryKey, quantity);

        ``System.out.println(``"库存设置: 商品id:" + productId + ``" , 数量:" + quantity);

    ``}

 

    ``/**

     ``* 获取商品库存

     ``* @param productId 商品ID

     ``* @return 当前库存数量

     ``*/

    ``public int getInventory(String productId) {

        ``String inventoryKey = ``"inventory:" + productId;

        ``Object value = redisTemplate.opsForValue().get(inventoryKey);

        ``return value == ``null ? ``0 : Integer.parseInt(value.toString());

`    }

  

商品系统的设计

商品包含了很多属性,这里我设计的商品表如下:

```CREATE TABLE product (``

  ``` product_id  ```int NOT NULL AUTO_INCREMENT COMMENT ``'商品id'``,

  ``` product_name varchar( ```100``) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ``'商品名称'``,

  ``` category_id  ```int NOT NULL COMMENT ``'类目id'``,

  ``` product_title varchar( ```300``) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ``'商品标题'``,

  ``` product_intro text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT  ```'商品详情'``,

  ``` product_picture varchar( ```200``) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ``'商品封面图'``,

  ``` product_price  ```double NOT NULL COMMENT ``'商品原价'``,

  ``` product_selling_price  ```double NOT NULL COMMENT ``'商品售卖价'``,

  ``` product_num  ```int NOT NULL COMMENT ``'商品库存'``,

  ``` product_sales  ```int NOT NULL COMMENT ``'销量'``,

  ``` state tinyint DEFAULT  ```'0' COMMENT ``'0-上架  1- 下架'``,

  ``` score  ```double DEFAULT NULL COMMENT ``'推荐评分,总共有5星'``,

  ```PRIMARY KEY (product_id`) USING BTREE``

) ENGINE=InnoDB AUTO_INCREMENT=``20 `DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='商品';``

 

商品还关联了多图

```CREATE TABLE product_picture (``

  ``` id  ```int NOT NULL AUTO_INCREMENT COMMENT ``'主键id'``,

  ``` product_id  ```int NOT NULL COMMENT ``'商品id'``,

  ``` product_picture varchar( ```200``) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ``'商品图片'``,

  ``` intro` text CHARACTER SET utf8 COLLATE utf8_general_ci, ``

  ```PRIMARY KEY (id`) USING BTREE``

) ENGINE=InnoDB AUTO_INCREMENT=``167 `DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='商品图片';``

  

商品还有一个动态的字典属性

 

动态字典属性表设计

```CREATE TABLE product_attr (``

  ``` id  ```int NOT NULL AUTO_INCREMENT,

  ``` product_id  ```int NOT NULL,

  ``` product_attr_config_id  ```int NOT NULL COMMENT ``'商品属性字典id'``,

  ``` attr_val varchar( ```500``) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ``'属性值'``,

  ```PRIMARY KEY (id`) USING BTREE``

) ENGINE=InnoDB AUTO_INCREMENT=``190 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=``'商品属性与字典关联'``;

 

CREATE TABLE `product_attr_config` (

  ``` id  ```int NOT NULL AUTO_INCREMENT,

  ``` attr_name varchar( ```500``) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ``'字典描述'``,

  ``` attr_key varchar( ```500``) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ``'字典key'``,

  ```PRIMARY KEY (id`) USING BTREE``

) ENGINE=InnoDB AUTO_INCREMENT=``8 `DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='商品属性字典';``

  

订单系统的设计

我们将订单的状态设计成以下几种:0-待付款 1-待发货 2-待收货 3-待评价 4-已完成 5-退款中 6-已退款 7-已取消。

订单状态扭转流程:

  1. 用户点击购买商品或从购物车点击,则商品进入待付款状态,此时,商品库存被锁,也就是实实在在的扣减了销售库存。

  2. 当30分钟超过后,用户未支付上面的待付款订单,则订单状态扭转为已取消,库存回流,此笔订单结束。

  3. 当用户30分钟内支付后,订单扭转为代发货。

  4. 管理员登录管理后台,将待发货订单进行发货操作后,订单状态变成待收货。

  5. 用户可以对待收获订单进行收获和退款操作,如果是退款,则变成退款中,管理员进行退款确认,确认后,订单变成已退款,退款成功后,库存回流。此订单结束。

  6. 如果用户确认收获,则订单变成待评价,用户可以进行评价,评价完成后,订单变成已完成,此订单结束。

 

订单表设计如下:

```CREATE TABLE orders (``

  ``` order_id varchar( ```200``) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,

  ``` user_id  ```int NOT NULL COMMENT ``'用户id'``,

  ``` product_id  ```int NOT NULL COMMENT ``'商品id'``,

  ``` product_num  ```int NOT NULL COMMENT ``'商品数量'``,

  ``` order_state  ```int NOT NULL COMMENT ``'订单状态 0-待付款 1-待发货 2-待收货 3-待评价 4-已完成 5-退款中 6-已退款 7-已取消'``,

  ``` product_price  ```double NOT NULL COMMENT ``'下单商品价格'``,

  ``` shipping_price  ```double NOT NULL COMMENT ``'下单运费价格'``,

  ``` refund_cause varchar( ```2255``) COLLATE utf8mb4_bin DEFAULT NULL COMMENT ``'退款原因'``,

  ``` order_remark varchar( ```2000``) COLLATE utf8mb4_bin NOT NULL COMMENT ``'订单备注'``,

  ``` pay_type  ```int DEFAULT NULL COMMENT ``'支付方式:0-支付宝 1-微信'``,

  ``` address varchar( ```2000``) COLLATE utf8mb4_bin NOT NULL COMMENT ``'收获地址'``,

  ``` create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT  ```'创建时间'``,

  ```PRIMARY KEY (order_id`) USING BTREE``

`) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单';``

  

 

三. 技术栈概述

后端技术栈:

JDK8 + springboot + mysql8

前端技术栈:

vue + Axios 等

 

SQL文件与全部源码我已整理清楚,移步获取:

gitcode( 巅 ) C 〇 M/hadluo2/shop.git

 

四. 项目部署教程

前端部署

安装node , 版本:v22.15.0 , 安装完成后。

 

 进入到项目 hadluo-shop-webadmin 目录下,这个项目是vue的管理后台, 右键,运行cmd,运行下面命令:

npm run dev

由于我已经跟你npm install好了,所以你无需执行,直接run就可以了!!

运行项目

 

 

进入到项目 hadluo-shop-h5 目录下,这个项目是vue的前端, 右键,运行cmd,运行下面命令:

npm run dev

由于我已经跟你npm install好了,所以你无需执行,直接run就可以了!!

运行项目

 

到此前端项目部署完成。

 

执行sql

自己安装好数据库,注意,必须是mysql8 ,否则代码运行会出错。新建一个 wxhadluo-bookshop 数据库, 然后执行  “wxhadluo-bookshop.sql”

 

Redis安装

项目需要安装redis,直接下载一个windows版本的redis即可,没有的联系我。

 

启动后端项目

然后部署后端 , 打开idea, 导入maven工程 hadluo-bookshop。

打开resources目录, 修改 application.yml 配置文件,主要修改下面几个信息:

 

 

 

然后启动  main 启动类 : Application.class

五. 访问项目

管理后端:

http://localhost:3001/

账号:wx-hadluo,  密码: 123456

 

前端:

http://localhost:3000/

用户: 453423@qq.com / 123456

可以自己注册用户。