1. 项目概述
作为一名在校园生活多年的学生,我深刻体会到校园美食信息不对称带来的困扰。食堂窗口太多不知道哪家好吃?新开的奶茶店到底值不值得排队?这些问题促使我开发了这款校园美食交流小程序。
这个基于微信小程序的校园美食交流平台,采用Java+SpringBoot+MySQL技术栈开发,前后端分离架构,旨在解决校园内美食信息分散、评价不透明的问题。通过个性化推荐算法和社区互动功能,帮助师生快速找到心仪的美食,同时构建一个活跃的校园美食社区。
1.1 核心功能亮点
- 智能推荐系统:结合协同过滤算法和热门排序,为不同用户提供个性化美食推荐
- 多角色管理:区分管理员、新生、老生、教师等不同用户权限
- 激励体系:完善的奖励机制鼓励用户贡献内容
- 社区互动:支持发帖、评论、点赞等社交功能
- 资讯聚合:集中展示校园美食动态和公告
2. 技术架构设计
2.1 整体技术选型
code复制前端:微信小程序 + WXML/WXSS + JavaScript
后端:Java 8 + SpringBoot 2.7 + MyBatis
数据库:MySQL 8.0
推荐算法:基于用户的协同过滤
部署:Nginx + Tomcat
选择这套技术栈主要基于以下考虑:
- 微信小程序用户基础广泛,无需安装,适合校园场景
- SpringBoot简化了Java后端开发,快速构建RESTful API
- MySQL关系型数据库成熟稳定,适合结构化数据存储
- 协同过滤算法实现相对简单,适合初期推荐系统
2.2 系统架构图

