SpringBoot校园餐厅评价系统实战:从架构设计到部署避坑全指南
2026/9/16 4:38:30 网站建设 项目流程

SpringBoot做校园餐厅评价系统,这个选题说实话在毕设里属于“看起来平平无奇、做起来大有文章”的类型。很多同学一听到“点评系统”就觉得是CRUD堆功能,结果做完才发现要么太单薄答辩没东西讲,要么业务逻辑一团乱线,代码改都改不动。我前前后后帮人复现和改造过几个类似的食堂评价平台,这里直接把拆解思路、技术选型和踩坑实录一次性讲透,希望能帮你把这个项目做出真正的区分度。

1. 项目概述与场景解构

1.1 这个系统到底要解决什么问题

高校食堂一直有个尴尬的局面:学生想吃合口的饭菜,只能靠同学口口相传;食堂档口想知道自己哪道菜受欢迎,只能靠卖得好不好猜;学校后勤想要提升餐饮服务质量,又缺乏量化的评价数据。这三方其实是互相有需求的,但缺少一个能沉淀评价数据的平台。

这个项目就是来补这个缺口的。学生登录后可以按餐厅、按菜品维度去打分和写评语,同时能看到其他人的推荐;食堂管理者可以查看自己档口的评分趋势和热门菜品;系统管理员负责审核内容、管理用户和统计数据。一句话概括:用SpringBoot做后端接口层,承载用户、餐厅、菜品、评论、点赞、收藏、通知等核心业务模块,配合前端页面形成完整的评价闭环。

1.2 适合谁做、能学到什么

如果你处于这几个状态,这个项目会非常合适:

  • 有Java SE基础、正在学SpringBoot但缺一个能写进简历的完整项目;
  • 准备考研复试需要展示工程能力,但不想做大而全的电商或管理系统;
  • 找工作想证明自己会用主流技术栈做实际业务,而不是只会写增删改查;
  • 对前后端交互、RESTful接口设计、数据库建模等工程化实践有兴趣。

做完这个项目,你得到的核心能力有三块:第一,真正理解SpringBoot的自动装配、起步依赖、配置文件绑定这些机制在实际项目中是怎么运作的;第二,掌握一套从建表到接口开发到联调到部署的完整流程,这种节奏感比单个技术点的掌握重要得多;第三,能说出每个表为什么这么设计、接口为什么这么划分,这在答辩时是实打实的加分项。

2. 技术选型与架构设计思路

2.1 为什么核心框架选SpringBoot而不是SSH或SSM

老牌的SSH和SSM不是不能用,但想用它们把项目搭起来,光环境配置就能耗掉一周。SpringBoot最大的价值在于它把“约定大于配置”落到了实处。起步依赖直接拉取整套兼容的依赖版本,比如引入spring-boot-starter-web,就自动带上了Spring MVC、内嵌Tomcat和Jackson;引入spring-boot-starter-data-jpa或mybatis相关启动器,就免去了手写SqlSessionFactory等一堆配置。

我特别建议你打开项目的pom.xml去挨个看依赖,这对面试“SpringBoot框架”相关提问非常管用。比如spring-boot-starter-test里为什么自带JUnit 5和Mockito,spring-boot-maven-plugin插件打包时做了什么,都是高频考点。

2.2 完整技术栈选型清单

层次选型思考过程
后端核心框架SpringBoot 2.7.x选择2.x而不是3.x,是因为绝大多数毕设和教学资料都基于2.x,遇到问题能找到的解决方案多,而且对JDK版本要求更友好
持久层MyBatis-Plus自定义SQL满足报表统计类查询,同时内置BaseMapper和LambdaQueryWrapper把简单的CRUD代码量砍掉一大半
数据库MySQL 5.7 / 8.0数据规模小,表结构清晰,事务和索引机制成熟稳定
前端Vue 2 / 3 + Element UI按你熟悉程度选择,如果时间紧可以直接用Vue 2 + Element UI,资料最全
权限控制Spring Security + JWT登录认证和接口鉴权一套搞定,JWT无状态设计天然适配前后端分离
缓存Redis用于存储验证码、热门餐厅排行榜、在线用户状态,避免每次请求都打数据库
接口文档Knife4j / Swagger自动生成可调试的API文档,联调和答辩演示都方便
部署Docker + Nginx展示工程化意识,用Docker镜像打包后端,Nginx反向代理前端静态资源

