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

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

系统最大的亮点是使用了两个推荐算法:

1. 基于Jaccard算法的用户浏览历史推荐。

2. 基于用户的协同过滤算法个性化推荐。

还有核心的商城保证库存不超卖,订单,运费等基本商城系统设计。下面我会详细描述下这些设计思路。

视频演示

https://githubs.xyz/show/6791a78f-b52e-46c5-8acb-85ee53d62fc2.mp4

图片演示

系统概述

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

1. 商品分类管理。

2. 商品管理。

3.库存管理。

4.订单管理。

5. 评价管理。

6.用户管理。

7.运费和运费模板管理。

8. 系统公告管理。

9.首页轮播图管理。

10. 用户购物车。

核心功能实现思想

用户协同过滤算法的设计

协同过滤(Collaborative Filtering, CF)是推荐系统中最经典的算法之一,其核心思想是通过用户的历史行为数据(如评分、点击、购买等)发现用户或物品的相似性,并基于这种相似性进行推荐。协同过滤分为两大类:基于用户的协同过滤和基于物品的协同过滤。

算法的步骤

1. 获取所有用户行为数据,构建用户-物品评分矩阵。

2. 目标用户与其它用户的相似度计算: 将用户对商品的评分视为向量,计算余弦相似度。

3. 选取与目标用户相似度最高的 k 个用户作为邻居 。

4. 通过邻居用户的评分进行加权平均预测(权重为用户相似度)。

5. 将预测评分按降序排序,选择评分最高的N个物品作为推荐结果。

举例说明

用户评分矩阵的构建

需要借助Array2DRowRealMatrix算法工具,Array2DRowRealMatrix 是 Apache Commons Math 库中的一个类,用于表示二维实数矩阵,并提供矩阵运算功能。

maven依赖如下:

  <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>

构建评分矩阵的代码:

       // 获取所有用户的行为数据,用于构建用户-物品评分矩阵
List<UserBehavior> allBehaviors = userBehaviorRepository.selectList(null); if(CollectionUtils.isEmpty(allBehaviors)) {
return Collections.emptyList();
} // 构建用户和物品的索引映射,方便后续构建评分矩阵
Map<Long, Integer> userIndex = new HashMap<>();
Map<Long, Integer> itemIndex = new HashMap<>();
// 提取用户id
List<Long> users = allBehaviors.stream().map(UserBehavior::getUserId).distinct().collect(Collectors.toList());
// 提取物品id
List<Long> items = allBehaviors.stream().map(UserBehavior::getItemId).distinct().collect(Collectors.toList());
for (int i = 0; i < users.size(); i++) {
userIndex.put(users.get(i), i);
}
for (int i = 0; i < items.size(); i++) {
itemIndex.put(items.get(i), i);
}
// 初始化评分矩阵,行表示用户,列表示物品 一个 users.size() x items.size() 大小的矩阵
RealMatrix ratingMatrix = new Array2DRowRealMatrix(users.size(), items.size());
// 根据用户行为数据填充评分矩阵
for (UserBehavior behavior : allBehaviors) {
if (behavior.getRating() != null) {
int uIndex = userIndex.get(behavior.getUserId());
int iIndex = itemIndex.get(behavior.getItemId());
// 设置 矩阵的 行,列 值 为 评分
ratingMatrix.setEntry(uIndex, iIndex, behavior.getRating());
}
}

余弦相似度计算

   /**
* 计算两个向量的余弦相似度
* 余弦相似度用于衡量两个用户的评分模式的相似程度
* @param vector1 第一个用户的评分向量
* @param vector2 第二个用户的评分向量
* @return 相似度值,范围[-1,1],值越大表示越相似
*/
private double calculateCosineSimilarity(double[] vector1, double[] vector2) {
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0; for (int i = 0; i < vector1.length; i++) {
dotProduct += vector1[i] * vector2[i];
norm1 += vector1[i] * vector1[i];
norm2 += vector2[i] * vector2[i];
} if (norm1 == 0 || norm2 == 0) return 0; return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}

根据余弦相似度计算取5个相似的用户作为邻居

        // 计算目标用户与其他用户的相似度
int userIdx = userIndex.get(user.getId());
Map<Integer, Double> userSimilarities = new HashMap<>(); for (int i = 0; i < users.size(); i++) {
if (i != userIdx) {
// 计算 当前用户 与其他的每一个用户的评分向量的 余弦相似度
double similarity = calculateCosineSimilarity(ratingMatrix.getRow(userIdx), ratingMatrix.getRow(i));
userSimilarities.put(i, similarity);
}
} // 选择最相似的5个用户作为邻居用户
List<Integer> similarUsers = userSimilarities.entrySet().stream()
// 按相似度值降序排序
.sorted(Map.Entry.<Integer, Double>comparingByValue().reversed())
// 取前5个最相似用户
.limit(5)
// 提取用户索引
.map(Map.Entry::getKey)
.collect(Collectors.toList());

