
做毕设辅导这些年SpringBoot的选题我接过太多说实话十个里面有八个是“XX管理系统”数据库一建、CRUD一写、页面套个模板完事。但这套“糖尿病人健康饮食计划平台”不一样它表面看也是管理平台核心技术栈同样是SpringBoot可真正值钱的地方在于它把营养学规则和工程代码揉在了一起——你要懂一点健康领域的知识才能把表结构和推荐逻辑设计得合理。这篇就用这个项目做完整拆解从需求分析到数据库设计从核心代码到远程部署上线一条线讲清楚。这个平台解决的实际问题很具体糖尿病患者最头疼的不是吃药打针而是“今天到底该吃什么”。医生说的“低GI、控热量、均衡营养”普通人很难换算成一日三餐。平台就是把食物库、营养数据、个人健康档案和饮食计划串联起来让患者能查、能算、能跟着计划吃。它适合三类人参考做Java毕设的学生源码论文都有落地场景、刚入门SpringBoot想做一个完整全栈项目的开发者、以及想做健康垂直领域MVP产品的产品经理。我下面所有内容都按可以直接复现的标准来写。1. 这个项目到底解决什么问题需求拆解与技术选型1.1 糖尿病饮食管理的真正痛点很多做系统的人上来就建表、写接口结果做出来的东西没人用。原因很简单——没弄明白业务场景的真实约束。糖尿病饮食管理有三个绕不开的痛点第一营养计算门槛高。一个患者每天应该摄入多少千卡热量取决于他的性别、年龄、身高、体重、活动强度甚至糖尿病分型。这些参数组合起来普通人是算不明白的。平台要做的第一件事就是把这个计算过程封装成自动逻辑用户填几个基础指标系统直接给出每天的热量总预算。第二低GI血糖生成指数食物选择困难。GI值低于55属于低GI食物适合糖尿病患者但市面上常见食物的GI值普通人根本记不住。平台需要一个结构化的食物库把每样东西的热量、GI、蛋白质、脂肪、碳水都存进去按条件筛选。第三饮食计划难以坚持。光告诉用户“你要控制饮食”没用得直接给出“早餐吃什么、午餐吃什么、晚餐吃什么”的可执行方案而且最好是能根据用户在平台上的健康档案自动生成的。如果你把AI说得太玄毕设阶段反而不实际完全可以先用规则引擎实现一套确定性的推荐逻辑效果也不差。1.2 为什么选SpringBoot而不是SSH或微服务这个项目的技术选型我建议就是SpringBoot MyBatis-Plus MySQL前端用Vue或者Thymeleaf都可以。很多人会问现在都在说微服务、分布式毕设要不要上Spring Cloud Alibaba、Nacos那一套我的意见很直接不要。这个项目的数据量级和业务复杂度单体架构完全扛得住微服务只会把问题复杂化。SpringBoot的核心价值是“约定大于配置”内嵌Tomcat一个jar包就能跑这正好符合课程设计/毕设场景里“快速开发、清晰交付、方便部署”的诉求。版本选择上要特别注意这也是搜“springboot版本太高”的原因。SpringBoot 2.7.x配JDK 8或11是当前最稳的组合。别一上来就SpringBoot 3.x——它能跑但很多老牌的依赖比如一些MyBatis的早期整合包、旧版JWT库在Jakarta命名空间迁移后会报ClassNotFoundException排查起来极其痛苦。如果一个项目的目标是稳定出成果就用成熟的版本组合。1.3 整体架构清晰三层别玩花活这个项目的架构我建议就是标准的三层架构加一个DTO/VO转换层Controller层接收请求、参数校验、返回统一结果结构Service层业务逻辑热量计算、计划推荐、统计都在这里Mapper层MyBatis-Plus的BaseMapper单表CRUD基本不用写SQL另外加一个包叫common放统一返回体Result、全局异常处理器、JWT工具类、跨域配置。这样分层的好处是论文好写、答辩好讲、代码好改。真不用设计什么“领域驱动设计”那套那种复杂度对于这类系统是过度的。2. 数据库设计这套系统的地基2.1 三类用户角色与权限模型数据库设计是整个项目里最见功底的部分。先把用户模型定下来患者普通用户、营养师/医生管理员、平台管理员。三张表的做法是一种方案但更简洁的做法是放在一张user表里用role字段区分CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 登录名, password varchar(100) NOT NULL COMMENT 加密后密码, nickname varchar(50) DEFAULT NULL, role tinyint(4) NOT NULL DEFAULT 1 COMMENT 1患者 2营养师 3管理员, gender tinyint(4) DEFAULT NULL COMMENT 0女 1男, age int(11) DEFAULT NULL, height decimal(5,2) DEFAULT NULL COMMENT cm, weight decimal(5,2) DEFAULT NULL COMMENT kg, diabetes_type tinyint(4) DEFAULT NULL COMMENT 1型/2型, activity_level tinyint(4) DEFAULT NULL COMMENT 1少动 2轻度 3中度 4重度, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;为什么把患者的基础健康指标直接放在user表而不是单独建一张detail表因为这个项目里没有“用户信息变更历史”这类复杂需求患者档案信息就是最新的那一份一行放得下就不拆表。保持合理冗余减少联表查询毕设阶段这是更好的设计策略。权限控制用SpringBoot拦截器做就够了不需要引入Spring Security如果你想加分引入也完全可以但不引入节省的时间能让你把前后端联调做扎实。拦截器里判断请求头里token解析出的role和当前访问路径做匹配不匹配就返回403。2.2 食物库与营养成分表这是整个平台的数据底座没有食物数据的饮食推荐就是空中楼阁。食物表的设计一定要把营养学里最常用的几个指标放全CREATE TABLE food ( id bigint(20) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL COMMENT 食物名, category varchar(50) DEFAULT NULL COMMENT 分类主食/肉类/蔬菜/水果/乳制品, calories decimal(7,2) DEFAULT NULL COMMENT 每100g热量(kcal), protein decimal(7,2) DEFAULT NULL COMMENT 蛋白质(g/100g), fat decimal(7,2) DEFAULT NULL COMMENT 脂肪(g/100g), carb decimal(7,2) DEFAULT NULL COMMENT 碳水(g/100g), gi_value int(11) DEFAULT NULL COMMENT GI值 0-100, unit varchar(20) DEFAULT NULL COMMENT 常见计量份量如1碗/1个/100g, is_common tinyint(4) DEFAULT 1 COMMENT 是否常用食物, status tinyint(4) DEFAULT 1 COMMENT 0下架 1上架, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT食物表;字段设计有三个细节要注意。一是单位的问题营养表里的热量和营养素通常按每100克算但用户在选“一个苹果”的时候不会想它是多少克所以还需要一个“常见份量”字段比如一个中等苹果约200克、一碗米饭约150克推荐时换算才准确。二是GI值只存整数就行专业食物GI表本身也精确到整数。三是预留status字段做上下架营养师可以维护食物库这个功能在论文里能作为一个管理模块亮点。提前准备食物数据时重点整理常见食物就够了二三十种就能让推荐逻辑跑起来不必追求数据量。查数据用《中国食物成分表》或者公开的低GI食物表换算要自己算清楚。2.3 饮食计划与计划明细一主多从的表结构饮食计划不是一张表能搞定的。一个用户一天有三餐或加餐每一餐里又包含多种食物这是典型的一对多关系。设计成主表和明细表维度清晰、扩展方便CREATE TABLE diet_plan ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, plan_date date NOT NULL COMMENT 计划对应日期, meal_type tinyint(4) NOT NULL COMMENT 1早餐 2午餐 3晚餐 4加餐, total_calories decimal(7,2) DEFAULT NULL COMMENT 本餐总热量, total_gi decimal(7,2) DEFAULT NULL COMMENT 本餐加权GI, status tinyint(4) DEFAULT 1, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_date (user_id,plan_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT饮食计划主表; CREATE TABLE diet_plan_detail ( id bigint(20) NOT NULL AUTO_INCREMENT, plan_id bigint(20) NOT NULL COMMENT 关联主表, food_id bigint(20) DEFAULT NULL, food_name varchar(100) NOT NULL COMMENT 冗余食物名, servings decimal(5,2) DEFAULT NULL COMMENT 份数, grams decimal(7,2) DEFAULT NULL COMMENT 实际克数, calories decimal(7,2) DEFAULT NULL COMMENT 本条目热量, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT饮食计划明细表;主表记录“哪一天哪一餐的总量”明细表记录“这一餐具体包含哪些食物、各多少克”。food_name冗余存储是故意为之因为食物表数据可能被营养师修改比如修正热量而历史计划应该保留当时的快照信息这种适度冗余在业务上是合理的。用user_id和plan_date建联合索引是因为最频繁的查询就是“查某用户某一天的全部计划”有索引能保证这个查询走索引。这个细节可以在数据库设计说明里写出来是论文的好素材。2.4 血糖记录与健康档案血糖记录表是这个平台里另一个核心业务数据结构相对简单但要注意测量时机的区分CREATE TABLE blood_sugar ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, measure_time datetime NOT NULL COMMENT 测量时间, measure_type tinyint(4) NOT NULL COMMENT 1空腹 2餐后2小时 3随机, value decimal(5,2) NOT NULL COMMENT 血糖值mmol/L, remark varchar(200) DEFAULT NULL, PRIMARY KEY (id), KEY idx_user_time (user_id,measure_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT血糖记录表;注意空腹和餐后2小时的正常范围完全不一样如果不区分type就存一起后续做趋势分析时数据就乱了。查询的时候拿用户最近7次空腹血糖或者最近7天的记录可以做折线图展示也能计算平均血糖。这个模块虽然简单但它是“健康平台”属性的直接体现答辩时能讲清楚“这个数据怎么指导饮食调整”整体项目的高度就不一样了。3. 核心功能实现认证、推荐算法、统计报表3.1 登录与JWT认证代码不多坑不少任何一个系统都逃不掉认证这关。这个项目用JWT做无状态认证SpringBoot里实现起来很轻。JWT的实现逻辑是用户登录成功后端根据用户名和角色生成一个token过期时间通常设24小时返回给前端前端每次请求在header里带Authorization: Bearer 后端拦截器校验token的合法性解析出用户和角色放行或拦截。核心代码分三块。第一块是JWT工具类负责生成和解析tokenComponent public class JwtUtil { // HS256的密钥长度必须大于等于32字节否则运行报错 private static final String SECRET DiabetesPlatformSecretKey_2024_YourName; private static final long EXPIRE 24 * 60 * 60 * 1000L; public String generateToken(Long userId, String username, Integer role) { return Jwts.builder() .setSubject(username) .claim(userId, userId) .claim(role, role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() EXPIRE)) .signWith(SignatureAlgorithm.HS256, SECRET.getBytes(StandardCharsets.UTF_8)) .compact(); } public Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET.getBytes(StandardCharsets.UTF_8)) .parseClaimsJws(token) .getBody(); } }这里有个新手的重灾区HS256签名时密钥字节数必须不少于256位32字节。如果你写一个很短的SECRET程序启动登录一次就抛WeakKeyException折腾一下午。用jjwt 0.9.1这个版本的话默认是HS256创建JwtBuilder时不需要指定签名算法也行。然后是拦截器Component public class AuthInterceptor implements HandlerInterceptor { Autowired private JwtUtil jwtUtil; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (OPTIONS.equals(request.getMethod())) { return true; // 放行跨域预检请求 } String auth request.getHeader(Authorization); if (auth null || !auth.startsWith(Bearer )) { response.setStatus(401); return false; } try { Claims claims jwtUtil.parseToken(auth.substring(7)); request.setAttribute(userId, claims.get(userId)); request.setAttribute(role, claims.get(role)); return true; } catch (Exception e) { response.setStatus(401); return false; } } }注意这里对OPTIONS请求放行。前后端分离开发时浏览器跨域会先发一个OPTIONS预检请求这个请求不带Authorization头如果拦截器直接拦截前端所有接口调用都会报401这种坑属于“看起来是前端问题其实是后端拦截器忘了放行”的典型情况。跨域配置用WebMvcConfigurer实现CorsRegistry把allowedOriginPatterns设为*allowedMethods设为GET/POST/PUT/DELETE/OPTIONS开发阶段足够。3.2 饮食推荐的核心算法从热量需求到三餐计划这就是这个项目和普通管理系统拉开差距的地方。推荐算法不需要机器学习但要把营养学规则工程化。算法分三步。第一步基于Harris-Benedict公式计算每日基础代谢率BMRpublic double calcBmr(User user) { double bmr; if (user.getGender() 1) { // 男 bmr 88.362 (13.397 * user.getWeight()) (4.799 * user.getHeight()) - (5.677 * user.getAge()); } else { // 女 bmr 447.593 (9.247 * user.getWeight()) (3.098 * user.getHeight()) - (4.330 * user.getAge()); } return bmr; }第二步乘以活动系数得到每日总消耗TDEE再根据糖尿病控制目标决定热量缺口。活动系数分四档久坐1.2、轻度活动1.375、中度活动1.55、重度活动1.725。对于需要控制体重的2型糖尿病患者建议摄入量在TDEE基础上减10%~20%但不低于BMR这一点在代码里要有判断逻辑。第三步按热量比例拆到三餐再从食物库里筛选食物组成计划。常规分配是早餐30%、午餐40%、晚餐30%如果有加餐可以从晚餐里分出来10%。比如某用户TDEE是2000千卡控糖减脂期打8折每日摄入目标1600千卡那么早餐目标480千卡、午餐640千卡、晚餐480千卡。接下来是食物选择。优先从低GIGI≤55食物里选兼顾三大营养素比例碳水50%~60%、蛋白质15%~20%、脂肪20%~30%。简单的实现是根据目标热量和食物类别主食类提供一半热量剩下的由肉蛋奶和蔬菜瓜果分摊。每选定一个食物按比例计算克数注意每个食物的“常见份量”字段换算成份数写进计划明细。这套逻辑够实用代码写起来也不复杂核心就是一个PlanGenerator类输入User对象输出当天三餐的DietPlan列表。推荐结果不追求“最优解”而追求“合理且能解释”因为答辩时老师一定会问“你的推荐依据是什么”你只要能把公式和规则讲清楚这个项目的技术深度就立住了。3.3 营养计算与低GI筛选逻辑热量和GI的计算要分层不能全部堆在Service里变成一个长方法。我建议做一个NutritionCalculator类来封装Component public class NutritionCalculator { // 根据食物每100g的营养数据与实际克数算出实际摄入 public NutritionValue calcActual(Food food, double grams) { NutritionValue v new NutritionValue(); v.setCalories(food.getCalories() * grams / 100.0); v.setProtein(food.getProtein() * grams / 100.0); v.setFat(food.getFat() * grams / 100.0); v.setCarb(food.getCarb() * grams / 100.0); // GI值不做线性换算取食物的原始GI但整餐加权GI要另算 v.setGi(food.getGiValue()); return v; } // 一餐的加权GI Σ(单个食物GI × 该食物碳水克数) / Σ碳水克数 public double calcMealGi(ListDietPlanDetail details) { double totalCarb 0, weightedGi 0; for (DietPlanDetail d : details) { totalCarb d.getGrams() * ?; // 需要查食物表获取每100g碳水 weightedGi d.getGi() * carbOfThisFood; } return totalCarb 0 ? 0 : weightedGi / totalCarb; } }加权GI这个细节很多人会写错。整餐的GI不是各个食物GI的算术平均而是以碳水化合物含量为权重求加权平均。因为一个菜的GI高但它碳水少对餐后血糖的真实影响未必大用一个数字直观展示给患者看比罗列一堆食物GI值有用得多。3.4 血糖趋势分析一周数据可视化怎么做血糖模块前半段是数据录入后半段是趋势展示。后端接口需要返回两类数据一是最近7次测量的原始记录列表表格展示二是按日期聚合的平均血糖前端画折线图。SQL层面用MyBatis-Plus也可以写但更清晰的是一条自定义SQLSELECT DATE_FORMAT(measure_time, %Y-%m-%d) as day, ROUND(AVG(value), 2) as avgValue, MAX(value) as maxValue, MIN(value) as minValue FROM blood_sugar WHERE user_id #{userId} AND measure_time DATE_SUB(CURDATE(), INTERVAL 7 DAY) GROUP BY DATE_FORMAT(measure_time, %Y-%m-%d) ORDER BY day;这个接口返回的数据前端直接塞进ECharts的line图就完事。要注意时间字段的时区问题后面部署章节会重点说。4. 远程部署全程实录从本地到公网可访问4.1 云服务器选型与环境初始化项目的交付说明里写了“远程部署”这块必须讲透。买一台最便宜的云服务器2核4G、带宽3Mbps起步就够了学生机一年也就百来块钱。操作系统选CentOS 7.9或者Ubuntu 20.04都行我习惯用Ubuntu软件源更新方便。环境安装按顺序来# 1. 更新系统包 sudo apt update sudo apt upgrade -y # 2. 安装JDK 11 sudo apt install openjdk-11-jdk -y java -version # 3. 安装MySQL 8.0 sudo apt install mysql-server -y sudo systemctl status mysql # 4. 安装Nginx前端部署用 sudo apt install nginx -y装MySQL之后记得执行安全初始化脚本sudo mysql_secure_installation然后创建一个业务库和专用的应用账号不要用root直接连应用CREATE DATABASE diabetes_platform DEFAULT CHARACTER SET utf8mb4; CREATE USER app_userlocalhost IDENTIFIED BY YourStrongPass123; GRANT ALL PRIVILEGES ON diabetes_platform.* TO app_userlocalhost; FLUSH PRIVILEGES;如果你用的是云数据库那就省略本地安装这一步直接用云厂商给的连接串。但要注意学生项目完全可以自己装MySQL不额外花钱还能体会完整的运维流程。4.2 后端打包、配置与systemd托管本地代码通过Git推送到服务器或者直接用scp把项目源码/压缩包传上去。推荐在本地执行Maven打包把产物jar传上去服务器上不需要装Maven省时间# 本地执行 mvn clean package -DskipTests # 构建产物在 target/ 目录下然后写生产环境的配置文件。杀掉application.yml里的本地数据源新建一个application-prod.ymlserver: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/diabetes_platform?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: app_user password: YourStrongPass123 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 # MyBatis-Plus配置 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl启动方式有两种。简单的方式是直接nohup java -jar diabetes-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod app.log 21 但这种直接进程方式不考虑开机自启和崩溃重启。稍微规范一点写一个systemd服务[Unit] DescriptionDiabetes Platform Afternetwork.target [Service] Userroot WorkingDirectory/opt/diabetes ExecStart/usr/bin/java -jar /opt/diabetes/diabetes.jar --spring.profiles.activeprod Restarton-failure RestartSec10 [Install] WantedBymulti-user.target把配置文件放到/etc/systemd/system/diabetes.service然后sudo systemctl daemon-reload sudo systemctl enable diabetes sudo systemctl start diabetes sudo systemctl status diabetes这样用journalctl -u diabetes可以实时看日志出错排查方便比nohup那套体验好太多。远程部署这件事能做到“服务崩溃自动拉起、开机自启、日志可查”交付质量就完全不一样了。4.3 前端打包与Nginx反向代理如果你的前端是Vue项目打包之前要改一下接口地址。在.env.production里配接口基础路径VUE_APP_BASE_API http://你的服务器IP:8080/api然后构建npm run build # 产物在 dist/ 目录把dist目录里的静态文件上传到服务器的/var/www/diabetes/然后配置Nginx站点server { listen 80; server_name 你的域名或IP; root /var/www/diabetes; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }try_files那一行是为了解决Vue路由history模式下刷新404的问题这个坑几乎人人都会踩。配置完执行nginx -t检查语法然后systemctl reload nginx。如果你想省事也可以不做前后端分离前端用Thymeleaf模板放在SpringBoot的resources/templates下打包时一起打进jar那就不用Nginx了直接访问IP:8080就行。但考虑到市面上多数毕设用的是VueSpringBoot前后端分离我还是把Nginx的配置给全。4.4 数据库初始化与数据脚本迁移本地开发完的数据库要整体搬到服务器。最省事的是用mysqldump导出# 本地导出 mysqldump -u root -p diabetes_platform diabetes.sql # 传到服务器后导入 mysql -u app_user -p diabetes_platform diabetes.sql注意导出和导入的字符集要一致尽量在命令里加--default-character-setutf8mb4否则Windows本地导出的UTF-8内容到Linux可能中文乱码。这个乱码问题是部署阶段出现频率最高的我见得太多了。导入之后一定要把食物表、用户表的数据清点一遍生产环境初始数据里不要有测试垃圾数据。如果管理员账号密码是明文存进去的记得使用BCrypt重新加密后再替换。5. 常见问题与避坑指南5.1 一张表说清高频报错这一节是我这几年帮人看项目、做远程部署时遇到的高频问题直接整理成速查表现象根本原因解决办法本地启动正常部署服务器连不上数据库MySQL只监听了127.0.0.1修改/etc/mysql/mysql.conf.d/mysqld.cnfbind-address改为0.0.0.0但应用和数据库同机则不必改接口返回时间比北京时间早8小时数据库连接串没指定serverTimezone在JDBC URL加serverTimezoneAsia/ShanghaiJackson配置time-zoneGMT8访问接口报401前端却明明带了token拦截器拦截了OPTIONS预检请求在拦截器的preHandle里对OPTIONS请求直接放行JWT启动报WeakKeyExceptionHS256密钥太短密钥至少32字节以上MySQL中文乱码显示问号数据库字符集不是utf8mb4建库语句指定DEFAULT CHARACTER SET utf8mb4导入时加--default-character-setutf8mb4Vue前端刷新页面404没有history模式兜底Nginx配置try_files $uri $uri/ /index.htmlMaven打包下载依赖失败中央仓库网络差在settings.xml配置阿里云镜像项目用SpringBoot 3.x启动报NoClassDefFoundError老依赖没适配Jakarta命名空间换回SpringBoot 2.7.x最稳妥每条都是我实测过的照着做基本能消灭80%的部署问题。5.2 部署与联调中的实战经验再说几个不太容易查到但很实用的经验。第一个是服务器防火墙和安全组。云服务商的安全组默认只开22端口你要去控制台把8080和80端口放行否则程序起了、Nginx也配置了外部就是访问不通。我见过好几个同学在服务器上折腾了两三个小时最后发现是安全组没放行端口。第二个是日志的用法。用systemd托管服务后java进程的日志默认进journald用journalctl -u diabetes -f实时跟踪很舒服。但如果你的服务是用nohup方式启动的日志写到nohup.out文件里排查问题就靠tail -f nohup.out。养成看日志的习惯遇到错误先看最后20行比乱猜管用得多。第三个是数据库备份。虽然毕设项目数据量不大但养成备份习惯没坏处。写个简单cron任务每天凌晨3点备份一次数据库0 3 * * * mysqldump -u app_user -pYourStrongPass123 diabetes_platform /backup/diabetes_$(date \%Y\%m\%d).sql 21留到论文的“系统维护”章节里也是加分项。第四个是关于前后端联调。开发阶段你很可能遇到CORS跨域问题后端记得在配置类里加CorsRegistry映射允许前端开发服务器比如localhost:8081调用。但部署到生产环境后走Nginx同域反代就不存在跨域问题了所以上线后可以把CORS限制收窄这是安全意识的体现。6. 写在最后的一点体会做这个项目的过程中我觉得最有价值的不是CRUD代码本身而是把“营养学规则”翻译成“程序逻辑”的那个过程。很多人做管理系统做到最后代码写了一堆但问起来“这个系统到底帮用户做了什么实质性的决策支持”答不上来。而这个糖尿病饮食平台你是真的能用BMR公式、GI加权、三餐热量配比这些具体的、可解释的规则让用户得到一个“今天按这个吃就行”的确定性结果——这就是系统存在的意义。如果后续有条件这个项目也留了很好的扩展口子把规则推荐升级成基于用户血糖反馈的个性化推荐、加入食物图片识别、做移动端适配都是在现有表结构和架构上能顺势延伸的方向。但现阶段把SpringBoot这套工程骨架、数据设计和部署链路吃透已经足够支撑一门毕设或者一次完整的全栈实战了。