1. 项目概述
黔醉酒业白酒销售系统是一个基于SpringBoot+Vue技术栈的电商平台,核心特色是采用协同过滤算法实现个性化推荐功能。这个项目特别适合作为计算机相关专业的毕业设计或课程设计选题,因为它完整覆盖了企业级应用开发的典型技术要素。
我在实际开发中发现,这类酒类电商系统有几个关键需求点:一是需要处理高并发的商品浏览和订单提交,二是要建立精准的用户画像实现营销转化,三是后台管理需要完善的权限控制和数据可视化。本系统通过前后端分离架构很好地平衡了这些需求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 前端技术选型
Vue.js 2.x作为前端框架,配合以下技术栈:
- Element UI:构建管理后台界面组件
- Axios:处理HTTP请求
- Vue Router:实现前端路由
- Vuex:状态管理方案
- ECharts:数据可视化展示
提示:项目采用Vue CLI 4.x脚手架初始化,建议Node.js版本保持在14-16之间以避免兼容性问题。
2.2 后端技术方案
SpringBoot 2.7.x作为后端核心框架,主要模块包括:
- Spring Security:认证与授权
- MyBatis-Plus:数据库操作
- Redis:缓存和会话管理
- Swagger:API文档生成
- Lombok:简化实体类开发
数据库使用MySQL 8.0,需要特别配置:
sql复制CREATE DATABASE liquor_sales
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
3. 核心功能实现
3.1 协同过滤推荐算法
系统采用基于用户的协同过滤算法,主要实现步骤:
- 用户-商品评分矩阵构建
java复制public Map<Long, Map<Long, Double>> buildUserItemMatrix() {
// 从数据库获取用户行为数据
List<UserBehavior> behaviors = behaviorMapper.selectList(null);
// 构建稀疏矩阵
Map<Long, Map<Long, Double>> matrix = new HashMap<>();
behaviors.forEach(behavior -> {
matrix.computeIfAbsent(behavior.getUserId(), k -> new HashMap<>())
.put(behavior.getProductId(), behavior.getScore());
});
return matrix;
}
- 相似度计算(余弦相似度)
java复制public double cosineSimilarity(Map<Long, Double> user1, Map<Long, Double> user2) {
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
// 计算共同评分项
Set<Long> commonItems = new HashSet<>(user1.keySet());
commonItems.retainAll(user2.keySet());
for (Long itemId : commonItems) {
dotProduct += user1.get(itemId) * user2.get(itemId);
}
// 计算范数
for (double rating : user1.values()) {
norm1 += Math.pow(rating, 2);
}
for (double rating : user2.values()) {
norm2 += Math.pow(rating, 2);
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
- 生成TOP-N推荐
java复制public List<Recommendation> generateRecommendations(Long userId, int topN) {
// 获取目标用户评分向量
Map<Long, Double> targetUser = userItemMatrix.get(userId);
// 计算与其他用户的相似度
Map<Long, Double> similarities = new HashMap<>();
userItemMatrix.forEach((otherUserId, otherUserVector) -> {
if (!otherUserId.equals(userId)) {
similarities.put(otherUserId, cosineSimilarity(targetUser, otherUserVector));
}
});
// 排序并获取最相似的K个用户
List<Long> similarUsers = similarities.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(30)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
// 预测评分并生成推荐
return similarUsers.stream()
.flatMap(similarUser -> userItemMatrix.get(similarUser).entrySet().stream())
.filter(entry -> !targetUser.containsKey(entry.getKey()))
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.averagingDouble(Map.Entry::getValue)
))
.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(topN)
.map(entry -> new Recommendation(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
3.2 高并发订单处理
采用Redis缓存+消息队列的方案:
- 商品库存预扣减
java复制public boolean preDeductStock(Long productId, int quantity) {
String key = "product:stock:" + productId;
Long value = redisTemplate.opsForValue().decrement(key, quantity);
if (value != null && value >= 0) {
// 发送库存变更消息到RabbitMQ
rabbitTemplate.convertAndSend(
"stock.exchange",
"stock.update",
new StockMessage(productId, quantity)
);
return true;
} else {
// 库存不足,恢复预扣减
redisTemplate.opsForValue().increment(key, quantity);
return false;
}
}
- 订单超时取消设计
java复制@Scheduled(fixedRate = 60000) // 每分钟检查一次
public void cancelUnpaidOrders() {
List<Order> unpaidOrders = orderMapper.selectUnpaidOrders(30); // 30分钟未支付
unpaidOrders.forEach(order -> {
// 恢复库存
order.getItems().forEach(item -> {
redisTemplate.opsForValue().increment(
"product:stock:" + item.getProductId(),
item.getQuantity()
);
});
// 更新订单状态
order.setStatus(OrderStatus.CANCELLED);
orderMapper.updateById(order);
});
}
4. 系统部署方案
4.1 开发环境配置
前端开发环境:
bash复制# 安装依赖
npm install
# 启动开发服务器
npm run serve
# 生产环境构建
npm run build
后端启动配置:
yaml复制server:
port: 8080
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/liquor_sales?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: localhost
port: 6379
4.2 生产环境部署
使用Docker Compose编排:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: liquor_sales
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
ports:
- "3306:3306"
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
- ./redis/data:/data
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
5. 常见问题解决
5.1 跨域问题解决方案
后端配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
5.2 推荐效果优化技巧
- 冷启动问题处理:
- 新用户推荐:基于商品热度推荐
sql复制SELECT product_id, COUNT(*) as hot
FROM order_items
GROUP BY product_id
ORDER BY hot DESC
LIMIT 10;
- 数据稀疏性优化:
- 采用混合推荐策略(内容+协同)
- 设置最小共同评分项阈值(至少5个共同评价商品)
- 实时性保障:
java复制@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点更新
public void refreshRecommendModel() {
userItemMatrix = buildUserItemMatrix();
// 预热缓存
userService.list().forEach(user -> {
List<Recommendation> recs = generateRecommendations(user.getId(), 10);
redisTemplate.opsForValue().set(
"user:rec:" + user.getId(),
recs,
24, TimeUnit.HOURS
);
});
}
6. 项目扩展方向
- 营销功能增强:
- 限时秒杀(Redis原子计数器+库存预热)
- 优惠券系统(领取与核销逻辑)
- 数据分析模块:
- 用户购买路径分析
- 销售漏斗可视化
- 微服务改造:
- 将推荐服务独立部署
- 引入Spring Cloud Gateway统一网关
- 移动端适配:
- 开发微信小程序版本
- 对接App推送系统
我在实际开发中发现,这类电商系统的性能瓶颈往往出现在商品详情页和推荐计算环节。建议在正式环境中对这两个模块做好压力测试,可以使用JMeter模拟并发请求,根据测试结果合理调整线程池和缓存策略。