这里要解释一下权限控制这个选型。很多学生为了贪图方便,直接用拦截器判断session里有没有用户,但Spring Security + JWT这套组合的含金量更高。JWT本身是一个经过签名的JSON字符串,服务端不用保存会话状态,用户在登录后将token放在请求头里,后端通过过滤器解析验证,天然适合前后端分离和多终端复用。虽然学习曲线陡一点,但搞明白它的过滤器链结构和认证流程,面试时能讲的东西就非常多了。

2.3 项目目录结构与分层思路

我推荐采用标准的分层架构,虽然看起来比controller-service-mapper三层多了一点东西,但职责边界清晰,后续加功能不会牵一发动全身:

src/main/java/com/campus/canteen ├── common // 通用工具类、统一返回结果、全局异常处理 ├── config // 配置类:JWT过滤器、Redis配置、CORS跨域配置 ├── controller // 接口层:只负责接收参数和返回结果 ├── service // 业务层:编写业务逻辑和事务控制 ├── mapper // 数据访问层:放MyBatis-Plus的Mapper接口和自定义SQL ├── entity // 实体类:与数据库表字段一一对应 ├── dto // 数据传输对象:比如登录请求、评价提交参数的封装 ├── vo // 视图对象:返回到前端展现层的数据结构 └── utils // JWT生成解析、文件存储等工具方法

有人可能会觉得entity和dto重复建类很麻烦,但在实际开发中,数据库表字段一定会比前端需要的数据多,比如用户表里有密码字段,返回用户信息时绝不能把它带出去。用dto和vo来隔离,既安全又灵活。

3. 数据库设计:评价系统的核心地基

3.1 数据表整体规划

数据库设计在这个项目里决定了一半的成败。我见过很多版本的表结构,要么五张表走天下,要么设计冗余字段搞得更新的时候各种不一致。这里给出一套我验证过的完整方案,包含10张核心表:

  • 用户表(user):id、username、password(BCrypt加密存储)、nickname、avatar、role(0学生/1食堂管理员/2系统管理员)、status、create_time
  • 餐厅表(canteen):id、name、location、description、image、avg_rating、rating_count、status、create_time
  • 菜品表(dish):id、canteen_id、name、image、price、description、monthly_sales、status
  • 评价表(comment):id、user_id、canteen_id、dish_id、rating(1-5分)、content、images、anonymous(是否匿名)、like_count、create_time
  • 回复表(reply):id、comment_id、user_id、content、reply_to_user_id、create_time
  • 点赞表(like_record):id、user_id、comment_id、create_time
  • 收藏表(favorite):id、user_id、dish_id、create_time
  • 通知表(notification):id、user_id、type、content、is_read、create_time
  • 管理员操作日志表(admin_log):id、admin_id、action、target_type、target_id、detail、create_time
  • 举报表(report):id、user_id、comment_id、reason、status、handle_result、create_time

尤其要注意的是餐厅表和菜品表里的冗余统计字段(avg_rating、rating_count、monthly_sales)。很多人第一反应是这些数据实时算不就行了?但实际查询会遇到性能瓶颈,用户看菜品列表时需要按评分排序,每次排序都去评价表里做聚合计算,数据量上来后会非常慢。折中的方案是:列表展示读冗余字段,评论变更时更新统计字段,单个菜品的详细评分分布再实时查。这就是典型的“用空间换时间”,也是工程里常用的手段。

3.2 主外键关系用什么方式处理

设计表关联时有两个派系:数据库层面加物理外键约束,或者只在应用层维护逻辑外键。在毕设阶段,我推荐逻辑外键为主,可以适当加物理外键

