资讯动态

SSM+微信小程序毕设实战:健身打卡项目从架构到答辩全解析

发布时间:2026/10/18 12:02:43 来源:尧图企业网站定制
简介一套针对Java毕业设计场景的SSM微信小程序健身小助手项目包面向需要完整可运行课题源码的高校学生及课程设计者业务围绕健身管理展开适合参考学习前后端分离的小程序开发模式。该项目已完成导师审核并通过答辩评审分达97分在Windows10/11环境中严格调试部署包内含数据库初始化SQL、环境配置文件与启动脚本下载后按文档说明即可运行。资源共1066个文件压缩包32.55MB主要类型包括Java后端源码、Vue管理端页面、小程序wxml/wxss结构、SQL数据库文件以及答辩PPT、开题报告、任务书、使用文档、演示视频等全套资料png/svg图片与图标用于界面展示xml/yml等配置用于参数调整整体目录分层清晰便于按模块查阅和二次开发。目前已有160人学习下载读者可据此快速理解健身类小程序的功能组织、数据库设计以及移动端与后端联调方法是毕业设计开题、答辩与项目落地的优质参考。1. 健身小助手这种高分优秀毕设包打开之后第一步不是看代码很多同学拿到 SSM 微信小程序 源码文档演示视频一应俱全的健身小助手项目时第一反应是赶紧翻代码然后就被几十个类文件和一堆 XML 配置劝退。实际上标题里真正值钱的不是健身这两个字而是 SSM 后端与小程序前端之间那套完整的联调链路以及源码、数据库、开题报告、PPT、使用文档、演示视频组成的可验证闭环。这个方向能解决两类真实问题一是毕设阶段需要一个既能现场演示、又能讲出业务深度的选题二是你有 Java 基础但没完整做过小程序前后端联调想找一个稳的骨架来改业务。它适合正在准备 Java 方向毕业设计的学生也适合想快速建立 SSM 小程序完整认知的开发者。这篇笔记直接按拆结构 → 跑通 → 改业务 → 防踩坑 → 准备答辩的顺序来写照着走能省下至少一周的弯路。2. 拆解项目骨架SSM 后端、MySQL 业务表、小程序前端的分工与边界拿到项目包不要急着启动先把三层结构看清楚。健身小助手这种项目代码量不大但结构是否清晰直接决定你后面改业务和答辩的难度。2.1 后端三层到底怎么分Controller 只做转发Service 写业务Mapper 只碰 SQLSSM 三个框架的分工常被一句话带过Spring 管对象、SpringMVC 管请求、MyBatis 管数据库。但真正打开源码之后层与层之间的边界才是决定这个项目能不能讲清楚的地方。常见做法是按 controller / service / mapper 三层切包我也见过不少翻车案例把查询逻辑直接写在 Controller 里一个方法堆两三百行答辩时导师一问事务怎么控制异常在哪处理就接不上话。一个典型的打卡请求流转是这样的小程序 wx.request 把 JSON 数据 POST 到 /api/checkin/add → DispatcherServlet 分发到 CheckinController → Controller 调用 CheckinService 接口的实现类 → Service 里做参数校验、重复打卡判断、事务控制 → 通过 CheckinMapper 接口操作数据库 → 结果逐层返回。这里的关键约束是Controller 不写 SQL也不处理事务只负责拿参数、调服务、返回统一 Result 对象事务注解 Transactional 只出现在 Service 实现类上。这样拆的好处是业务变更时只改 Service 和 Mapper接口路径不动小程序端也不用跟着改。如果你拿到的项目里把 Mapper 的查询结果直接返回给前端要格外注意实体类通常带着级联关系直接序列化容易把关联对象整串带出去甚至会触发 Jackson 的无限递归这个问题第 5 章单独讲。更稳的做法是 Controller 返回 VO视图对象把实体类留在服务层内部。能主动说出为什么不用实体类直接返回的人不多这是答辩时一个很好的加分点。2.2 数据库不是四张表的事用户、打卡、计划、身体数据的字段设计与关联健身小助手这类业务核心表跑不掉这几类用户表绑定微信 openid、打卡记录表、健身计划表。身体数据看似单独一张表但对这个量级的项目冗余在用户表里更实用——身高体重本身就变化缓慢用户每次打开首页需要的是最新值没必要为了所谓的规范化拆一张历史曲线表出来只有当你打算做体重周趋势图时才值得单开 body_record 表。设计的关键不是表多而是字段粒度是否经得起提问。CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, openid VARCHAR(64) NOT NULL COMMENT 微信登录唯一标识, nickname VARCHAR(32) DEFAULT 健身用户, gender TINYINT DEFAULT 0 COMMENT 0未知 1男 2女, height DECIMAL(5,2) DEFAULT NULL COMMENT 身高cm, weight DECIMAL(5,2) DEFAULT NULL COMMENT 体重kg, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;openid 是微信小程序登录后由微信接口返回的字符串同一用户对同一小程序是固定不变的所以必须加唯一索引。身高体重用 DECIMAL 而不是 FLOAT因为 FLOAT 在比较和展示时容易出现精度尾差DECIMAL(5,2) 能存 0.00 到 999.99对体重和身高完全够用。create_time 用 DATETIME 并默认当前时间减少业务代码里手动 new Date() 的重复劳动。CREATE TABLE checkin ( id INT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL COMMENT 关联user.id, plan_id INT DEFAULT NULL COMMENT 关联plan.id可为空, type TINYINT NOT NULL COMMENT 1跑步 2力量 3瑜伽, duration_min INT DEFAULT 0 COMMENT 运动时长分钟, calories INT DEFAULT 0 COMMENT 消耗卡路里, status TINYINT DEFAULT 0 COMMENT 0正常 1已撤销, checkin_date DATE NOT NULL COMMENT 打卡日期, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_date (user_id, checkin_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT打卡记录表;checkin_date 用 DATE 而不是 DATETIME这是很多人第一次建表容易踩的点如果存 DATETIME同一天多次打卡的时间不同判断今天是否已打卡时就得用 DATE(checkin_date) 函数把字段包一层写了函数的列索引会失效查询性能打折且写法难看。用一个单独的 DATE 字段直接等值查询就能命中联合索引 idx_user_date。status 字段用来做撤销而不是直接 DELETE 记录这样统计报表里能保留历史并且撤销可追溯。CREATE TABLE plan ( id INT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL, goal TINYINT NOT NULL COMMENT 1减脂 2增肌 3保持, week_count TINYINT DEFAULT 3 COMMENT 每周计划训练次数, status TINYINT DEFAULT 1 COMMENT 1进行中 2已完成 3已放弃, start_date DATE NOT NULL, end_date DATE DEFAULT NULL, PRIMARY KEY (id), KEY idx_user_status (user_id, status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT健身计划表;计划表的关键在于 status 的流转必须由后端 Service 控制而不是小程序端随便传。常见做法是一个轻量的状态机进行中 → 打卡次数达标 → 已完成超过计划结束日期仍未达标 → 已放弃。字段只是存状态状态怎么变由后端逻辑说了算这点答辩时能展开讲两分钟。2.3 小程序端不是只看页面目录结构、请求封装与登录态的打开方式小程序端最怕的是每个页面都直接 wx.request 裸调路径写死、错误处理重复、token 手工拼。拿到项目先看 utils 或 api 目录通常这里会有一个封装好的 request 方法负责拼接 baseURL、注入 token、统一处理业务码和 401。// utils/request.js const BASE_URL http://192.168.1.100:8080; // 开发环境用电脑局域网IP function request(path, method, data) { return new Promise((resolve, reject) { const token wx.getStorageSync(token); wx.request({ url: BASE_URL path, method: method || GET, data: data || {}, header: { Content-Type: application/json, token: token || }, success: (res) { if (res.data.code 0) { resolve(res.data.data); } else if (res.statusCode 401) { // token 过期或失效清掉并跳登录页 wx.removeStorageSync(token); wx.reLaunch({ url: /pages/login/login }); } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(res.data); } }, fail: () { wx.showToast({ title: 网络连接失败, icon: none }); reject(new Error(network error)); } }); }); } module.exports { request };这里 BASE_URL 用 192.168.x.x 是关键开发者工具里可以用 localhost但真机预览时手机上的 localhost 指向手机自己必然连不上电脑上的后端。请求被包成 Promise 后页面里用 async/await 读代码会清爽很多。注意一个容易误判的细节wx.request 只要请求发出去了即使 HTTP 状态码是 401也会走 success 回调而不是 fail所以 401 的判断必须放在 success 里通过 res.statusCode 做分支我见过有人把它放 fail 里导致登录过期后永远没有跳转。登录态这一环小程序和普通网页登录不同前端 wx.login 拿到临时 code 发给后端后端拿 code 向微信接口换 openid再生成自己的 token 返回前端。前端把 token 存进 storage后续请求在 header 里带 token 识别用户。token 过期后的 401 统一处理放在 request 封装里而不是每个页面各写一遍。3. 把项目跑起来环境搭配、数据库导入、双端联调的完整命令如果说拆结构是看懂那跑通就是落地。这一章照着做目标是在 30 分钟内让后端和小程序同时在你的机器上工作。3.1 环境版本怎么搭才不会在启动时翻车健身小助手是典型的老牌技术栈组合版本搭配有一个稳的配方我一般建议照这个来不要追求新版本组件推荐版本备注JDK1.8 / 8SSM 项目在 JDK 8 下编译最稳JDK 17 会碰到强封装报错Maven3.6.33.8 对仓库源有调整个别私服镜像配置会失效Apache Tomcat8.5Spring 5 Tomcat 9 也行但 8.5 是最少折腾的组合MySQL5.78.0 也能用但驱动要换 mysql-connector-java 8.x注意时区参数微信开发者工具最新稳定版只影响前端编译基本无兼容问题这个表格不是玄学是有实际原因的。SSM 项目大多基于 Spring 5.x、MyBatis 3.5.x 这一代依赖它们对 JDK 8 的支持最完整JDK 11 也能跑但反射相关的强封装在 JDK 17 会直接抛异常。数据库方面MySQL 8 默认驱动类名从 com.mysql.jdbc.Driver 改成了 com.mysql.cj.jdbc.Driver如果项目里的 jdbc.properties 还写着旧类名启动必然报 class not found。所以拿到项目先核对这几处再动数据别一上来就怀疑代码。3.2 导入数据库和修改配置最容易被忽略的三个位置第一步不是启动 IDEA而是把数据库建出来。项目里通常带一个 .sql 文件用命令行导入mysql -uroot -p123456 -e CREATE DATABASE IF NOT EXISTS fitness DEFAULT CHARSET utf8mb4 mysql -uroot -p123456 fitness fitness.sql命令行导入的好处是编码可控。用可视化工具导入时如果不注意选择 utf8mb4经常出现表建出来了、中文注释全变问号的情况。导入后先验证核心表是否存在SHOW TABLES;然后改配置文件。SSM 项目的数据库配置一般在 jdbc.properties 或 application.propertiesjdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/fitness?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456这里三个位置必须检查driver 是否与 MySQL 版本匹配MySQL 8 要换 com.mysql.cj.jdbc.Driver记得同步升级 mysql-connector-java 依赖url 是否带 characterEncodingutf8缺了中文写入必乱码serverTimezone 是否设置MySQL 8 在某些时区配置下会在连接时报错。数据库密码只要包含特殊字符在 properties 里就得做转义处理省事起见直接把密码改成简单的数字字母组合。最后是 Maven 导入。用 IDEA 打开项目顺序错了会很难受先等右下角 Maven 依赖下载完成再配置 Tomcat。配置路径是 Run Configurations → 新增 Tomcat Server → Local → Deployment 里把项目的 exploded artifact 加进去然后启动。启动成功的标志不是控制台开头那段 Spring 日志而是最后一行类似 Deployment of web application archive ... has finished。如果卡在这一步先确认 Tomcat 版本和项目 web.xml 头部声明是否匹配web 3.x 对应 Tomcat 7 以上web 4.x 需要 Tomcat 9声明和容器对不上会启动时报错。3.3 小程序端联调开发者工具三个设置一次搞定后端起来了小程序端打开项目目录依次做三件事。第一件在微信开发者工具里关掉域名校验详情 → 本地设置 → 勾选不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书。开发环境走 http 和局域网 IP不勾这一项请求直接 fail页面永远白屏而且不会告诉你具体原因。第二件改 BASE_URL 为电脑的局域网 IPconst BASE_URL http://192.168.1.100:8080;怎么拿到这个 IPWindows 命令行执行 ipconfig找到无线局域网适配器或以太网适配器下的 IPv4 地址手机和电脑连同一个 WiFi就能真机预览。这里最常见的问题不是 IP 填错而是路由器开了 AP 隔离手机和电脑互 ping 不通表现就是网络层完全连不上后面避坑章节还会提。第三件先验证后端接口独立可访问。在浏览器直接访问 http://192.168.1.100:8080/api/user/info 这类 GET 接口能看到 JSON 返回说明后端网络层是通的问题就只在小程序配置侧。然后再打开开发者工具的 Network 面板点一次登录请求确认状态码和响应体。联调阶段的核心原则是先证明后端独立可访问再去怀疑小程序端。这个顺序能少排查一半问题。4. 健身业务怎么落地打卡防重、计划推荐、统计聚合三块核心代码项目跑通只是开始真正决定你能不能讲清楚业务深度的是这三块核心代码。它们恰好也对应答辩时最容易被追问的三个问题。4.1 打卡接口的幂等设计同一用户一天只能打一次卡健身小助手最核心的业务动作是打卡。这个接口看着简单但直接往表里 insert 一定被导师问住用户手抖点了两次怎么办网络重试呢所以实现上要先查后插把重复的判断放在 Service 层同时配合数据库唯一索引兜底。Service public class CheckinServiceImpl implements CheckinService { Override Transactional(rollbackFor Exception.class) public Result add(CheckinDTO dto) { // 1. 按用户和当天日期查是否已有记录 LocalDate today LocalDate.now(); Checkin exists checkinMapper.selectByUserAndDate(dto.getUserId(), today); if (exists ! null) { return Result.fail(1001, 今天已经打过卡不要重复提交); } // 2. 构建记录并插入 Checkin checkin new Checkin(); checkin.setUserId(dto.getUserId()); checkin.setType(dto.getType()); checkin.setDurationMin(dto.getDurationMin()); checkin.setCalories(dto.getCalories()); checkin.setCheckinDate(today); return checkinMapper.insert(checkin) 0 ? Result.ok() : Result.fail(1002, 打卡失败); } }这个实现有三个要点。第一LocalDate.now() 用的是服务器时区如果日后部署的服务器和客户端跨时区会出现客户端显示是今天、服务端判定是昨天的情况联调时把时区对齐成 Asia/Shanghai。第二Transactional 加在 Service 方法上保证查重 插入两步同生共死防止查重通过但插入异常时留下半截业务状态。第三返回码设计成业务码 1001 和 1002 而不是 HTTP 500前端拿 code 判断业务失败拿 statusCode 判断网络失败两者分开处理才不会被一个弹窗糊弄过去。对应的 Mapper XML 里查重语句要只查必要字段select idselectByUserAndDate resultTypecom.example.entity.Checkin SELECT id, user_id, type, duration_min, calories, status, checkin_date FROM checkin WHERE user_id #{userId} AND checkin_date #{date} LIMIT 1 /select注意这里没有查 create_time也没有查 plan_id。查询列只带回业务需要判断的字段能避免 MyBatis 去触碰关联对象省掉一次可能的懒加载触发点。检查一下 #{date} 传的是 java.time.LocalDateMyBatis 会直接映射到 DATE 列不需要额外转换。考虑到并发场景Service 层的先查后插存在一个极小的竞态窗口同一用户连点两次两个请求同时通过判空然后各自插入一条。到最后严格兜底的是表上的联合唯一索引这里我建议给 checkin 表再加一个UNIQUE KEY uk_user_date (user_id, checkin_date)如果项目里没加自己补上在答辩时主动讲出接口幂等靠业务判断数据一致性靠唯一索引兜底这句话能让评委看到你理解到位的分层防线。4.2 计划推荐先做 BMI 分层再按目标过滤别一上来就谈算法计划推荐是项目里最有业务深度的部分也是最容易被过度设计的地方。一个毕设体量不需要引入规则引擎或者跑来跑去的模型把推荐逻辑清晰写在 Service 层的 if-else 里反而最好讲、最好维护。public ListPlanVO recommend(Long userId) { User user userMapper.selectById(userId); // 1. 计算 BMI 体重(kg) / (身高(m)^2) double heightM user.getHeight() / 100.0; double bmi user.getWeight() / (heightM * heightM); // 2. 按国内常用参考线分层决定目标类型 int goal; if (bmi 24) { goal 1; // 偏重推荐减脂 } else if (bmi 18.5) { goal 2; // 偏瘦推荐增肌 } else { goal 3; // 正常推荐保持 } // 3. 排除用户已创建的计划避免重复推荐 return planMapper.selectByGoal(goal, user.getId()); }BMI 大于等于 24 归为偏重、低于 18.5 归为偏瘦这是国内常用的参考线。代码里写常量没问题但答辩时最好主动说一句这个阈值目前是常量后续可以改造成配置表或写成系统参数。这句主动陈述比贴十行代码更能展示设计意识。selectByGoal 的第二个参数传当前用户 id目的是在 SQL 里排除已创建的计划避免用户反复收到同一套推荐。SQL 侧对应如下SELECT id, goal, week_count, start_date, end_date FROM plan WHERE goal #{goal} AND user_id ! #{userId} ORDER BY RAND() LIMIT 3这里 ORDER BY RAND() 在数据量很小的场景下没问题能实现每次进去推的内容不完全一样的效果足够演示。数据量上千以后 RAND() 会全表扫但在这个项目的体量里完全不需要为此改成复杂的随机策略——这就是我要强调的别过度设计方案要和业务量级匹配讲清楚取舍比盲目堆技术更能说服人。4.3 统计报表一条 SQL 聚合出一周的运动量统计页是演示效果最好的页面它把打卡表按类型和日期聚合前端画成柱状图。SELECT type AS exercise_type, COUNT(*) AS total_times, SUM(duration_min) AS total_minutes, SUM(calories) AS total_calories FROM checkin WHERE user_id #{userId} AND checkin_date BETWEEN #{startDate} AND #{endDate} AND status 0 GROUP BY type ORDER BY total_minutes DESC这条 SQL 有三个值得对导师讲清楚的决策点。第一BETWEEN 两端是 DATE 类型所以边界是包含当天 00:00 到 23:59:59 的完整一天这也是前面建表把 checkin_date 单独定为 DATE 字段的原因——如果这里用 DATETIME统计周报时得小心处理下边界。第二status 0 把撤销记录排除在统计外既保留了数据又不污染报表。第三GROUP BY type 之后的结果直接给前端渲染Java 层不需要再做二次聚合。如果项目里还需要按周、按月汇总常见做法是在 Service 层根据传入的 startDate 和 endDate 调同一个方法前端用日期选择器控制范围。至于要不要用存储过程或者物化视图对这个演示场景完全没必要反而会让导师觉得你把简单问题复杂化了。5. 避坑指南跑通健身小助手最常见的 5 个坑这一章不是理论推导是照着项目一步步跑才能真正遇到的坑。每一条都按现象 → 原因 → 解决来讲。5.1 小程序请求一直 fail后端却什么都没收到现象开发者工具里点打卡请求一直 fail后端控制台没有任何日志浏览器直接访问接口却正常返回 JSON。原因绝大多数情况是开发者工具的域名校验没有关闭或者请求地址不是局域网 IP。开发环境的 http 接口和 IP 直连都会被微信的合法域名校验拦下表现就是 fail且不返回具体原因很容易被误判成后端代码问题。解决勾选不校验合法域名后重新编译同时确认 BASE_URL 是电脑的局域网 IP。真机预览时手机必须和电脑在同一局域网。想确认是不是域名校验问题可以把 BASE_URL 临时改成 https 的公网地址测一次能通就说明问题出在校验配置不是代码逻辑。5.2 数据库中文乱码字符串存进去变成问号现象用户昵称、计划名称等中文数据在小程序端输入正常写入数据库后就变成 ?? 或乱码。原因两层问题叠加。一是数据库连接串没带 characterEncodingutf8二是表或库的字符集不是 utf8mb4。只改其中一处问题依旧。解决先确认连接串再确认表结构。connection 串要带useUnicodetruecharacterEncodingutf8建表语句统一DEFAULT CHARSETutf8mb4。如果表已经建出来执行下面语句修复ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4;改完重启后端再测一次。这条的隐蔽之处在于如果连接串带了对 charset 而表不对录入时并不报错只是存入的数据已经损坏改完表结构后旧数据需要清理不要留着。5.3 启动报 NoClassDefFoundError依赖冲突比缺依赖更隐蔽现象Tomcat 启动时抛 NoClassDefFoundError 或 ClassNotFoundException但不是每次都出现偶尔重启又好了。原因典型情况是项目 Web-INF/lib 下手动放了旧版本的 jar同时 Maven 又拉了一份新版本classpath 里出现重复类加载顺序又不固定表现就是时好时坏。SSM 老项目经常会有人图省事把整个 lib 目录拷进去。解决把 lib 目录下手动添加的 jar 清掉依赖全部交给 Maven 管理。检查方法是在 IDEA 的 Maven 面板执行mvn dependency:tree看同一个 artifact 是否出现多个版本。如果某个依赖确实不在中央仓库确保它只在 lib 里存在pom 里不要再声一次。这个坑排查起来费时间提前清理能帮你省下一整晚。5.4 JSON 序列化死循环返回关联对象直接栈溢出现象请求打卡列表时接口返回 500控制台报 infinite recursion 或 StackOverflowError。原因实体类存在双向关联。比如 checkin 实体里有一个 User 对象User 实体里又有一个 ListCheckinJackson 序列化时 A 引 B、B 引 A递归到栈溢出。解决在关联字段上加 JsonIgnore序列化时跳过该侧。public class User { // 其他字段略 JsonIgnore private ListCheckin checkinList; }如果需要返回关联信息就新建 VO 对象只放需要的字段。顺手把不该暴露的用户内部字段一起过滤掉等于补了个安全隐患答辩时还能顺便讲一句序列化对象和持久化对象分离的设计原则。5.5 token 过期后页面弹一堆报错弹窗现象登录态过期后用户继续操作每个页面弹一次请求失败接口返回 401体验非常差。原因对 401 的处理逻辑散落在各个页面每个页面单独 showToast没有统一的过期跳转。解决按 2.3 的做法在 request 封装里做统一拦截statusCode 为 401 时清除本地 tokenwx.reLaunch 到登录页页面层只处理业务错误码。改完验证一次手动把 storage 里的 token 改错操作任意接口应该只发生一次跳转而不是满屏报错弹窗。6. 从能跑到高分答辩演示路径和两个加分验证技巧项目能跑通只是及格线答辩时导师想听的是你为什么这么设计和你怎么证明它能工作。这里给你两个现成的验证技巧。第一个是数据对比演示。答辩前准备一个专门的演示账号提前录入 3 到 5 天的打卡数据答辩现场操作小程序再新增一条打卡然后切到数据库执行SELECT checkin_date, type, duration_min, calories FROM checkin WHERE user_id 1 ORDER BY checkin_date DESC;屏幕左边是小程序提交页面右边是数据库查询结果现场新增的记录实时出现在第一行。这个动作比PPT上十页截图都有说服力它直接证明了接口链路是通的、数据落库是真实的而不是录好的演示视频或者写死的 mock 数据。第二个技巧是主动讲为什么这样建表。答辩时把三件事说清楚checkin_date 用 DATE 而不是 DATETIME 的业务理由status 字段保留撤销记录的意义openid 唯一索引的必要性。这三点背下来十分钟技术问答至少能稳稳接住一半。演示顺序我一般建议先展示小程序端完整操作流程再打开后端控制台实时看日志输出最后抛数据库查询求证。这个顺序让导师看到的东西从页面能点逐层深入到底层存储覆盖全链路的证据链条。如果项目里有管理端还可以加一步在小程序里操作管理数据列表同步变化这样前后端联动就更直观。最后说一点自己的教训。我做类似 SSM 项目的时候最吃亏的就是只讲能跑没准备为什么。被导师问了一个很基本的问题——这个打卡接口并发下会不会出问题——当场答得支支吾吾。后来每次演示前我把重复打卡怎么防统计为什么不用存储过程为什么事务加在 Service 层而不是 Controller这类问题写在一张纸上对着镜子提前讲一遍。准备过的回答和临场编的答案在台下的观感完全是两回事这句话我是真信了。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