最后是计算加权平均,当中还需要进行 归一化处理, 来避免了因用户群体整体相似度偏高/偏低导致的预测偏差,使得推荐结果更贴近用户的真实偏好。

整体代码较长,我就不贴了。

库存系统的设计

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

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

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

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

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

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

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

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

库存扣减的部分代码:

  /**
* 扣减库存(使用Redisson分布式锁)
* @param quantity 扣减数量
* @return true-扣减成功,false-扣减失败(库存不足)
*/
public boolean deductInventory(Integer spuId, int quantity) {
String lockKey = "lock:inventory:" + spuId;
String inventoryKey = "inventory:" + spuId; 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();
}
}
}

  

商品系统的设计

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

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 '商品封面图',
`spu0_price` double NOT NULL COMMENT '参考价,商品第一个spu的价格',
`product_sales` int NOT NULL COMMENT '销量',
`state` tinyint DEFAULT '0' COMMENT '0-上架 1- 下架',
PRIMARY KEY (`product_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='商品';

商品关联的spu规格表:

CREATE TABLE `product_spu` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
`product_id` int NOT NULL COMMENT '商品id',
`spu_name` varchar(100) COLLATE utf8mb4_bin NOT NULL COMMENT '规格的key名称,比如尺码',
`spu_value` varchar(100) COLLATE utf8mb4_bin NOT NULL COMMENT '规格的key的值,比如尺码的大小是S',
`spu_price` double NOT NULL COMMENT '商品售卖价',
`spu_stock` int NOT NULL COMMENT 'spu库存',
`state` tinyint DEFAULT '0' COMMENT '0-上架 1- 下架',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=85 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=276 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC 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=295 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC 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',
`spu_id` int NOT NULL COMMENT '商品id',
`spu_name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'spu的名称',
`spu_value` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'spu的值',
`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) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '退款原因',
`order_remark` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '订单备注',
`pay_type` int DEFAULT NULL COMMENT '支付方式:0-支付宝 1-微信',
`address` varchar(2000) CHARACTER SET utf8mb4 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 ROW_FORMAT=DYNAMIC COMMENT='订单';

 

运费的设计

首先需要有一个模板表 , 上架商品时, 直接选中到这个运费模板

CREATE TABLE `shipping_template` (
`template_id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '模板名称',
`is_free_shipping` tinyint(1) DEFAULT '0' COMMENT '是否包邮(0否1是)',
PRIMARY KEY (`template_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='运费模板表';

每个模板有着自己的运费规则, 规则里面重要的就是城市信息。每个城市的运费都不一样。

CREATE TABLE `shipping_rule` (
`id` int NOT NULL AUTO_INCREMENT,
`template_id` int NOT NULL COMMENT '运费模板ID',
`city_id` int NOT NULL COMMENT '地区编码(可多级)',
`first_fee` double NOT NULL COMMENT '该地域的运费',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='运费规则表';

最后,有一个城市表 , 记录着中国的省市区数据

CREATE TABLE `city` (
`id` int NOT NULL COMMENT '主键',
`name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '省市区名称',
`parentid` int DEFAULT NULL COMMENT '上级ID',
`shortname` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '简称',
`leveltype` tinyint DEFAULT NULL COMMENT '级别:0,中国;1,省分;2,市;3,区、县',
`citycode` varchar(7) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '城市代码',
`zipcode` varchar(7) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邮编',
`lng` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '经度',
`lat` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '纬度',
`pinyin` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '拼音',
`status` enum('0','1') CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC;

三. 技术栈概述

后端技术栈:

JDK8 + springboot + mysql8

前端技术栈:

vue3 + 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 ,否则代码运行会出错。新建一个 clothingshop 数据库, 然后执行  “clothingshop.sql”

Redis安装

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

启动后端项目

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

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

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

五. 访问项目

管理后端:

http://localhost:3001/

账号:wx-hadluo,  密码: 123456

前端:

http://localhost:3000/

用户: wxhadluo / 123456

可以自己注册用户。

springboot+vue实现鲜花商城系统源码(带用户协同过滤个性化推荐算法)的更多相关文章

  1. H5传奇源码,附带微信支付,商城系统,新增了元宝交易商城系统源码

    源码说明:传奇游戏是80年底的经典游戏,传奇源码,H5游戏源码下载,附带微信支付,商城系统,新增了元宝交易商城系统源码,内置很多任务,比如首冲任务,修复了很多BUG.[架设要求]游戏名称:H5传奇世界 ...

  2. 购买的wemall 6.0商城系统源码分享

    使用方法 1.解压目录 2.cd wemall6 && npm i 3.配置config下的config.json 4.npm start 摒弃以往的开发框架thinkphp,使用no ...

  3. Apache mahout 源码阅读笔记--协同过滤, PearsonCorrelationSimilarity

    协同过滤源码路径: ~/project/javaproject/mahout-0.9/core/src $tree main/java/org/apache/mahout/cf/taste/ -L 2 ...

  4. JAVA多用户商城系统源码

    最近公司要搞商城,让我多方咨询,最后看了很多,要不就是代码注释不全,要不就是bug多,要么就是文档缺少,最后决定自己开发一套商城. 下面是开发的一些心得体会,权且记录下来,给自己做个记录把.   网址 ...

  5. 告别IT,出售多年自己研发的股票分析系统源码

    不知已过而立,发狠告别IT,回头看看以前自己的多个作品,耗时最多的就是这个股票分析系统了,留在自己的电脑里也体现不出多大价值了,故打算出售源码给需要的人,联系方式QQ:874724605 注明:股票源 ...

  6. 整合了一个功能强大完善的OA系统源码,php全开源 界面漂亮美观

    整合了一个功能强大完善的OA系统源码,php全开源界面漂亮美观.需要的同学联系Q:930948049

  7. 几个功能强大的系统源码(机票分销、机票预订、OA、手机充值、wifi营销、网络超市、体检平台)

    1.机票分销.机票预订系统源码 2.OA系统源码 3.手机在线充值系统源码 4.wifi营销系统源码 5.网络超市系统源码 6.在线体检平台系统源码 7.违章查询与缴费系统源码 需要的同学请联系QQ: ...

  8. HoverTree系统源码介绍

    HoverTree是一个开源asp.net系统.系统的效果请到:http://hovertree.com体验. 源码描述:一.源码特点采用典型的三层架构进行开发,实现了留言板的功能,后台管理,留言审核 ...

  9. 将Android系统源码导入ecplise

    Android系统源码中带有个IDE的配置文件,目录为:development/ide/ 如果要用eclipse导入查看系统源码,则将development/ide/eclipse/.classpat ...

  10. 安卓系统源码编译系列(六)——单独编译内置浏览器WebView教程

    原文                   http://blog.csdn.net/zhaoxy_thu/article/details/18883015                 本文主要对从 ...

随机推荐

  1. markdown常用数学公式

    常用数学公式示例 单行 $$ f(x)=x $$ \[f(x)=x \] 多行 $$ \sum_i^n + \sum_{i=0}^{n} $$ \[\sum_i^n + \sum_{i=0}^{n} ...

  2. unity纯净版下载地址

    真的服了,unity居然做成这个鸟样,夹带广告,一天一激活... 民间整理的纯净版下载地址 https://unityitellyou.github.io/#/

  3. 时间复杂度O(n):查找盛最多水的容器

    给定一个长度为 n 的整数数组 height .有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) . 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳 ...

  4. 主流PLC串口自由协议通信标准化

    一.PLC串口自由协议通信概述:串口自由协议通信是一种灵活的串行通信方式.在该模式下,开发者无需遵循特定标准协议,可根据实际需求自由定义数据格式与交互规则.通常需明确数据帧结构,例如设置起始字节.数据 ...

  5. LG 8 月月赛

    1 比赛情况 A B C D \(100\) \(100\color{red}{\text{(已被 Hack)}}\) \(45\) \(0\) 2 比赛流程 开场构造 A,构造错了,卡了 \(30\ ...

  6. Dify快速搭建问答系统

    简单记录下Dify系统的部署,以及可能遇到的各种问题,然后演示一下如何快速的搭建一个问答系统. 为什么用Dify 首先回答为什么用大模型的方案.在没有大模型之前,我们只能把问题和答案存储在数据库中,然 ...

  7. 【数据库基石】聚簇索引 vs 非聚簇索引:结构图解、性能差异与最佳实践

    深入解析:聚簇索引 vs 非聚簇索引的核心区别与工作原理 数据库索引设计的必修课 一.核心区别概览 通过对比表快速掌握核心差异: 特性 聚簇索引 非聚簇索引 关键影响 索引数量 每表仅1个 每表可多个 ...

  8. P1600 [NOIP 2016 提高组] 天天爱跑步解析-树上差分+全局桶

    思维难度:cf2300+ 实现方案:贡献计算 方法:线段树合并或者树上差分+桶的统计 思路点补充: 按照题目的设定,如果一个观察员 \(j\) 能够观察到某个人经过,说明 \(j\)一定在第 \(i\ ...

  9. AX-MES生产制造管理系统-设备保养

    对于设备日常维护,我们分为点检与保养,设备点检是指对设备进行定期检查,目的是为了发现设备异常或隐患,确保它们能够按预期进行工作:设备保养则是指对设备进行定期的维护工作,为了保持设备规定状态所做的工作, ...

  10. Java学习:IDEA控制台中文乱码问题

    前两天刚开始学习Java的时候遇见了IDEA控制台中文乱码的问题 [历程一]用网上的方法 通过网上的办法,我最终将Project Encoding改为GBK,然后控制台就不会乱码了,但是很不稳定,有时 ...