逻辑外键的意思是,comment表里有canteen_id和dish_id字段,但不做数据库级的FOREIGN KEY约束。优点很明显:方便做分布式改造的迁移、删除数据时更灵活、测试数据构造更简单。缺点是有可能产生孤儿数据,但如果应用层用事务控制好,问题不大。

这里还要强调一下删除策略。用户删除了一个评论,但其他用户可能已经点过赞或者管理员处理过举报,物理删除会导致一系列连锁问题。推荐的做法是加一个deleted字段做逻辑删除,查询时默认过滤掉已删除的数据,MyBatis-Plus的@TableLogic注解就能实现,自动帮你拼上where deleted = 0这个条件。

3.3 索引设计不能随便建

数据库表结构定了还不够,索引设计同样重要。评价表里查询频率最高的场景是“查看某个餐厅或某个菜品下的评价列表”,所以(canteen_id, create_time)和(dish_id, create_time)这两个联合索引必须建。点赞表要防重复插入,所以(user_id, comment_id)建立唯一索引。用户表登录时按username查询,该字段上也要加唯一索引。

这些你都应该能在答辩时说清楚,不要笼统说“建了索引”,要说出最左前缀原则覆盖索引这些概念。比如联合索引(canteen_id, create_time),它能同时支撑按canteen_id的等值查询和按canteen_id+create_time的范围排序,这就是索引设计中的“一箭双雕”。我见过太多人把每个字段都单独建索引,结果MySQL优化器反而不知道选哪个好,还白白占空间。

4. 核心功能模块的完整实现

4.1 用户认证模块:从JWT签发到接口放行

这个模块是所有功能的基础,实现逻辑值得拆开揉碎讲清楚。

用户输入账号密码提交到后端,流程是这样的:先调用userService根据username查用户,然后用BCryptPasswordEncoder的matches方法比对密码哈希值,比对通过后生成JWT,把用户id和角色塞进token的claims里。JWT生成后返回给前端,前端存到localStorage里,每次请求在Authorization头里带上。

后端这边要写一个OncePerRequestFilter,继承Spring的过滤器基类,在过滤逻辑里取请求头里的token并校验签名,解析出的用户信息放进ThreadLocal或SecurityContext里,这样后续的Controller和Service就能随时拿到当前登录用户是谁。在这套基础之上,还需要配置哪些接口是公开的,哪些必须登录,哪些只有管理员才能访问。

以食堂管理员身份为例,他想删除一条差评,请求到达Controller之前,JWT过滤器已经解析出他的角色是ROLE_CANTEEN_ADMIN,然后Spring Security的授权管理器会根据注解@PreAuthorize("hasRole('CANTEEN_ADMIN')")来决定放行还是返回403。把权限规则和业务代码解耦,这是工程化程度的一个体现。

注意:不要把JWT的secret明文写在代码里,应放到application.yml配置文件中,并用@ConfigurationProperties或@Value注入。更保险的做法是secret长度至少32字节,否则HS256算法的签名强度会打折扣。

4.2 评价提交与多条件组合打分

评价模块是业务核心,具体来说要处理这几个逻辑:

  • 用户提交评价时包含canteen_id、dish_id、rating、content、images等字段;
  • 后端先判断用户是否已经评价过同一菜品(30天内),防止刷屏;
  • 评分范围校验,rating必须为1到5的整数,content长度不能超过500字;
  • 高分非好评绑定问题,这里需要一个巧妙的设计:用户在打分之后,需要选择“推荐菜品”才能提交成功,这就保证了评价不只是评分,而是有具体内容的;
  • 保存评论后同步更新canteen表和dish表的rating_count和avg_rating字段;
  • 如果是匿名评价,返回数据时user_id显示为null,nickname显示为“匿名用户”。

其中同步更新冗余字段这一步千万不能漏,我见过很多项目评论发了但排名不更新,就是因为漏了这一步。

再讲一个容易被忽视的设计:评分与文本解耦。也就是说,评价表并不需要在主表上既存评分又存长文本。如果需要更复杂的评价维度,比如口味、价格、环境三个维度分开打分,可以在主表存总体评分,再加一张评价详情表存各子维度的分数。不过毕设阶段5分制整数评分已经够用了,追求复杂维度反而会让前端交互变重、数据质量变差。

