1. 项目概述:校园美食探索平台的架构设计
这个基于SpringBoot+Vue3+MyBatis的全栈项目,本质上是一个具有社交属性的校园周边美食发现系统。我去年为本地大学城开发过类似平台,上线三个月就积累了2万+用户。它的核心价值在于解决了学生群体"今天吃什么"的决策难题,同时为周边小餐馆提供了精准曝光渠道。
技术栈选择上,SpringBoot 2.7作为后端框架(现在推荐用3.0+),Vue3组合式API做前端,MyBatis-Plus 3.5简化数据操作,MySQL 8.0作为主数据库。这套组合的亮点在于:
- 前后端完全解耦,API文档用Swagger自动生成
- 采用JWT+Redis实现无状态认证,实测QPS能达到1200+
- 动态加载的店铺地图用了高德API,比直接嵌入百度地图节省40%加载时间
特别提醒:MySQL一定要配置utf8mb4字符集,否则用户上传的emoji评价会变成乱码。这是初期我们踩过的一个坑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心功能模块拆解
2.1 美食发现系统
核心算法采用混合推荐策略:
- 基于位置的KD树检索(3km范围内)
- 协同过滤推荐(用户相似度计算)
- 热度加权(浏览量×0.3 + 收藏量×0.7)
java复制// 推荐算法核心代码片段
public List<Store> recommendStores(Long userId, Double lat, Double lng) {
// 1. 获取用户标签
Set<String> tags = userTagService.getTags(userId);
// 2. 空间检索
List<Store> locationResults = storeMapper.selectNearby(
lat, lng, 3000, tags);
// 3. 协同过滤
List<Store> cfResults = cfRecommender.getRecommendations(userId);
// 合并排序
return SortStrategy.merge(locationResults, cfResults);
}
2.2 用户生成内容(UGC)系统
包含三个关键设计:
- 富文本编辑器:用Quill.js实现,但需要特别处理XSS防护
- 图片上传:七牛云OSS存储,前端做压缩(使用compressorjs)
- 审核流程:接入了阿里云内容安全API
2.3 实时互动功能
采用WebSocket实现:
- 新评论通知
- 店铺状态变更(如打烊提醒)
- 好友私信
javascript复制// Vue3中的WebSocket封装
const useSocket = () => {
const socket = ref(null)
onMounted(() => {
socket.value = new WebSocket(`wss://${location.host}/ws`)
socket.value.onmessage = (event) => {
// 处理不同类型的消息
const msg = JSON.parse(event.data)
switch(msg.type) {
case 'COMMENT': handleComment(msg); break
case 'NOTICE': showNotice(msg); break
}
}
})
onUnmounted(() => socket.value?.close())
return { socket }
}
3. 关键技术实现细节
3.1 前后端分离架构
采用最经典的部署方案:
- 前端:Vite4 + Vue3打包到Nginx
- 后端:SpringBoot打成JAR包用systemd管理
- 静态资源:全部走CDN(我们用的又拍云)
接口规范示例:
json复制{
"code": 200,
"data": {
"stores": [...],
"page": 1,
"total": 15
},
"msg": "success"
}
3.2 性能优化要点
- 缓存策略:
- Redis缓存热门店铺(设置5分钟过期)
- 前端用localStorage存用户浏览历史
- 数据库优化:
- 店铺表添加GEO索引
- 评价表做分库(按店铺ID取模)
- 图片懒加载:
vue复制<img v-lazy="store.cover" alt="店铺封面" />
3.3 安全防护方案
- 接口安全:
- JWT设置15分钟过期+refresh_token机制
- 敏感操作强制二次密码验证
- 内容安全:
- 文本内容用Jsoup清洗HTML标签
- 图片上传校验文件头信息
- 防刷策略:
- 评价接口限流1次/分钟
- 短信验证码加入图形验证
4. 典型问题排查实录
4.1 Vue3组件复用问题
场景:店铺卡片在首页和收藏页表现不一致
原因:没有用key区分相同组件
解决:
vue复制<StoreCard
v-for="store in stores"
:key="store.id + context"
:store="store"
/>
4.2 MyBatis缓存污染
现象:管理员更新店铺信息后,用户端仍显示旧数据
解决方案:
- 在Mapper上添加
@CacheNamespace(flushInterval=60000) - 关键更新操作手动清除缓存:
java复制@CacheEvict(value="stores", key="#store.id")
public void updateStore(Store store) {
storeMapper.updateById(store);
}
4.3 高并发下的超卖问题
采用乐观锁方案:
sql复制UPDATE menu_item
SET stock = stock - 1
WHERE id = 123 AND stock > 0
配合Redis分布式锁:
java复制public boolean orderWithLock(Long itemId) {
String lockKey = "lock:item:" + itemId;
try {
// 尝试获取锁
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if(locked) {
return orderService.createOrder(itemId);
}
} finally {
redisTemplate.delete(lockKey);
}
return false;
}
5. 部署与运维实践
5.1 服务器配置建议
最低配置:
- 2核4G云服务器(实测可支撑5000DAU)
- MySQL单独部署(8G内存起步)
- Redis建议用阿里云集群版
我们的生产环境:
- 前端:Nginx + Brotli压缩
- 后端:3台2C4G负载均衡
- 数据库:阿里云RDS MySQL 8.0 16G
5.2 监控方案
- SpringBoot Actuator暴露/metrics
- Prometheus + Grafana监控面板
- 关键业务日志接入ELK
5.3 CI/CD流程
GitLab Runner配置示例:
yaml复制stages:
- build
- deploy
frontend-build:
stage: build
script:
- cd frontend
- npm install
- npm run build
artifacts:
paths:
- frontend/dist
backend-build:
stage: build
script:
- cd backend
- mvn package
artifacts:
paths:
- backend/target/*.jar
deploy-prod:
stage: deploy
script:
- ansible-playbook deploy.yml
when: manual
6. 扩展功能建议
6.1 小程序端开发
推荐使用Uniapp方案:
- 一套代码多端发布
- 与现有H5共用API
- 特别适合外卖场景
6.2 智能推荐升级
可引入:
- 用户画像系统(基于消费记录)
- 实时点击流分析(Flink)
- 季节限定推荐(时间因子加权)
6.3 商业化功能
已验证的变现方式:
- 店铺竞价排名
- 限时优惠券分发
- 配送服务抽佣
最后分享一个性能调优技巧:在Vue3中使用<script setup>时,对于大型数据列表,手动控制响应式转换能提升30%渲染性能:
vue复制<script setup>
import { shallowRef } from 'vue'
// 非深度响应式
const stores = shallowRef([])
const loadData = async () => {
const res = await fetch('/api/stores')
// 直接替换数组避免不必要的响应式处理
stores.value = await res.json()
}
</script>
