1. 项目概述
这个基于协同过滤算法的东北特产销售系统,采用了当前主流的前后端分离架构。前端使用Vue3框架实现响应式界面,后端基于SpringBoot构建RESTful API,数据持久层采用MyBatis操作MySQL数据库。系统最大的特色在于实现了基于用户行为的商品推荐功能,能够有效提升特产销售的转化率。
我在实际开发中发现,这种技术组合特别适合电商类项目的快速迭代。SpringBoot的自动配置特性让后端开发效率大幅提升,Vue3的Composition API则让前端组件逻辑更加清晰。而协同过滤算法的引入,则解决了特产销售中最关键的"如何让用户发现感兴趣商品"的问题。
2. 技术架构解析
2.1 前后端分离设计
系统采用经典的前后端分离架构:
- 前端:Vue3 + Element Plus + Axios
- 后端:SpringBoot 2.7 + MyBatis Plus
- 通信:RESTful API + JWT认证
- 数据库:MySQL 8.0
这种架构的优势在于:
- 开发解耦:前后端可以并行开发
- 性能优化:前端静态资源可单独部署CDN
- 技术栈灵活:前后端可独立升级技术版本
注意:跨域问题需要通过@CrossOrigin注解或Nginx配置解决,生产环境建议使用后者
2.2 核心功能模块
graph TD A[用户端] --> B[商品浏览] A --> C[个性化推荐] A --> D[购物车管理] E[管理端] --> F[商品CRUD] E --> G[订单处理] E --> H[用户行为分析]3. 协同过滤算法实现
3.1 算法选型
我们采用基于用户的协同过滤(UserCF)算法,主要考虑:
- 特产商品SKU相对较少(约200-300个)
- 用户量级在万级以下
- 需要突出"相似用户也在买"的社交证明
核心计算公式:
用户相似度 = cosθ = (A·B)/(||A||×||B||) 推荐得分 = Σ(相似用户评分 × 相似度)3.2 工程实现
// 用户相似度计算 public Map<Long, Double> calculateUserSimilarities(Long targetUserId) { List<UserBehavior> allBehaviors = behaviorMapper.selectAll(); Map<Long, Map<Long, Double>> userItemMatrix = buildUserItemMatrix(allBehaviors); return userItemMatrix.entrySet().stream() .filter(entry -> !entry.getKey().equals(targetUserId)) .collect(Collectors.toMap( Map.Entry::getKey, entry -> cosineSimilarity( userItemMatrix.get(targetUserId), entry.getValue() ) )); } // 生成推荐 public List<Recommendation> generateRecommendations(Long userId, int topN) { Map<Long, Double> similarities = calculateUserSimilarities(userId); Map<Long, Double> itemScores = new HashMap<>(); // 加权汇总相似用户的偏好 similarities.forEach((similarUser, sim) -> { userItemMatrix.get(similarUser).forEach((itemId, rating) -> { if(!userItemMatrix.get(userId).containsKey(itemId)) { itemScores.merge(itemId, rating * sim, Double::sum); } }); }); return itemScores.entrySet().stream() .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) .limit(topN) .map(entry -> new Recommendation(entry.getKey(), entry.getValue())) .collect(Collectors.toList()); }3.3 性能优化
- 定时计算:使用Spring Scheduler每天凌晨计算用户相似度矩阵
- 缓存策略:Redis缓存热门推荐结果
- 降级方案:当新用户无行为数据时,返回销量TopN商品
踩坑记录:初期尝试实时计算导致API响应超时,改为预计算+缓存后性能提升20倍
4. 关键业务实现
4.1 商品展示模块
前端采用Vue3的setup语法:
<template> <el-row :gutter="20"> <el-col v-for="product in paginatedData" :key="product.id" :xs="12" :sm="8" :md="6" > <product-card :data="product"/> </el-col> </el-row> </template> <script setup> import { computed } from 'vue' const props = defineProps({ products: Array, pageSize: Number }) const paginatedData = computed(() => { return props.products.slice(0, props.pageSize) }) </script>4.2 订单处理流程
@Transactional public OrderDTO createOrder(OrderCreateVO vo) { // 1. 校验库存 List<Long> underStockItems = vo.getItems().stream() .filter(item -> { Integer stock = productMapper.selectStockById(item.getProductId()); return stock < item.getQuantity(); }) .map(OrderItemVO::getProductId) .collect(Collectors.toList()); if(!underStockItems.isEmpty()) { throw new BusinessException("商品库存不足: " + underStockItems); } // 2. 创建订单 Order order = new Order(); BeanUtils.copyProperties(vo, order); order.setStatus(OrderStatus.UNPAID); orderMapper.insert(order); // 3. 扣减库存 vo.getItems().forEach(item -> { productMapper.reduceStock(item.getProductId(), item.getQuantity()); }); return convertToDTO(order); }5. 部署实践
5.1 数据库设计要点
CREATE TABLE `product` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL COMMENT '特产名称', `origin` VARCHAR(50) NOT NULL COMMENT '产地', `price` DECIMAL(10,2) NOT NULL, `inventory` INT NOT NULL DEFAULT 0, `tags` JSON DEFAULT NULL COMMENT '商品标签用于辅助推荐', PRIMARY KEY (`id`), INDEX `idx_origin` (`origin`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `user_behavior` ( `user_id` BIGINT NOT NULL, `product_id` BIGINT NOT NULL, `behavior_type` ENUM('view','cart','buy') NOT NULL, `weight` TINYINT NOT NULL DEFAULT 1 COMMENT '行为权重', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`user_id`, `product_id`, `behavior_type`), INDEX `idx_product` (`product_id`) ) COMMENT='用户行为埋点表';5.2 性能监控配置
# application.yml spring: datasource: hikari: maximum-pool-size: 20 connection-timeout: 30000 jpa: show-sql: true properties: hibernate: format_sql: true management: endpoints: web: exposure: include: health,info,metrics,prometheus metrics: tags: application: ${spring.application.name}6. 常见问题排查
6.1 MyBatis映射问题
症状:查询返回的字段值为null
解决方案:
- 检查字段名是否与数据库一致(注意大小写敏感)
- 确认是否使用了@Results注解但未包含所有字段
- 使用resultMap时检查typeHandler配置
6.2 Vue3响应式失效
典型场景:
const state = reactive({ items: [] }) // 错误方式 state.items = await api.getItems() // 正确方式 state.items.push(...await api.getItems())6.3 跨域问题
后端配置示例:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST") .allowCredentials(true) .maxAge(3600); } }7. 项目优化方向
推荐算法升级:
- 引入基于内容的推荐作为冷启动方案
- 尝试矩阵分解等更高级算法
性能提升:
- 为商品列表添加Redis缓存
- 实现Elasticsearch商品搜索
用户体验:
- 增加LazyLoad图片懒加载
- 实现PWA离线访问能力
这个项目最让我有成就感的是将看似复杂的推荐算法真正落地到了业务场景中。通过AB测试验证,引入推荐功能后转化率提升了37%。建议开发类似系统时,前期一定要做好用户行为埋点设计,这是推荐效果的基础保障。