4.3 图片上传:本地存储与动静分离

图片上传也是常见的功能点。毕设阶段我强烈建议用本地磁盘存储外加Nginx映射静态访问路径,先别碰云存储服务,省去各种配置成本。

具体做法是:在application.yml中配置一个upload.path,比如/data/canteen/images/,用户上传时通过MultipartFile的transferTo方法把文件写到该目录下,文件名用UUID重命名防止重复。然后定义一个WebMvcConfigurer把虚拟路径和磁盘路径做映射,这样图片URL就能像访问静态资源一样直接展示。

这里有几件重要的细节:

  • 上传前校验文件类型,不能只校验后缀名,还要校验文件的MIME类型,防止有人传个WebShell上去;
  • 限制单个文件大小,在SpringBoot的配置文件里设置spring.servlet.multipart.max-file-size: 5MBmax-request-size: 10MB
  • 图片压缩可以不做,但图片体积限制必须做,否则服务器磁盘容易被塞爆;
  • 删除评论时不能只删数据库记录,磁盘上的图片也要清理,否则积累一年就是几十GB垃圾。

4.4 个性化推荐:基于标签的简化协同过滤

如果你想在这个项目里做出亮点,强烈建议加一个**“猜你喜欢”**的推荐模块。别一听推荐就觉得要搞深度学习,光一个Spark或TensorFlow就够你喝一壶的,而且毕设的场景下数据量根本喂不饱模型。

实用做法是基于标签的推荐。菜品表加一个tags字段,存“麻辣”“清淡”“招牌”这类标签。用户每次评价菜品时,系统自动把他的偏好向量加上该菜品的标签权重。推荐时先找和当前用户偏好最相似的Top N用户群,再从这些用户高频正向评价的菜品中选当前用户没吃过的进行推荐。逻辑不算复杂,但能讲出基于物品的协同过滤思想,同时核心代码自己可控、答辩能讲清楚。

如果觉得这个复杂度还是高,可以退一步做“热门排行+好友动态”的简化版,通过Redis的ZSet数据结构维护点赞榜和评论活跃榜,数据更新和排名查询都非常高效。

4.5 通知系统:从主动查询到事件驱动

当有人回复你的评论,或者你关注的档口出了新品,系统需要给用户发通知。比较完善的实现有两个层次:

基础层次是查询时生成。用户拉取通知时,查回复表找到“目标评论id属于该用户”的回复数据,再加上菜品上新等信息动态组装。这种方式实现简单,数据永远是最新的,但每次拉取都要做几表关联。

进阶层次是事件驱动写入。用户A回复了用户B的评论,业务代码在事务里同时写一条notification记录,通知类型为REPLY,内容摘要为回复正文。用户拉取通知时直接查notification表,已读标记更新即可。这样拉取接口很简单,查询也快,而且天然支持后续扩展站内信、邮件提醒等场景。

我在你的需求里看到“校园美食互动评价系统”,互动才是精髓。通知模块不只是锦上添花,它是让用户感受到“被回应”的关键设计,强烈建议保留。

5. 项目启动与联调:从IDEA到前端页面

5.1 用IDEA创建和配置SpringBoot项目全流程

很多新手在刚开始时卡在项目创建这一步,这里把整个流程过一遍。

用IDEA最新版新建项目时选择Spring Initializr,在Spring Boot版本那里选2.7.x。如果你本地JDK是8或11,不要手贱去选3.x版本,因为3.x要求JDK 17起步,选错版本后面全是妖魔问题。这也是你在热搜词里看到“springboot版本太高”这种烦心事的原因,版本不匹配是很多新手第一道大坎。

依赖选择的时候,勾上Web、MySQL Driver、MyBatis-Plus Framework(如果你用的是个人版IDEA,可以用Maven方式引入依赖)、Lombok、Spring Security、Redis、Validation。注意MyBatis-Plus不在IDEA的初始依赖列表里,需要在pom.xml手动加坐标。

