尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot+Vue健康减肥系统毕设全攻略:从源码到答辩

SpringBoot+Vue健康减肥系统毕设全攻略:从源码到答辩 又到毕业设计和课程设计扎堆的时候了。今年好几个学弟学妹来问我同一个问题“想做一个健康减肥系统的毕设用springbootvue能不能带源码带数据库带论文”说实话这类题目在计算机专业里非常常见但很多同学拿到源码后第一步就卡在“跑不起来”更别说讲清楚原理、应对答辩了。这篇文章我就把自己实际调试这个项目的过程、踩过的坑、核心模块的实现思路以及毕业论文怎么搭、答辩怎么答一次性说清楚。先说这个项目能做什么一套完整的健康减肥系统平台前端是Vue后端是SpringBoot数据库用MySQL登录用JWT做权限控制。用户可以在线注册、记录每日饮食、录入体重、查看BMI指数和热量报表管理员可以维护食物库和运动项目、管理用户账号、查看系统统计数据。源码、数据库脚本、毕业论文模板都齐全适合做毕业设计也可以压缩一下当作JavaWeb课程设计交差。文章后面我会从系统设计、核心代码、环境搭建、常见报错排查、论文与答辩五个部分展开全程按我实际操作的顺序来讲。内容偏“保姆级”就算你只有Java基础、Vue没怎么写过只要照着做也能把项目完整跑起来。1. 项目全貌与核心设计思路1.1 这个系统解决了什么问题健康减肥系统本质上是一个“减肥数据管理平台”。减肥这件事说起来就是“管住嘴、迈开腿”但落到软件上就需要一个能记录、能统计、能反馈的工具。用户的痛点很明确不知道自己每天吃了多少热量不知道自己的体重变化趋势更不知道该怎么设定一个合理的减脂目标。系统把这些问题拆成几个模块来解决用户注册登录后先维护一份个人身体档案包括身高、体重、年龄、性别。系统根据这些数据自动计算BMI和基础代谢率BMR并给出一个每日建议摄入热量。用户每天记录饮食从食物库中挑选食物并填写克数后端自动计算本次摄入热量。用户每次运动后记录运动项目和时长系统计算大约消耗了多少热量。体重记录以折线图方式可视化用户能直观看到自己的变化趋势。管理员在后台维护食物热量表、运动项目表审核用户信息查看平台整体统计数据。作为毕设项目它的功能量适中既不是只有一个CRUD的空壳也不会复杂到一个人做不完。这也是我推荐这类题目的原因。1.2 前后端分别拆了哪些功能我用表格把这套系统的主要功能列一下后面所有代码和模块讲解都围绕这张表展开。角色功能模块具体说明普通用户注册登录用户名密码注册密码加密存储登录返回JWT令牌普通用户个人档案身高、体重、年龄、性别维护普通用户健康指标BMI计算、BMR计算、每日推荐摄入热量普通用户饮食打卡选择食物、填写克数、自动计算热量按日查看记录普通用户运动打卡选择运动项目、填写时长、估算消耗热量普通用户体重趋势记录每日体重ECharts折线图展示普通用户减肥计划设置目标体重和计划周期系统给出进度管理员用户管理用户列表、禁用/启用账号管理员食物管理食物库增删改查维护每100克热量管理员运动管理运动项目增删改查维护每小时消耗热量管理员数据统计注册用户趋势、打卡热度、热量统计图表这样的功能设计既能体现“健康减肥”的业务闭环又没绕开常规的后台管理系统必备的增删改查符合高校对毕业设计“有业务场景、有技术含量、功能完整”的要求。1.3 为什么选SpringBootVue这套组合这个话题我回答过无数次。很多同学纠结到底用SSMJSP还是SpringBootVue我的结论很直接如果你的目标是顺利毕业、答辩不被问垮、顺便还能在简历上写一笔那SpringBootVue是当前最合适的选择。SpringBoot的好处是“省心”。它把Spring家族的繁琐配置大量简化了你不需要手动写一堆XML配置文件一个带内嵌Tomcat的jar包就能把项目跑起来。对于学生来说这意味着一套代码可以在本机IDEA里直接运行不需要额外部署Tomcat演示的时候省去大量环境问题。Vue的好处是“组件化”。前端页面拆成一个个组件登录页、注册页、首页、个人中心、管理后台分得清清楚楚改起来不牵连。而且Vue的生态足够成熟配合Element UI组件库一天时间就能把管理后台的界面搭出来。再往后说这套技术栈和你以后找工作用的东西基本一致。现在Java后端岗位的日常开发很大概率就是SpringBootRedisMySQL前端偶尔还要会Vue用这套组合做毕设相当于是提前做了一次岗前训练。1.4 后端目录结构与前端目录结构我习惯先把工程结构说清楚不然代码发给别人对方打开一看几十个文件根本不知道从哪里开始看。后端典型结构health-beauty-system ├── src/main/java/com/example/health │ ├── config # 配置类跨域、JWT拦截器 │ ├── controller # 接口层 │ ├── service # 业务逻辑层 │ │ └── impl # 业务实现 │ ├── mapper # MyBatis-Plus的Mapper接口 │ ├── entity # 数据库实体 │ ├── dto # 前端传参对象 │ ├── vo # 返回给前端的视图对象 │ ├── utils # 工具类JWT、日期 │ ├── common # 统一返回结果、异常处理 │ └── HealthApplication.java # 启动类 ├── src/main/resources │ ├── application.yml │ └── mapper # MyBatis的XML文件前端典型结构health-web ├── public ├── src │ ├── api # 所有请求接口封装 │ ├── router # 路由配置 │ ├── store # Pinia/Vuex状态管理 │ ├── views # 页面组件 │ │ ├── user # 用户端页面 │ │ ├── admin # 管理端页面 │ │ └── login.vue │ ├── components # 公共组件 │ └── utils # axios封装、工具函数 ├── package.json └── vue.config.js前后端分离项目的关键点就在这里后端只负责提供JSON格式的接口数据前端只负责页面渲染和请求调用两者通过HTTP协议通信。理解了这一点后面所有联调问题都能找到排查方向。2. 系统核心功能模块与关键代码拆解这部分是整篇文章的干货中心。我不贴完整的几千行源码因为那没有意义而是把每个核心模块的思路和关键代码抽出来你拿着这套逻辑去看项目里的源码会轻松很多。2.1 JWT登录认证与权限控制登录认证是几乎所有Web系统都要面对的问题。很多学生项目用Session拦截器也能实现登录但放在现在的前后端分离架构下Session跨域处理起来特别麻烦所以我直接用JWT。JWT的本质就是用户登录成功后后端生成一个包含用户信息的加密字符串前端把它存起来以后每次请求都带上这个字符串后端解析它就知道当前是谁在调用接口。核心逻辑分三步。第一步登录接口校验用户名密码PostMapping(/login) public Result login(RequestBody LoginDTO loginDTO) { User user userService.findByUsername(loginDTO.getUsername()); if (user null || !passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) { return Result.error(用户名或密码错误); } if (1.equals(user.getStatus())) { return Result.error(账号已被禁用请联系管理员); } // 密码正确生成token有效期2小时 String token JwtUtil.createToken(user.getId(), user.getUsername(), user.getRole()); return Result.ok(token); }第二步JwtUtil工具类生成和解析Tokenpublic class JwtUtil { private static final String SECRET your-secret-key-change-me; private static final long EXPIRE_TIME 2 * 60 * 60 * 1000; public static String createToken(Long userId, String username, String role) { return Jwts.builder() .claim(userId, userId) .claim(username, username) .claim(role, role) .setExpiration(new Date(System.currentTimeMillis() EXPIRE_TIME)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody(); } }第三步写一个拦截器在请求进入Controller之前校验Tokenpublic class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token null || !token.startsWith(Bearer )) { response.setStatus(401); return false; } try { Claims claims JwtUtil.parseToken(token.replace(Bearer , )); request.setAttribute(userId, claims.get(userId)); return true; } catch (Exception e) { response.setStatus(401); return false; } } }这里有几个踩坑点要提醒你密码一定不要用明文存数据库用BCryptPasswordEncoder加密这也是Spring Security里推荐的做法。网上很多项目直接用MD5答辩时容易被评委老师追问所以尽量用BCrypt。Token过期时间不要设置太长2小时比较合理。设置成7天虽然自己测试方便但答辩时老师问到“安全性怎么考虑”会有点尴尬。前端请求头携带Token时统一叫Authorization值写Bearer加空格加token这是业界习惯。2.2 饮食打卡与热量换算业务逻辑饮食打卡是健康减肥系统的核心业务。用户记录一顿饭吃了什么、吃了多少克系统告诉他这顿饭摄入多少热量。热量计算本身不复杂就是一个按比例换算的过程Override public DietRecordVO addDietRecord(DietRecordDTO dto) { Food food foodMapper.selectById(dto.getFoodId()); if (food null) { throw new ServiceException(所选择的食物不存在); } // 食物表中存储的是每100克的热量值这里按实际克数换算 double calories food.getCalories() * (dto.getWeight() / 100.0); DietRecord record new DietRecord(); record.setUserId(dto.getUserId()); record.setFoodId(food.getId()); record.setFoodName(food.getName()); record.setWeight(dto.getWeight()); record.setCalories(calories); record.setRecordDate(dto.getRecordDate()); record.setCreateTime(LocalDateTime.now()); dietRecordMapper.insert(record); // 返回当日累计摄入前端可以实时展示 Double totalCalories dietRecordMapper.sumCaloriesByUserIdAndDate( dto.getUserId(), dto.getRecordDate()); DietRecordVO vo new DietRecordVO(); vo.setRecord(record); vo.setTodayTotalCalories(totalCalories); return vo; }这个模块在数据库层面只需要一张饮食记录表字段包括id、user_id、food_id、food_name、weight、calories、record_date、create_time。很多同学会问为什么不在记录表里直接冗余一个calories字段我的回答是冗余热量字段是合理的因为用户可能在记录之后管理员修改了食物库的热量数据。这时如果每次查询都去现算一来麻烦二来历史记录也会跟着变。把当时的计算结果存下来才能保证用户历史记录的准确性。这里还有一个业务细节建议在计划里加上“每日摄入上限”提醒功能。也就是用户当天的累计摄入已经超过系统推荐的摄入热量时前端弹出一条提示后端也可以返回一个警告字段。代码实现并不难就是在service里多一次判断和返回但加上之后整个系统的业务完整度会瞬间提升不少。2.3 体重记录与BMI可视化体重记录模块的前端展示用ECharts画折线图这也是很多毕设项目喜欢展示的部分。直观、好看、能说明问题。后端逻辑比较简单用户新增一条体重记录PostMapping(/weight) public Result addWeightRecord(RequestBody WeightRecordDTO dto) { Long userId (Long) request.getAttribute(userId); WeightRecord record new WeightRecord(); record.setUserId(userId); record.setWeight(dto.getWeight()); record.setRecordDate(dto.getRecordDate()); weightRecordMapper.insert(record); // 计算并返回最新BMI指数方便前端页面直接刷新 UserInfo userInfo userInfoMapper.selectByUserId(userId); Double heightM userInfo.getHeight() / 100.0; double bmi dto.getWeight() / (heightM * heightM); return Result.ok(bmi); }BMI的计算公式是体重除以身高的平方需要注意的是身高单位是米。很多同学第一次写容易把厘米直接放进去算出来的BMI大得离谱这就是单位没换算。前端折线图的关键代码const chart echarts.init(document.getElementById(weightChart)) chart.setOption({ title: { text: 体重变化趋势 }, tooltip: { trigger: axis }, xAxis: { type: category, data: dates }, yAxis: { type: value, name: 体重(kg) }, series: [ { name: 体重, type: line, data: weights, smooth: true, areaStyle: { opacity: 0.2 } } ] })这一块几乎是模板式代码但很加分。你可以把起始体重、目标体重、当前体重三条线放在同一张图里做对比这样“减肥进度”这个功能就显得特别明显。2.4 管理员后台与数据统计管理员的食物库管理本质上就是一张食物表的增删改查这里不多说。我想重点提的是数据统计模块因为这是很多同学容易忽略、但评委老师容易关注的点。建议管理员首页至少展示三类统计信息近7天新增注册用户的折线图。用户每日打卡次数的柱状图。食物热量Top10排行榜的饼图或者横向柱状图。统计接口用SQL聚合实现以打卡次数为例GetMapping(/admin/stats/checkin) public Result checkinStats() { ListMapString, Object list dietRecordMapper.countCheckinByDate( LocalDate.now().minusDays(7), LocalDate.now()); return Result.ok(list); }对应的SQLSELECT record_date AS date, COUNT(DISTINCT user_id) AS count FROM diet_record WHERE record_date BETWEEN #{start} AND #{end} GROUP BY record_date ORDER BY record_date注意这里用了COUNT DISTINCT表示每天有多少个不同的用户打卡而不是打卡了多少条语义不一样。写统计SQL的时候一定要想清楚你要的指标口径。2.5 可选加分项Redis缓存和Excel导出如果时间充裕我建议在系统里加两个加分项难度不大但答辩时能显著提升技术分量。第一个是Redis缓存。比如把食物库列表在系统启动时加载到Redis用户查询时先走缓存缓存没有再查数据库。代码如下Cacheable(value foodList, key #categoryId) public ListFood listFoodByCategory(Long categoryId) { return foodMapper.selectList( new LambdaQueryWrapperFood().eq(Food::getCategoryId, categoryId)); }用Spring Cache抽象不需要手动操作RedisTemplate只需要在启动类上加上EnableCaching注解然后在配置类里把RedisTemplate的序列化方式配置成JSON。就这么几十行代码项目技术亮点里就可以写上“引入Redis缓存降低数据库压力”。第二个是Excel导出。用EasyExcel把食物库数据导出成Excel文件这个功能在答辩演示时特别实用老师一看就知道你做过实际交付的东西。GetMapping(/admin/food/export) public void exportFood(HttpServletResponse response) throws IOException { ListFood foodList foodMapper.selectList(null); response.setContentType(application/vnd.ms-excel); response.setCharacterEncoding(utf-8); response.setHeader(Content-Disposition, attachment;filenamefood.xlsx); EasyExcel.write(response.getOutputStream(), Food.class).sheet(食物库).doWrite(foodList); }有了这两个功能你的项目就不再是“人人都会的CRUD”了而是有缓存设计、有数据导出能力的完整系统这个在评分表上都是能拉开差距的点。3. 手把手从零搭建并跑通整套系统现在进入环境搭建和运行部分。我把每一步都写细一点因为据我观察大多数同学拿到一个新项目最大的障碍不是不懂技术而是不知道“先后顺序”。3.1 开发工具与版本选择版本问题我放在最前面说因为这一步出错后面会连环爆炸。工具推荐版本说明JDKJDK 1.8 或 11不要用JDK 17以上跑SpringBoot 2.x会有兼容问题Maven3.6.x 或 3.8.x版本太低下载依赖容易报错IDEA2022以上版本社区版也行别用太老的Node.js14.x 或 16.x版本太高会导致node-sass等依赖安装失败MySQL5.7 或 8.0两个版本都行连接串略有差异Navicat任意版本用来导入数据库脚本查看数据这里我特别强调一下Node的版本。Vue 2项目里经常用到node-sass这个库对Node版本非常敏感Node 17以上大概率安装失败。如果你已经安装了新版本Node建议用nvm切换回Node 14整个前端跑起来会顺很多。Vue 3项目用的是vite和vue/compiler-sfc对Node版本要求相对宽松一些但为了稳妥最好也统一用16。3.2 后端项目初始化与配置拿到源码后先用IDEA以Maven项目的方式导入后端工程。导入的时候IDEA会自动读取pom.xml开始下载依赖这个过程可能需要几分钟取决于你的网络情况。依赖下载完成后第一步先去改application.ymlserver: port: 8088 spring: datasource: url: jdbc:mysql://localhost:3306/health_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 mybatis-plus: configuration: 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-secret-key-change-me expire: 7200注意几件事MySQL 8.0的驱动类是com.mysql.cj.jdbc.DriverMySQL 5.7也可以用这个区别不大。url里必须带上serverTimezoneAsia/Shanghai否则时间字段会报错。数据库账号密码一定要改成你自己本机的这一步是最常见的启动失败原因。改完配置直接运行HealthApplication类看到类似“Started HealthApplication in 5.32 seconds”的日志后端就算启动成功了。3.3 前端项目搭建与启动前端工程一般是一个独立的Vue项目名字可能叫health-web或者health-ui。用命令行进入目录执行npm install如果是在国内网络环境下建议先设置淘宝镜像不然npm install容易卡死npm config set registry https://registry.npmmirror.com依赖安装完成后执行npm run serve当控制台出现“Compiled successfully”并且提示你访问localhost:8080时前端就起来了。但此时前后端还没有打通因为前端页面里的接口请求需要转发到后端的8088端口。这一步在前端项目里通过vue.config.js的devServer代理解决const { defineConfig } require(vue/cli-service) module.exports defineConfig({ transpileDependencies: true, devServer: { port: 8080, proxy: { /api: { target: http://localhost:8088, changeOrigin: true } } } })前端所有axios请求统一以“/api”开头后端Controller的RequestMapping里也统一以“/api”开头这样开发环境下前端不用处理跨域问题请求全部由代理转发。等到真正部署的时候用Nginx再配一次反向代理就行。3.4 数据库脚本导入与初始账号在Navicat里新建一个数据库名字和application.yml里的保持一致比如health_db字符集选utf8mb4。然后把项目里的health.sql脚本拖进去执行。执行完检查一下表结构应该有用户表、角色表、食物表、运动记录表、饮食记录表、体重记录表、公告表等。初始账号一般已经写死在SQL脚本里常见的是管理员admin / 123456普通用户user / 123456如果脚本里没写初始账号最简单的办法是直接调后端注册接口在浏览器里访问后端的Swagger地址或者用Postman调一次注册接口。我强烈建议项目里集成Swagger理由后面说。3.5 联调启动的完整顺序我按自己调试项目的习惯把启动顺序整理一下。这个顺序非常重要一定要照做先启动MySQL服务确认能正常连接。导入数据库脚本检查表是否生成。启动后端SpringBoot项目确认控制台没有报错。用浏览器访问后端接口地址比如localhost:8088/api/food/list看是否正常返回JSON。启动前端Vue项目npm run serve。浏览器访问前端地址登录、注册、打卡、看图表逐个功能点测试。我见过太多人上来就启动前端结果页面一堆报错其实后端还没跑起来。前后端分离项目调试永远要先确认后端接口通再去看前端。4. 跑项目时最容易踩的坑与排查方案这个章节我单独拿出来写因为从我的经验来看代码本身往往没太大问题真正卡住用户的全是环境和版本问题。下面这些都是我在帮人调试时反复遇到的高频问题。4.1 Maven依赖下载慢或下载失败后端导入IDEA后Maven需要从中央仓库下载大量依赖。国内网络下经常出现jar包下载到一半就失败或者卡住不动的情况。解决方案是修改Maven的settings.xml文件把镜像源换成阿里云仓库mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror改完之后在IDEA里点击Maven面板的刷新按钮让依赖重新下载。如果还有个别jar包损坏可以找到本地仓库目录把对应文件夹删掉再重新刷新下载。4.2 后端启动报错的排查路径后端启动报错是最常见的但绝大多数都是那几类问题。我整理了一个排查对照表现象大概率原因解决方案Access denied for user rootlocalhost数据库账号密码错误修改application.ymlUnknown database health_db还没创建数据库在Navicat里新建数据库Table doesnt exist没导入SQL脚本执行health.sqlPort 8088 was already in use端口被占用找到占用进程并杀掉或改端口Failed to configure a DataSource数据源配置没生效检查yml缩进和账号密码java.lang.UnsupportedClassVersionErrorJDK版本和项目不兼容切换JDK版本建议1.8Cannot load driver class: com.mysql.cj.jdbc.Driverpom里没引入MySQL驱动检查pom.xml依赖这里重点说端口占用的问题。Windows系统下用这个命令查找占用8088端口的进程netstat -ano | findstr 8088拿到PID后在任务管理器里找到对应进程结束掉或者在命令行执行taskkill /pid 12345 /f4.3 前端依赖安装失败与启动报错前端的坑主要集中在两处一是npm install报错二是npm run serve之后页面空白或报错。npm install报错先看报错信息里有没有node-sass。如果有十有八九是Node版本太高用nvm切换到Node 14再试。切换Node版本之后最好把node_modules目录和package-lock.json文件删掉重新安装避免残留文件的干扰。npm run serve之后页面空白打开浏览器控制台如果看到“Cannot GET /”说明前端路由配置有问题检查一下router的mode。如果用的是createWebHistory模式刷新页面会404改成createWebHashHistory模式使用#路由就不会有这个问题。这也是一个典型的开发环境小坑。4.4 Vue项目打包后布局异常的真相这个热搜词我太熟悉了。很多同学开发时一切正常一执行npm run build把dist目录扔到服务器上打开页面发现样式全乱了图片也没了。原因基本是打包路径用的绝对路径。Vue CLI项目需要在vue.config.js里设置publicPathconst { defineConfig } require(vue/cli-service) module.exports defineConfig({ publicPath: ./, // 其它配置 })publicPath设置为./打包后所有静态资源引用路径都变成相对路径放到服务器任意子目录下都能正常访问。这个问题在开发环境不会暴露只在部署时出现所以特别容易被忽略。4.5 跨域问题与接口403排查开发环境我前面已经说了用devServer代理就能解决跨域。但如果你不用代理非要前端直接请求后端接口那就必须在后端配置跨域Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }如果你加了JWT拦截器还要注意一个问题预检请求是OPTIONS方法它不会携带Token。所以拦截器里要放行OPTIONS请求否则前端大概率遇到“Request failed with status code 401”的报错。这个细节很多人写了CORS配置却依然报跨域根源就在拦截器把预检请求拦了。5. 毕业论文结构设计与答辩提分技巧源码和项目跑通只是前半场毕业论文和答辩才是真正的重头戏。这部分我结合自己看过的许多论文和答辩现场给出一套可以直接套用的框架。5.1 论文目录应该怎么搭一份完整的毕设论文最重要的就是目录结构清晰。我推荐以下结构章节内容要点篇幅建议第一章 绪论研究背景与意义、国内外现状、主要工作4-5页第二章 相关技术介绍SpringBoot、Vue、MySQL、Redis等5-6页第三章 系统需求分析可行性分析、功能需求、用例图、非功能需求6-8页第四章 系统设计架构设计、功能模块设计、数据库设计ER图表结构10-12页第五章 系统实现每个模块的界面截图核心代码文字说明15-20页第六章 系统测试测试环境、测试用例表、测试结果分析5-8页第七章 总结与展望项目总结、存在的不足、未来优化方向2-3页数据库设计章节一定要画ER图这个我用的是draw.io或者ProcessOn导出的图片很清晰。每一个表都要有小节说明包括字段名、类型、含义、主外键关系。系统实现章节不要光贴代码也不要光放截图。正确写法是先用文字描述这个模块的业务流程然后放功能截图最后贴核心代码并解释关键逻辑。这三者缺一不可。5.2 写论文最容易忽略的三个细节第一个细节是图表编号。论文里所有图和表都要有编号和标题图在下方表在上方。不要小看这一点很多老师的评分表里专门有“格式规范”这一项。第二个细节是参考文献格式。引用格式要符合标准一般学校都会提供模板建议按模板逐条改不要贪多凑到20-30篇就够了。SpringBoot、Vue相关的国内外文献很好找别整篇论文只在最后一页列几篇无关文章那是大忌。第三个细节是测试章节。系统测试不能只写“测试通过”要有测试用例表包括模块名称、测试步骤、预期结果、实际结果。这不仅是为了凑篇幅更是向评委老师展示你做过功能验证的证据。5.3 答辩高频问题与答题思路评委老师问来问去其实就那几个方向。我把高频问题整理成一份速查表并且标注了答题思路。高频问题答题思路为什么选择SpringBootSpringBoot简化Spring配置内嵌Tomcat自动装配适合快速开发JWT和Session有什么区别JWT无状态、跨域友好、服务端不用存session注意过期与刷新密码是怎么存储的BCrypt加密哈希加盐避免反查数据库表之间是什么关系用户与饮食记录1对N用户与体重记录1对N管理员与食物1对N系统有哪些安全措施JWT认证、拦截器校验、密码加密、SQL预编译防注入、XSS过滤Redis在项目中用在哪里查询频繁的食物库缓存、验证码缓存如果做了的话减肥推荐热量的依据是什么Mifflin-St Jeor公式计算BMR乘以活动系数设置减脂缺口如果用户量大了怎么办引入Redis缓存热点数据、数据库读写分离、分页查询、接口限流答题的关键不是背答案而是把项目里真实的做法讲清楚。比如问到Redis你就直接说“我在食物查询接口上加了Spring Cache缓存缓存key是食物分类ID这样可以减少数据库查询频率”远比空洞地说“Redis性能很好”要打动人。还有一点答辩前建议自己从浏览器登录系统完整走一遍用户流程和管理员流程把每个页面的数据来源都搞清楚。老师经常会指着某个页面问“这个图的数据从哪来”你如果说不上来前面讲得再好也会打折扣。反过来你要是能清楚地回答“这个折线图的数据是前端调用weight接口按日期分组查询得到的”老师心里对你的评价马上就不一样了。这套系统做下来核心价值不在于代码量有多大而在于它完整覆盖了一个Web项目的所有关键环节需求分析、数据库建模、后端接口开发、前端页面实现、联调测试、论文撰写、答辩展示。每一个环节都有能拿出来讲的细节。你在调试它的时候踩过的每一个坑最后都会变成答辩时的底气。别只做“代码搬运工”把它当成一次真正走向工作岗位前的全流程演练收获会比分数本身大得多。
返回列表