1. 项目背景与核心价值
最近在电商领域,垂直类美食推荐平台正在快速崛起。不同于传统综合电商,这类平台更注重个性化推荐和美食场景化运营。我最近刚完成一个企业级美食推荐商城的全栈开发,采用SpringBoot+Vue+MyBatis技术栈,今天就来分享下这个项目的完整架构设计和实现细节。
这个系统最大的特色在于将推荐算法深度整合到电商流程中。用户不仅能像普通商城一样浏览购买,系统还会基于用户画像、购买历史、实时行为等多维度数据,智能推荐符合口味的美食商品。从技术实现来看,项目包含了完整的后台管理系统、移动端H5页面、微信小程序接入能力,以及核心的推荐引擎模块。
2. 技术架构设计解析
2.1 整体架构设计
系统采用前后端分离架构,后端基于SpringBoot 2.7.x构建,前端使用Vue 3组合式API开发。这种架构选择主要基于以下考虑:
- SpringBoot的优势:快速构建微服务、自动配置、内嵌Tomcat简化部署
- Vue 3的革新:Composition API更好组织代码、更好的TypeScript支持
- 分离架构的好处:前后端并行开发、独立部署、技术栈灵活
架构分层如下:
┌─────────────────┐ │ 客户端 │ ← Vue3 + Vant UI ├─────────────────┤ │ API网关 │ ← Spring Cloud Gateway ├─────────────────┤ │ 业务微服务集群 │ ← SpringBoot + MyBatis │ - 用户服务 │ │ - 商品服务 │ │ - 订单服务 │ │ - 推荐服务 │ ├─────────────────┤ │ 数据层 │ ← MySQL + Redis + Elasticsearch └─────────────────┘2.2 数据库设计要点
MySQL作为主数据库,设计了约30张核心表。几个关键设计决策:
用户体系设计:
CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(64) NOT NULL COMMENT '登录账号', `password` varchar(128) NOT NULL COMMENT '加密密码', `salt` varchar(32) NOT NULL COMMENT '加密盐值', `nickname` varchar(64) DEFAULT NULL COMMENT '显示名称', `avatar` varchar(255) DEFAULT NULL COMMENT '头像URL', `taste_tags` json DEFAULT NULL COMMENT '口味偏好标签', PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;商品特色字段:
ALTER TABLE `product` ADD COLUMN `flavor_profile` json DEFAULT NULL COMMENT '风味特征向量', ADD COLUMN `recommend_weight` decimal(5,2) DEFAULT 1.0 COMMENT '推荐权重';特别注意:美食类商品需要特别设计风味特征字段,这是推荐系统的数据基础
3. 核心功能实现细节
3.1 个性化推荐引擎实现
推荐系统采用多策略混合模式:
- 基于内容的推荐:分析商品风味特征(辣度、甜度、口感等)
- 协同过滤:用户-商品交互矩阵分解
- 实时推荐:基于当前会话的点击流分析
核心Java实现片段:
// 混合推荐策略 public List<Product> recommendProducts(Long userId, int size) { // 获取用户画像 UserProfile profile = userService.getUserProfile(userId); // 并行获取各策略结果 CompletableFuture<List<Product>> cfContent = CompletableFuture.supplyAsync( () -> contentBasedRecommender.recommend(profile, size/2)); CompletableFuture<List<Product>> cfCF = CompletableFuture.supplyAsync( () -> cfRecommender.recommend(userId, size/2)); // 合并并去重 return Stream.concat(cfContent.join().stream(), cfCF.join().stream()) .distinct() .limit(size) .collect(Collectors.toList()); }3.2 高并发订单处理
采用分布式锁+库存预扣模式:
@Transactional public Order createOrder(OrderDTO orderDTO) { // 分布式锁防重 String lockKey = "order:lock:" + orderDTO.getUserId(); boolean locked = redisLock.tryLock(lockKey, 10, TimeUnit.SECONDS); if (!locked) { throw new BusinessException("操作太频繁"); } try { // 预扣库存 reduceStock(orderDTO.getItems()); // 生成订单 Order order = assembleOrder(orderDTO); orderMapper.insert(order); // 发送延迟消息检查支付状态 rocketMQTemplate.asyncSend("order-delay-queue", new OrderMessage(order.getId()), new SendCallback(){...}); return order; } finally { redisLock.unlock(lockKey); } }4. 前端工程化实践
4.1 Vue3组合式API优化
商品详情页逻辑组织:
// useProductDetail.js export default function useProductDetail(productId) { const product = ref(null) const recommendations = ref([]) const loading = ref(true) const fetchData = async () => { const [detailRes, recRes] = await Promise.all([ api.getProductDetail(productId), api.getRecommendations(productId) ]) product.value = detailRes.data recommendations.value = recRes.data.list loading.value = false } onMounted(fetchData) return { product, recommendations, loading } }4.2 性能优化方案
- 路由懒加载:
const routes = [ { path: '/detail/:id', component: () => import('./views/ProductDetail.vue') } ]- 图片懒加载:使用Intersection Observer API
- API请求缓存:axios扩展实现GET请求内存缓存
5. 部署与运维实践
5.1 容器化部署方案
Docker Compose编排文件关键部分:
services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - mysql_data:/var/lib/mysql redis: image: redis:6-alpine ports: - "6379:6379" backend: build: ./backend ports: - "8080:8080" depends_on: - mysql - redis5.2 监控告警配置
Prometheus监控指标示例:
- job_name: 'springboot' metrics_path: '/actuator/prometheus' static_configs: - targets: ['backend:8080']Grafana面板需要重点关注:
- JVM内存使用
- API响应时间P99
- MySQL连接池使用率
- Redis缓存命中率
6. 典型问题排查实录
6.1 推荐效果波动问题
现象:新用户推荐结果质量不稳定
排查过程:
- 检查冷启动策略实现
- 验证特征工程处理逻辑
- 分析AB测试分流配置
解决方案:
// 优化后的冷启动处理 public List<Product> recommendForNewUser(User user) { // 1. 基于注册时选择的偏好标签 if (CollectionUtils.isNotEmpty(user.getTasteTags())) { return contentBasedRecommender.recommendByTags(user.getTasteTags()); } // 2. 退回基于热门商品+多样性采样 return hybridRecommender.recommendHotProducts() .stream() .sorted(comparing(p -> Math.random())) .limit(10) .collect(Collectors.toList()); }6.2 库存超卖问题
现象:促销时出现超卖
根本原因:MySQL默认RR隔离级别下的幻读问题
最终方案:
- 采用SELECT...FOR UPDATE悲观锁
- 增加Redis库存缓存层
- 引入分布式事务Seata保障最终一致性
7. 项目演进方向
- 推荐系统升级:引入图神经网络挖掘用户-商品关系
- 搜索体验优化:基于Elasticsearch实现风味语义搜索
- 云原生改造:迁移到Kubernetes集群
- 数据分析平台:构建用户行为数据湖
这个项目从架构设计到具体实现有很多值得分享的细节,特别是在处理高并发订单和构建推荐系统方面。在实际开发中,最大的收获是要平衡系统复杂度和业务需求,避免过度设计。比如在推荐系统初期,先用简单的策略快速验证效果,再逐步引入更复杂的算法。