然后是配置文件。检查application.yml里的数据源和Redis连接、JWT密钥和过期时间、文件上传路径、MyBatis-Plus的日志打印和逻辑删除配置。以一个典型的本地配置为例:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/canteen_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 database: 0 servlet: multipart: max-file-size: 5MB max-request-size: 10MB mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 jwt: secret: your-32-character-secret-key-please-change expire: 604800

这里有个细节:map-underscore-to-camel-case字段映射必须开启,不然数据库的create_time映射不到Java实体类的createTime,接口查出来全是null,排查非常费时间。

5.2 前端联调时最容易翻车的几个点

前端联调是很多后端同学头疼的地方,这里分享几个典型的坑和解决思路。

首先是跨域问题。前端跑在8081端口,后端在8080端口,属于跨域请求。解决方法有两种:后端在配置类里实现WebMvcConfigurer的addCorsMappings方法配置允许跨域,或者前端通过Vite/Nginx的代理转发。我推荐前端配置代理,这样生产环境Nginx做反向代理时,前端请求地址不用改;后端同时也配好CORS,方便本地调试。两层都配上不会冲突。

其次是接口返回格式要统一。建议所有接口都返回一个统一的Result对象,格式为{code: 200, message: "success", data: {...}}。这样前端可以做统一的响应拦截,不用每个请求都单独判断成功失败。我见过接口有的返回对象、有的返回List、有的直接返回null,前端处理起来非常痛苦。

第三是日期格式问题。后端返回的LocalDateTime默认序列化格式是"2025-01-15T10:30:00",前端直接显示会很难看。解决方式是在application.yml里加配置:

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8

5.3 用Postman/Apifox做完整接口自测

接口写完不要直接丢给前端,自己先用Apifox或Postman完整跑一遍流程。近两年我更推荐Apifox,因为它内置了Mock数据和接口文档管理,一个平台搞定调试和协作。

自测流程要覆盖业务闭环:

  • 注册用户、登录拿token;
  • 用token创建一条餐厅评价(带图片上传);
  • 用另一用户账号对这条评价点赞;
  • 验证餐厅评分是否从无到有发生变化;
  • 管理员登录,对敏感评论做隐藏;
  • 再拉取评论列表,确认已经看不到被隐藏的评论。

这套流程走通后,大部分接口的问题都能暴露出来。实测下来最常触发Bug的是“评论后更新餐厅平均分”这步,很多人只更新了菜品表忘了餐厅表,或者事务没有生效导致分数更新了但评价记录没插入成功。建议update方法上加@Transactional注解,并在测试时故意制造一次插入失败,看看事务是否真的回滚。

6. 数据可视化与后台管理:别让PPT式图表糊弄事

6.1 餐厅评分趋势与热力图分析

毕设里数据可视化是非常出彩的一部分。热门关键词里出现了“基于springboot vue的前后端分离”,架子搭好之后,可视化就能直接体现数据的价值。

比较推荐做三个维度的可视化:

餐厅评分雷达图:对一个餐厅的评分做多维度拆分,比如口味、环境、服务、价格四个维度做成五维雷达图,用户能直观看出这家食堂的优势短板。

评分时间趋势折线图:按周或月聚合用户对特定餐厅的评分均值,看趋势变化。食堂管理方可以通过趋势图感知到“这道菜最近评分下滑”,及时调整菜品配方或更换档口。

热门菜品词云:清洗菜品评价文本,用HanLP或Jieba做分词,统计高频词和情感倾向词,生成词云图。比如“微辣”“入味”“太油”这些高频关键词,比单纯看分数更能反映真实口碑。

后端为可视化提供数据时,SQL聚合查询是基本功。以月度评分趋势为例,SQL大概长这样:

SELECT DATE_FORMAT(create_time, '%Y-%m') AS month, AVG(rating) AS avg_rating, COUNT(*) AS comment_count FROM comment WHERE canteen_id = #{canteenId} AND deleted = 0 GROUP BY DATE_FORMAT(create_time, '%Y-%m') ORDER BY month ASC;

