1. 项目概述:美食分享系统的全栈开发实践
每次看到朋友圈里那些让人垂涎欲滴的美食照片,总忍不住想点赞收藏。但普通社交平台的美食内容太分散,专业的点评网站又过于商业化。这就是为什么我要开发这个轻量级美食分享系统——用技术为吃货们打造一个纯粹的交流空间。
这个基于SpringBoot+Vue的全栈项目,从数据库设计到前后端联调都是亲手搭建。系统不仅实现了常规的图文发布功能,还创新性地加入了地理位置标记和口味标签体系。最让我自豪的是那个智能推荐算法,它能根据用户历史浏览记录,自动匹配相似口味的美食达人。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 后端技术选型
SpringBoot 2.7.4作为后端框架是经过多重考量的结果。相比传统SSM架构,它的自动配置特性让开发效率提升至少40%。特别是处理美食图片上传时,内嵌的Tomcat容器配合MultipartFile接口,文件处理代码量减少了2/3。
数据库选用MySQL 8.0而非MongoDB,主要考虑到:
- 美食数据的关系型特征明显(用户-菜品-店铺的关联查询)
- 事务一致性要求(订单/收藏等业务)
- 地理空间数据处理需求(ST_Distance_Sphere函数计算店铺距离)
java复制// 典型的美食数据查询示例
@Repository
public interface DishRepository extends JpaRepository<Dish, Long> {
@Query("SELECT d FROM Dish d WHERE ST_Distance_Sphere(point(:lng, :lat), d.location) < :radius")
List<Dish> findNearby(@Param("lng") double longitude,
@Param("lat") double latitude,
@Param("radius") int radius);
}
2.2 前端技术方案
Vue 3的组合式API让前端开发体验焕然一新。特别是在实现瀑布流布局时,用useIntersectionObserver实现的懒加载性能比传统监听scroll事件提升60%。项目还引入了这些关键依赖:
- Element Plus:构建管理后台的利器,其Form组件二次封装后,表单开发效率提升50%
- Axios:精心配置的拦截器实现了:
- JWT自动刷新(静默更新accessToken)
- 请求重试机制(针对网络波动场景)
- 全局Loading状态管理
- Vee-Validate:配合i18n实现多语言表单校验
实践发现:Vue的keep-alive配合路由meta配置,使详情页返回列表时能保持滚动位置,用户体验提升显著
3. 核心功能实现细节
3.1 美食发布模块
这个看似简单的功能背后藏着不少技术细节。图片处理采用分层策略:
- 前端先用canvas压缩(保持EXIF信息)
- 后端使用Thumbnailator生成三种尺寸:
- 原图(限制10MB)
- 展示图(1920px宽度,质量80%)
- 缩略图(320px正方形裁剪)
java复制// 图片处理核心代码
public void processImage(MultipartFile file, String destPath) throws IOException {
Thumbnails.of(file.getInputStream())
.size(1920, 1920)
.keepAspectRatio(true)
.outputQuality(0.8)
.toFile(new File(destPath + "_large"));
Thumbnails.of(file.getInputStream())
.size(320, 320)
.keepAspectRatio(false)
.toFile(new File(destPath + "_thumb"));
}
3.2 智能推荐系统
基于协同过滤的推荐算法在初期效果不佳,后来改进为混合推荐模型:
- 基于内容的推荐(菜品标签匹配)
- 用户行为协同过滤(浏览/收藏/点赞)
- 时空维度加权(同城推荐权重+30%)
sql复制-- 推荐算法核心SQL
SELECT d.*,
(tag_similarity * 0.6 + behavior_score * 0.3 + geo_weight * 0.1) AS total_score
FROM dishes d
JOIN (
-- 标签相似度计算
SELECT dish_id, COUNT(*) * 0.1 AS tag_similarity
FROM dish_tags
WHERE tag_id IN (SELECT tag_id FROM user_favorite_tags WHERE user_id = ?)
GROUP BY dish_id
) t1 ON d.id = t1.dish_id
LEFT JOIN (
-- 用户行为评分
SELECT target_id AS dish_id,
SUM(CASE WHEN action_type = 'VIEW' THEN 1
WHEN action_type = 'LIKE' THEN 3
ELSE 5 END) * 0.01 AS behavior_score
FROM user_actions
WHERE user_id = ? AND target_type = 'DISH'
GROUP BY target_id
) t2 ON d.id = t2.dish_id
WHERE d.city_code = ?
ORDER BY total_score DESC
LIMIT 20;
4. 性能优化实战
4.1 缓存策略设计
采用三级缓存架构应对高并发场景:
- 前端localStorage缓存用户个人数据(有效期1天)
- Redis缓存热点数据:
- 美食排行榜(ZSET结构,每5分钟更新)
- 用户关系数据(Hash结构)
- MySQL查询缓存(针对复杂聚合查询)
缓存击穿防护方案:
- 使用Redisson分布式锁实现互斥重建
- 布隆过滤器拦截无效ID请求
java复制public Dish getDishWithCache(Long id) {
String cacheKey = "dish:" + id;
// 一级缓存查询
Dish dish = (Dish) redisTemplate.opsForValue().get(cacheKey);
if (dish != null) return dish;
// 获取分布式锁
RLock lock = redissonClient.getLock("lock:dish:" + id);
try {
lock.lock();
// 双重检查
dish = (Dish) redisTemplate.opsForValue().get(cacheKey);
if (dish != null) return dish;
// 数据库查询
dish = dishRepository.findById(id).orElseThrow();
// 写入缓存并设置随机过期时间(防雪崩)
redisTemplate.opsForValue().set(cacheKey, dish,
30 + ThreadLocalRandom.current().nextInt(30),
TimeUnit.MINUTES);
return dish;
} finally {
lock.unlock();
}
}
4.2 数据库优化
针对美食系统的特点做了这些优化:
- 索引策略:
- 组合索引:(city_code, status, create_time)
- 全文索引:菜品描述字段(支持中文分词)
- 查询优化:
- 禁用SELECT *
- 复杂统计使用物化视图
- 分库分表准备:
- 用户数据按UID范围分片
- 菜品数据按城市分片
5. 部署与监控方案
5.1 容器化部署
采用Docker Compose编排方案:
yaml复制version: '3'
services:
app:
image: openjdk:11-jre
ports:
- "8080:8080"
volumes:
- ./logs:/app/logs
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
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"
volumes:
- redis_data:/data
volumes:
mysql_data:
redis_data:
5.2 监控体系搭建
- Spring Boot Actuator暴露健康指标
- Prometheus + Grafana监控看板:
- JVM内存/线程监控
- 接口QPS/耗时统计
- ELK日志收集系统:
- 关键业务日志标记TraceID
- 错误日志自动触发告警
6. 踩坑经验总结
-
图片处理陷阱:
- 发现某些手机拍摄的照片旋转异常 → 解决方案:使用Apache Sanselan读取EXIF Orientation
- 大文件上传超时 → 调整Nginx配置:
client_max_body_size 20M
-
地理位置查询优化:
- 初期使用Haversine公式计算距离 → 性能差
- 改进方案:MySQL空间索引 + ST_Distance_Sphere
-
推荐算法冷启动问题:
- 新用户没有行为数据 → 增加热门推荐兜底策略
- 新品曝光不足 → 引入时间衰减因子
这个项目让我深刻体会到,一个好的美食分享平台不仅需要扎实的技术实现,更要理解美食爱好者的真实需求。比如那个"深夜食堂"模式(晚上自动切换深色主题),就是收到用户反馈后增加的贴心功能。
