SpringBoot+Vue3高校饮食推荐系统开发实践
1. 项目概述这个基于Java SpringBootVue3MyBatis的高校学生饮食推荐系统是一个典型的前后端分离架构应用。系统通过分析学生的饮食偏好、消费习惯和营养需求为高校学生提供个性化的餐饮推荐服务。我在开发过程中发现这种系统不仅能帮助学生解决今天吃什么的难题还能为食堂管理者提供数据支持优化菜品供应结构。系统采用MySQL作为数据库充分发挥了SpringBoot的快速开发特性和Vue3的响应式优势。前后端分离的设计让开发和部署更加灵活MyBatis作为ORM框架则简化了数据库操作。下面我将从技术选型、系统设计和实现细节三个方面详细解析这个项目的开发过程。2. 技术栈选型分析2.1 后端技术选择SpringBoot作为后端框架的选择主要基于以下几个考虑自动配置特性大幅减少了XML配置内嵌Tomcat服务器简化了部署流程丰富的starter依赖可以快速集成各种功能模块完善的生态和社区支持在实际开发中我们特别使用了Spring Security进行权限控制Spring Cache管理缓存以及Spring Data JPA的部分特性辅助MyBatis。2.2 前端框架考量Vue3相比Vue2有几个显著优势Composition API提供了更好的代码组织方式更小的打包体积和更快的渲染速度更好的TypeScript支持更灵活的逻辑复用方式我们特别利用了Vue3的setup语法糖、ref和reactive响应式API以及Pinia状态管理库。Element Plus作为UI组件库提供了丰富的预制组件。2.3 数据库选型MySQL 8.0作为关系型数据库的选择理由高校饮食数据具有明确的结构化特征事务支持确保数据一致性成熟的索引机制优化查询性能丰富的社区资源和工具支持我们在表设计时特别注意了范式化同时针对热点查询做了适当的反范式优化。3. 系统架构设计3.1 整体架构系统采用经典的三层架构表现层Vue3前端应用业务逻辑层SpringBoot后端服务数据访问层MyBatisMySQL前后端通过RESTful API交互使用JWT进行身份认证。特别设计了API网关统一处理跨域、鉴权和限流。3.2 数据库设计核心表包括用户表(student_info)菜品表(dish_info)食堂表(canteen_info)消费记录表(consumption_record)评价表(rating)推荐记录表(recommendation)我们建立了适当的索引和外键约束同时使用触发器维护部分统计字段。3.3 推荐算法设计系统采用混合推荐策略基于内容的推荐分析菜品特征相似度协同过滤根据相似用户的口味推荐热门推荐近期受欢迎的菜品随机推荐增加多样性算法实现上使用了Java的Mahout库并针对高校场景做了定制优化。4. 关键功能实现4.1 用户认证模块采用JWT实现无状态认证// 生成Token示例 public String generateToken(UserDetails userDetails) { MapString, Object claims new HashMap(); return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() JWT_TOKEN_VALIDITY * 1000)) .signWith(SignatureAlgorithm.HS512, secret) .compact(); }前端使用axios拦截器自动携带Tokenaxios.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config })4.2 推荐引擎实现核心推荐逻辑public ListDish recommendDishes(Long studentId) { // 获取用户特征 StudentPreference preference preferenceMapper.selectByStudentId(studentId); // 基于内容的推荐 ListDish contentBased contentBasedRecommender.recommend(preference); // 协同过滤推荐 ListDish cfBased cfRecommender.recommend(studentId); // 合并结果并去重 return mergeAndDeduplicate(contentBased, cfBased); }4.3 前后端数据交互典型API设计示例RestController RequestMapping(/api/dishes) public class DishController { Autowired private DishService dishService; GetMapping(/recommend) public ResponseEntityListDishDTO getRecommendations( RequestParam Long studentId, RequestParam(defaultValue 10) int limit) { return ResponseEntity.ok(dishService.getRecommendations(studentId, limit)); } }前端调用示例const fetchRecommendations async (studentId) { try { const res await axios.get(/api/dishes/recommend, { params: { studentId } }); return res.data; } catch (error) { console.error(获取推荐失败:, error); return []; } }5. 性能优化实践5.1 数据库优化索引优化为常用查询字段建立复合索引CREATE INDEX idx_dish_canteen ON dish_info(canteen_id, category);查询优化避免SELECT *使用分页Select(SELECT id, name, price FROM dish_info WHERE canteen_id #{canteenId} LIMIT #{offset}, #{limit}) ListDish selectByCanteen(Param(canteenId) Long canteenId, Param(offset) int offset, Param(limit) int limit);缓存策略使用Redis缓存热点数据5.2 前端性能优化组件懒加载const RecommendList defineAsyncComponent(() import(./components/RecommendList.vue) )图片懒加载img v-lazydish.imageUrl alt菜品图片API请求合并与防抖5.3 推荐算法优化离线计算定时任务预先计算推荐结果增量更新用户行为实时更新推荐模型结果缓存缓存推荐结果减少重复计算6. 安全防护措施6.1 SQL注入防护MyBatis严格使用#{}参数绑定select idselectByConditions resultTypeDish SELECT * FROM dish_info WHERE name LIKE CONCAT(%, #{name}, %) AND price BETWEEN #{minPrice} AND #{maxPrice} /select6.2 XSS防护前端使用DOMPurify净化输入import DOMPurify from dompurify; const clean DOMPurify.sanitize(userInput);后端统一过滤敏感字符public String filterXSS(String value) { if (value null) return null; return value.replaceAll(, lt;) .replaceAll(, gt;); }6.3 CSRF防护虽然使用JWT后CSRF风险降低但仍采取了以下措施关键操作需要二次确认敏感接口使用POST而非GET设置SameSite cookie属性7. 部署与监控7.1 多环境配置SpringBoot profiles配置不同环境# application-dev.yml server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/campus_food_dev7.2 容器化部署使用Docker编排# 后端Dockerfile示例 FROM openjdk:11 COPY target/campus-food.jar app.jar ENTRYPOINT [java,-jar,/app.jar]7.3 监控方案Spring Boot Actuator提供健康检查Prometheus Grafana监控系统指标ELK日志收集分析8. 开发中的经验总结8.1 前后端协作经验使用Swagger维护API文档定义统一的响应格式{ code: 200, message: success, data: {} }约定错误代码规范8.2 性能调优心得数据库查询N1问题解决// 使用MyBatis的SelectProvider实现联合查询 SelectProvider(type DishSqlProvider.class, method selectWithCanteen) ListDishWithCanteen selectWithCanteen();Vue组件性能优化合理使用v-if和v-show避免不必要的响应式数据使用computed缓存计算结果8.3 推荐算法改进方向引入时间因素考虑早中晚餐不同需求天气影响不同天气推荐不同菜品社交因素好友喜欢的菜品加权推荐9. 常见问题解决方案9.1 跨域问题SpringBoot配置CORSConfiguration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(*) .allowedMethods(*) .allowedHeaders(*); } }9.2 页面刷新404Vue Router配置const router createRouter({ history: createWebHistory(), routes, }) // 后端需要配置所有路由指向index.html9.3 MyBatis动态SQL使用