类似这种SQL要能随口说出设计思路,MyBatis-Plus的QueryWrapper搞不定复杂聚合,在Mapper里写XML,简单清晰还能走索引。

6.2 管理员后台的权限边界设计

后台管理分三类角色,权限边界必须清晰:

  • 系统管理员:用户管理(封号、重置密码)、餐厅与菜品审核、评论内容审核与置顶、数据统计总览;
  • 食堂管理员:只能管理自己所在餐厅的菜品信息、查看本餐厅的评价、对恶意差评提起申诉(由系统管理员处理);
  • 普通学生用户:没有后台访问权限。

在Spring Security配置里,不同的URL前缀绑定不同的角色要求即可。比如/api/admin/**需要ROLE_ADMIN,/api/canteen/**需要ROLE_CANTEEN_ADMIN。尤其注意水平权限问题:食堂管理员A不能通过手动改URL里的餐厅ID去操作食堂B的数据。在service层做数据归属校验,查询时强制加上WHERE canteen_id = 当前管理员的餐厅ID,不能只依赖前端把餐厅ID传进来。

7. 性能优化与安全加固:进阶加分的实操项目

7.1 Redis缓存在评价系统中的落地用法

缓存的位置选得好,效果立竿见影:

热门餐厅排行榜:用Redis的ZSet,key为canteen:rank,member为餐厅ID,score为综合热度分(评价数+点赞数加权),每小时定时任务重算一次。榜单加载约消耗个位数毫秒,远比实时查数据库聚合快。

菜品详情缓存:菜品基础信息变化频率低、读取频率高,适合缓存。用Spring Cache的@Cacheable注解放在getDishDetail方法上,CacheManager配置为Redis,key为菜品的JSON序列化结果,TTL设为30分钟。

验证码存储:登录或注册时的图形/短信验证码存Redis,5分钟过期,天然带过期特性。

一个关键注意点是缓存穿透和缓存击穿。菜品的id是自增整数,恶意请求一个不存在的ID会每次穿透到数据库。解决方案是在接口层对请求参数做基础校验,查不到数据的缓存空值并设置较短TTL。此外,热点餐厅的缓存突然过期会导致一瞬间大量请求打到数据库,加入互斥锁或逻辑过期时间去保护。

7.2 接口安全:防刷、鉴权、参数校验三层防线

一个在线公开的系统最容易受到的是自动脚本攻击。三步防线必不可少:

第一层,接口限流。发评论或点赞接口加上简单限流,用Redis的incr命令实现计数器,一分钟内同一用户最多评论5次、点赞20次,超出返回“操作太频繁”。这种小成本设计能把大量恶意刷屏挡在业务逻辑之外。也可以用AOP自定义注解@RateLimiter,对整个Controller类一对一生效。

第二层,JWT鉴权与Token续期。JWT过期时间设置为7天是一次性的,用户7天后必须重新登录。为了让体验更顺滑,可以采用双Token方案:accessToken 30分钟过期,refreshToken 7天有效期,accessToken过期后用refreshToken去换新的。答辩时提到这个设计,面试官眼中你的工程经验值会直接拉满。

第三层,参数校验与XSS防护。Spring Validation框架的@NotBlank、@Size、@Min、@Max在Controller入参上做好校验,避免脏数据进入数据库。文本内容做HTML标签过滤,防止存储型XSS。简单做法是引入一个自定义的XssFilter,对请求体中的<script>等危险标签进行转义和清除。

7.3 日志记录与异常处理机制

日志这个环节被很多学生直接跳过,但它是线上排查问题的生命线。用@Slf4j在关键Service类打info和warn日志,内容包括请求用户ID、操作参数、耗时和异常栈。配合Spring Boot的全局异常处理器@RestControllerAdvice,按异常类型返回不同的错误信息格式:

  • 参数校验异常返回400级错误码和具体字段错误;
  • 业务异常返回自定义CodeMsg;
  • 未捕获异常统一返回500,并对日志做error级别记录,避免把异常堆栈直接抛给前端。

注意:日志里绝不能打印用户的明文密码、身份证号等敏感信息。真实开发中因为日志泄露密码的事故比想象中的多得多。

8. 常见问题与避坑指南

8.1 高频报错的排查路径

问题1:启动时报Failed to configure a DataSource原因多半是数据源没有配置或者连接失败。先检查application.yml里url、用户名、密码是否正确,再确认MySQL服务是否启动、数据库是否已创建。如果是连接成功、但找不到数据库,执行CREATE DATABASE canteen_db DEFAULT CHARACTER SET utf8mb4;

问题2:MyBatis-Plus分页不生效检查是否配置了分页插件。MyBatis-Plus新版需要手动添加MybatisPlusInterceptor,并把PaginationInnerInterceptor作为内置拦截器注册进去,否则Page参数会被当成普通参数处理,查询不报错但全表数据都返回了。

问题3:JWT过滤器对所有请求生效导致登录接口无法访问把登录注册接口的URL加入过滤器的白名单。在SecurityConfig的permitAll()里配好白名单,JWT过滤器也要有对应的路径断言。顺带提醒:白名单的路径匹配规则要和Controller里写的路径完全一致,别一个写/api/auth/login一个写/api/login,这种小坑能卡一整晚。

问题4:前端上传图片显示404优先确认Nginx或后端的虚拟路径映射是否指向了正确的磁盘目录,再查看文件是否真的被上传到目标位置。命令行里ls -al /data/canteen/images/检查一下文件是否存在、权限是否正常。真实开发很大比例是目录没有写权限导致的。

8.2 答辩时会被告知的几个加分细节

做毕设时系统能跑只是及格线,能讲清楚每个模块为什么这么做才是高分关键。这里列几个我指导论文时反复强调的点:

  • 数据库表设计里冗余统计字段的选择,比一张大宽表一次性算到底更有说服力;
  • 评价既要“数值量化”也要“文本洞察”,评分和NLP关键词提取结合,让数据真正有分析价值;
  • JWT无状态认证为什么适合前后端分离,对应会带来什么问题和补偿措施;
  • 自定义异常体系的设计,而不只是用try-catch出来一个假结果抛给前端;
  • 并发场景下的超卖问题,比如同一道菜同时被大量用户点赞、同一用户重复点赞,它们分别用的什么手段(唯一索引、Redis计数、事务隔离级别)来控制。

8.3 时间规划建议:八周开发节奏

最后给一个制订开发计划的时间参考,这个节奏我试过能顺利完成:

  • 第1周:跑通项目骨架,完成数据库建表,搞定登录注册和JWT认证;
  • 第2周:完成餐厅、菜品模块和用户中心(头像上传、资料编辑);
  • 第3-4周:评价模块完整闭环,包括多条件评分、图片上传、匿名、点赞、回复和通知;
  • 第5周:管理后台和可视化图表;
  • 第6周:Redis缓存、接口限流、安全加固(XSS、权限校验);
  • 第7周:联调、修复接口问题、整理数据库脚本和启动文档;
  • 第8周:压测、性能调优、准备答辩PPT和数据备份。

这个节奏不算紧,但也不宽裕,重点是把两三周的战略时间留给评价模块和可视化,这两块是答辩时最容易出彩的地方。别一上来就埋头写代码,先把建表SQL和接口文档定下来,否则后面改起来全是重复劳动。

这个项目做下来最大的感受是:SpringBoot只是一个载体,真正值钱的是你如何把业务需求转化为表结构、接口设计和技术方案的能力。校园餐厅评价系统虽然看起来不大,但用户端、商家端、管理端三类角色、评价闭环、通知互动、数据可视化、安全风控全都要覆盖,做完之后你对一个完整项目从0到1的理解会上一个台阶。如果时间允许,建议在系统里真实录入一个月的数据(哪怕自己写脚本模拟),有真实数据支撑的可视化和推荐模块,才是答辩时最有说服力的部分。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询