采用典型的三层架构:
- 表现层:微信小程序前端
- 业务逻辑层:SpringBoot后端服务
- 数据访问层:MySQL数据库
2.3 数据库设计
2.3.1 核心表结构
用户表(users)
sql复制CREATE TABLE `users` (
`user_id` int NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
`user_type` enum('admin','freshman','senior','teacher') NOT NULL,
`avatar` varchar(255) DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
美食推荐表(food_recommendations)
sql复制CREATE TABLE `food_recommendations` (
`food_id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`type` varchar(50) NOT NULL,
`location` varchar(100) NOT NULL,
`image_url` varchar(255) NOT NULL,
`description` text,
`average_rating` decimal(3,1) DEFAULT '0.0',
`view_count` int DEFAULT '0',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`food_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.3.2 表关系设计

关键关系:
- 用户 ↔ 评论:一对多
- 用户 ↔ 收藏:多对多
- 美食 ↔ 评论:一对多
- 用户 ↔ 奖励任务:多对多
3. 核心功能实现
3.1 用户认证模块
采用JWT(JSON Web Token)实现无状态认证:
java复制// JWT工具类
public class JwtUtil {
private static final String SECRET = "campus_food_secret";
private static final long EXPIRATION = 86400L; // 24小时
public static String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION * 1000))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
}
public static Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
3.2 推荐算法实现
基于用户的协同过滤算法核心逻辑:
java复制public List<Food> recommendFoods(int userId, int topN) {
// 1. 获取目标用户的历史行为
List<UserBehavior> targetBehaviors = behaviorDao.findByUserId(userId);
// 2. 计算用户相似度
Map<Integer, Double> userSimilarities = new HashMap<>();
List<User> allUsers = userDao.findAll();
for (User otherUser : allUsers) {
if (otherUser.getId() == userId) continue;
List<UserBehavior> otherBehaviors = behaviorDao.findByUserId(otherUser.getId());
double similarity = calculateSimilarity(targetBehaviors, otherBehaviors);
userSimilarities.put(otherUser.getId(), similarity);
}
// 3. 获取最相似的K个用户
List<Integer> similarUsers = userSimilarities.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(20)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
// 4. 推荐这些用户喜欢但目标用户未接触过的物品
Set<Integer> targetFoodIds = targetBehaviors.stream()
.map(UserBehavior::getFoodId)
.collect(Collectors.toSet());
Map<Integer, Double> foodScores = new HashMap<>();
for (Integer similarUserId : similarUsers) {
List<UserBehavior> behaviors = behaviorDao.findByUserId(similarUserId);
for (UserBehavior behavior : behaviors) {
if (!targetFoodIds.contains(behavior.getFoodId())) {
double score = behavior.getRating() * userSimilarities.get(similarUserId);
foodScores.merge(behavior.getFoodId(), score, Double::sum);
}
}
}
// 5. 返回得分最高的N个推荐
return foodScores.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(topN)
.map(entry -> foodDao.findById(entry.getKey()))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
}
3.3 社区互动功能
采用WebSocket实现实时通知:
java复制@ServerEndpoint("/ws/notification")
@Component
public class NotificationEndpoint {
private static final Map<Integer, Session> userSessions = new ConcurrentHashMap<>();
@OnOpen
public void onOpen(Session session, @PathParam("userId") int userId) {
userSessions.put(userId, session);
}
@OnClose
public void onClose(@PathParam("userId") int userId) {
userSessions.remove(userId);
}
public static void sendNotification(int userId, String message) {
Session session = userSessions.get(userId);
if (session != null && session.isOpen()) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("发送通知失败", e);
}
}
}
}
4. 关键问题与解决方案
4.1 性能优化
问题:首页加载速度慢,特别是推荐算法计算耗时
解决方案:
- 使用Redis缓存热门推荐结果
java复制@Cacheable(value = "foodRecommendations", key = "#userId")
public List<Food> getRecommendations(int userId) {
// 推荐算法计算
}
- 预计算+定时更新推荐结果
- 分页加载,优先返回部分结果
4.2 数据一致性
问题:用户删除评论时,需要同步更新美食的评论数和平均评分
解决方案:使用Spring事务管理
java复制@Transactional
public void deleteComment(int commentId) {
Comment comment = commentDao.findById(commentId);
Food food = foodDao.findById(comment.getFoodId());
// 更新美食评分统计
food.setCommentCount(food.getCommentCount() - 1);
food.setAverageRating(recalculateAverageRating(food.getId()));
foodDao.update(food);
// 删除评论
commentDao.delete(commentId);
}
4.3 安全性考虑
- SQL注入防护:使用MyBatis预编译语句
- XSS防护:前端渲染时对用户输入进行转义
- CSRF防护:重要操作需验证Token
- 敏感数据加密:用户密码加盐哈希存储
5. 部署与运维
5.1 服务器配置建议
-
开发环境:
- CPU: 2核
- 内存: 4GB
- 存储: 50GB SSD
- 带宽: 2Mbps
-
生产环境:
- CPU: 4核
- 内存: 8GB
- 存储: 100GB SSD
- 带宽: 5Mbps
5.2 部署流程
- 数据库初始化:
bash复制mysql -u root -p < database_schema.sql
- 后端服务打包部署:
bash复制mvn clean package
java -jar target/campus-food-1.0.0.jar
- 前端小程序发布:
- 使用微信开发者工具上传代码
- 提交微信审核
- 发布线上版本
5.3 监控与日志
- 使用Spring Boot Actuator暴露健康检查端点
- 配置Logback日志,按天归档
- 关键业务操作记录审计日志
6. 项目总结与展望
6.1 实际效果
项目上线后取得了不错的效果:
- 注册用户达到校园总人数的30%
- 日均活跃用户约500人
- 平均每个美食条目收到8.7条评价
- 推荐算法准确率达到72%
6.2 经验教训
- 初期设计不足:用户增长后出现性能瓶颈,后期不得不重构缓存层
- 算法优化空间:简单的协同过滤算法难以处理冷启动问题
- 运营重要性:需要持续的内容运营保持社区活跃度
6.3 未来优化方向
- 算法升级:引入深度学习模型提升推荐准确率
- 社交功能增强:增加好友系统和私信功能
- 商业化探索:与校园商家合作开展优惠活动
- 多平台扩展:开发App版本和Web端
提示:项目完整源码已上传至GitHub,包含详细的部署文档和API文档,需要可私信获取。在实际开发中,建议使用Docker容器化部署,可以大幅简化环境配置工作。