ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

小程序+Java+MySQL个人健康管理系统源码解析与部署避坑指南

小程序+Java+MySQL个人健康管理系统源码解析与部署避坑指南 简介面向小程序开发学习者与Java后端初学者的个人健康管理系统完整源码属于典型的毕业设计/课程设计项目。系统涵盖健康信息展示、数据管理及增删改查等核心服务用户可便捷维护个人健康档案。技术栈使用Java后端、Maven依赖管理、MySQL 5.7数据库及Tomcat7部署小程序端可借助微信开发者工具或HBuilderX运行调试。资源共1569个文件压缩包约35.62MB以Java、Vue、JS、JSON、WXML、WXSS等前后端代码为主另含SQL数据库脚本、DOC/DOCX设计文档、启动与安装批处理文件目录结构清晰便于按模块检索学习。目前已有199人学习下载适合用于毕业设计参考、课程设计实践或小程序与后端全栈入门。通过该项目可系统掌握小程序端与Java服务端的数据交互、数据库表设计、接口调用及Tomcat部署流程是理解完整前后端协作的实用案例。1. 从一套源码包入手小程序 Java MySQL 的个人健康管理系统怎么落地做个人健康管理系统最省时间的路子不是从零敲代码而是先找一套结构完整的源码包当骨架前端是微信小程序后端是 Java 接口数据落在 MySQL三样东西如果各自为政联调能调到你怀疑人生。这套基于小程序的个人健康管理系统源代码把小程序端、Java 后端、MySQL 脚本放在同一个压缩包里还带 LW 部分的说明文档正好对应毕业设计和课程设计里最常见的交付形态。适合两类人一是要交毕设/课设、时间紧但想让系统“能跑、能演示、能讲清楚”的同学二是想快速搭一个小程序Java 后端骨架然后替换成自己业务模块的开发者。这里不吹功能多全先讲清楚它怎么组织、怎么跑通、坑在哪。2. 系统架构三层职责与一条健康记录的完整链路2.1 小程序、Java 后端、MySQL 各干哪些活拿到这套工程后先把目录捋清楚。正常会是三个部分并列一个小程序前端工程、一个 Java 后端工程、一个数据库脚本外加 LW 文档目录。我在看毕设类源码时习惯先不看代码细节而是先找“数据从哪进、往哪存、怎么回来”这条主线因为健康管理系统本质上就是记录类 CRUD 加一点业务计算。小程序端的职责集中在页面和交互用户填身高体重、点保存、看历史列表、看趋势图这些都是前端活。前端不能直连数据库所以所有数据都得封装成 JSON 走 wx.request 发给 Java 后端。Java 后端是唯一的数据入口承担三件事校验登录态、校验业务参数、把数据交给 MySQL。MySQL 只负责存用户表、健康记录表、健康档案表基本跑不掉。端核心职责典型内容小程序端页面展示、表单输入、本地校验、发起请求wxml 页面、wxss、js 逻辑、app.json 配置Java 后端登录鉴权、接口路由、业务校验、读写数据库Controller、Service、Mapper、实体类MySQL持久化存储、按条件查询、分页用户表、健康记录表、健康档案表、资讯表这套分工不是随意的。后端做唯一入口核心原因是小程序端一旦发出去任何人都能抓到请求报文并重放如果后端不校验 token、不校验字段边界数据库会被刷得很难看。所以健康数据这种敏感业务规则必须收在后端。2.2 一条健康记录从表单到数据库的完整链路我一般会把链路拆成四步前端组包、后端接包、业务落库、回包给前端。先看小程序端的请求写法这类工程里最常见的是这种结构wx.request({ url: getApp().globalData.baseUrl /api/health/record/submit, method: POST, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) }, data: { height: formData.height, weight: formData.weight, systolic: formData.systolic, diastolic: formData.diastolic, heartRate: formData.heartRate, recordDate: 2025-01-15 }, success: (res) { if (res.data.code 200) { wx.showToast({ title: 保存成功, icon: success }); } else { wx.showToast({ title: res.data.msg, icon: none }); } } });这里有两个细节值得注意。Authorization 放在 header 里而不放在 body是因为后端拦截器通常只从 header 取 token放 body 里后端要额外解析而且业务接口的 DTO 也会被请求体污染。recordDate 用“YYYY-MM-DD”字符串而不是时间戳因为 MySQL 的 date 类型直接接收这种格式的字符串省去后端 Date 转换那一步。后端常见的接收方式是这样Controller 只做路由和参数透传PostMapping(/api/health/record/submit) public Result submit(RequestBody HealthRecordDTO dto, RequestHeader(Authorization) String token) { Integer userId JwtUtil.parseToken(token); healthRecordService.save(dto, userId); return Result.ok(); }这里的逻辑是先解析 token 拿到当前用户 ID再交给 Service 层做业务处理。有人会把 JwtUtil.parseToken 放在 Controller 里也有人写在拦截器里统一处理两种都行。但要注意如果 token 解析失败后端应该返回 401 而不是 200前端拿到 401 后要做统一跳转登录页处理否则用户会看到“保存成功”但实际没存进去。3. 核心模块拆解登录、数据录入与列表加载更多3.1 登录模块wx.login 换 code、后端换 openid、JWT 下发小程序登录跟网页登录完全是两套逻辑。网页登录是账号密码小程序是 wx.login 拿临时 code后端拿 code 去微信接口换 openid。前端登录这段几乎每个毕设工程都是这个套路wx.login({ success: async (loginRes) { if (loginRes.code) { const res await new Promise((resolve, reject) { wx.request({ url: getApp().globalData.baseUrl /api/auth/login, method: POST, data: { code: loginRes.code }, success: resolve, fail: reject }); }); if (res.data.code 200) { wx.setStorageSync(token, res.data.data.token); wx.setStorageSync(userInfo, res.data.data.userInfo); } else { wx.showToast({ title: res.data.msg, icon: none }); } } } });后端拿到 code 后要做的第一件事是调微信的 code2Session 接口用 code 换 openid 和 session_key。openid 是用户在当前小程序里的唯一标识后端拿 openid 去查用户表查不到就自动建档。这个流程里最容易写错的是直接把 openid 塞进 JWT我一般只在 token 里放 userId因为 openid 属于敏感信息而且 token 里内容越少后续校验逻辑越清爽。JWT 的密钥和过期时间值得单独说。密钥至少 32 位随机字符串别用“secret123”这种。过期时间看场景毕设演示建议 2 小时太短用户看个页面就掉线太长又显得不专业。后端生成 token 时可以顺手把用户基础信息也返回给前端省得前端再发一次请求。3.2 健康数据录入表单校验与 BMI 计算录入模块属于健康管理系统的门面身高、体重、血压、心率这几项是标配。页面表单一般长这样view classform-item text classlabel身高(cm)/text input typedigit bindinputonHeightInput value{{height}} placeholder请输入身高 / /view view classform-item text classlabel体重(kg)/text input typedigit bindinputonWeightInput value{{weight}} placeholder请输入体重 / /view button bindtapsubmitRecord保存记录/button注意 input 的 type 是 digit这样弹出的键盘是数字键盘带小数点的 type 才能输 170.5 这种值。bindinput 每次输入都会触发对应处理函数把输入值同步到 this.data。保存按钮绑定的 submitRecord 做两件事本地校验和组装参数。submitRecord() { const height Number(this.data.height); const weight Number(this.data.weight); if (height 50 || height 250) { wx.showToast({ title: 身高需在 50-250cm 之间, icon: none }); return; } if (weight 2 || weight 300) { wx.showToast({ title: 体重需在 2-300kg 之间, icon: none }); return; } const bmi weight / Math.pow(height / 100, 2); const bmiStr bmi.toFixed(1); // 拿到 bmiStr 后拼进 data走 wx.request 提交 }前端校验这段纯粹是用户体验层面的拦截真正防刷的是后端校验。BMI 的计算逻辑用体重除以身高米的平方height / 100 是把厘米换算成米这个换算漏掉的人不少算出来的值会差一万倍。toFixed(1) 保留一位小数但它在极端大数下返回指数形式所以稳妥做法是外面再包一层 parseFloat。后端拿到 DTO 后要做同样的区间校验参数越界直接返回错误码而不是让非法数据进数据库。3.3 列表加载更多分页参数与“没有更多了”的判断健康记录是按时间倒序展示的数据一多就必须分页。小程序端实现加载更多有固定套路页面到底部时触发 onReachBottom然后当前页码加一再请求onReachBottom() { if (this.data.hasMore) { this.setData({ page: this.data.page 1 }); this.loadRecords(); } else { wx.showToast({ title: 没有更多了, icon: none }); } }, loadRecords() { wx.request({ url: getApp().globalData.baseUrl /api/health/record/page, data: { page: this.data.page, pageSize: 10 }, header: { Authorization: wx.getStorageSync(token) }, success: (res) { const list res.data.data.list; this.setData({ records: this.data.records.concat(list), hasMore: res.data.data.hasMore }); } }); }这段有两个边界要特别注意。一是 hasMore 的判断必须由后端来算常见做法是根据总数和页码算出是否还有下一页前端不能靠 list.length 是否大于 0 来猜否则最后一页返回空数组时会误判。二是 records 要用 concat 追加而不是整体覆盖每次 setData 传完整列表数据量大时小程序渲染可能会变慢但毕设量级完全够用。后端对应的是标准分页查询MyBatis 里常写成 LIMITSelect(SELECT * FROM health_record WHERE user_id #{userId} ORDER BY record_date DESC LIMIT #{offset}, #{pageSize}) ListHealthRecord pageByUser(Param(userId) Integer userId, Param(offset) Integer offset, Param(pageSize) Integer pageSize);offset 用 (page - 1) * pageSize 算出来。LIMIT 这种分页在数据量过十万后会变慢但健康管理这种个人应用一辈子都攒不到十万条记录所以不要在这上面过度设计。等哪天真的数据量上来了再考虑换成按 ID 游标分页也不迟。4. 把工程跑起来从建库到真机预览的完整步骤4.1 环境准备与数据库初始化跑这套工程前先把环境对一遍JDK 建议 8 或 11MySQL 用 5.7 或 8.0 都行微信开发者工具装最新稳定版就好。这三个版本有一对不匹配后面全是眼泪尤其是 JDK 和 MySQL 驱动的关系JDK 8 配合 MySQL 8.0 的驱动JDK 11 也能跑但某些老工程用的旧驱动会在 JDK 11 上报模块化错误。数据库初始化这一步先找到包内 SQL 脚本一般叫 health.sql 或类似名字用命令行导入mysql -u root -p health_db health.sql如果 health_db 这个库还不存在先建库再导入。MySQL 8.0 里建库我通常加上字符集设置避免后面中文乱码来回折腾CREATE DATABASE IF NOT EXISTS health_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;utf8mb4 比 utf8 的优势在于能存四字节的 emoji 和生僻字健康记录里可能包含用户备注这里面什么字符都可能出现。导入完成后用 show tables 看一眼正常会有用户表、健康记录表、健康档案表等七八张表表数量过少就说明脚本导入不完整。4.2 后端配置与启动连接串里那几个参数别删后端工程导入 IDEA 后第一件事不是点运行而是改配置文件。Spring Boot 工程通常是 application.yml里面的数据源配置是关键server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/health_db?useSSLfalsecharacterEncodingutf8mb4serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver这条 URL 连缀里有三个参数建议一个都别删。characterEncodingutf8mb4 保证中文写入不出乱码serverTimezoneAsia/Shanghai 不设的话日期字段查出来会比本地时间慢 8 小时allowPublicKeyRetrievaltrue 是 MySQL 8.0 之后连 5.7 以上库常见的报错点不加会在启动时报 Public Key Retrieval 异常。驱动类名 com.mysql.cj.jdbc.Driver 是 MySQL 8.0 的写法早期工程里写 com.mysql.jdbc.Driver 的是老驱动遇到就改成这个新的。启动方式看工程类型Maven 工程直接跑mvn spring-boot:run如果包内直接带已构建的 jar就用 java -jar 启动。启动日志里看到 Tomcat started on port 8080 就说明后端起来了。我习惯启动后再用浏览器直接访问一个 GET 接口试试通不通如果接口返回 JSON 而不是报错页说明数据库连接和路由都正常。4.3 小程序端配置与真机预览微信开发者工具导入小程序前端工程后先别急着编译。第一步改 appid没有正式 appid 就点“测试号”不影响本地调试。第二步在小程序代码里找到 baseUrl 配置把它从写死的 http://localhost:8080 改成你电脑的局域网 IP否则真机预览时手机根本找不到 localhost。开发调试阶段右侧详情菜单里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”这样本地 http 接口才能打通。这个选项只是开发期救命用的上线前必须换成已备案的 HTTPS 域名。提示真机预览前确保手机和电脑连的是同一个路由器下的网络后端端口 8080 在 Windows 防火墙里要放行否则手机请求会一直卡在 pending。小程序页面的导航栏高度是个隐藏坑。微信小程序顶部导航栏在不同机型上高度不同尤其是带刘海的机型写死 88px 会在某些手机上错位。稳妥做法是动态取胶囊按钮的位置const menuRect wx.getMenuButtonBoundingClientRect(); const navBarHeight (menuRect.top - wx.getSystemInfoSync().statusBarHeight) * 2 menuRect.height;这个计算式的思路是胶囊按钮距离顶部的距离减去状态栏高度得到的就是导航栏在状态栏下方的实际高度再乘以 2 加胶囊高度基本能覆盖绝大多数机型。做自定义导航栏时用这个值去撑顶栏高度比写死可靠得多。5. 避坑手册跑源码最容易卡住的 5 个问题5.1 环境类问题MySQL 8.0 连不上与中文乱码坑一启动后端报 Public Key Retrieval is not allowed。现象是 Spring Boot 启动时数据源初始化失败日志里抛出这个异常。原因是 MySQL 8.0 默认使用 caching_sha2_password 认证插件客户端与之通信时如果没有先获取服务端公钥就会被拒。解决方式就是在 JDBC URL 末尾加 allowPublicKeyRetrievaltrue。另外一个连带问题是驱动类名过时老工程写 com.mysql.jdbc.DriverMySQL 8.0 驱动已经改成 com.mysql.cj.jdbc.Driver两个都核对一遍再启动。坑二界面显示中文全是问号。现象是健康记录里填的中文备注存进数据库后变成“???”前端查出来也是问号。原因有两层建库时没指定 utf8mb4或者 JDBC 连接串没带 characterEncodingutf8mb4。解决方式是按 4.1 的建库语句重新建库连接串也同步加上参数。注意改完连接串要重启后端光改库不重启问题照旧。5.2 联调类问题真机连不上、手机号获取失败与接口 404坑三真机预览时请求一直失败但开发者工具里正常。现象是小程序在开发者工具里跑得挺好一扫码到真机所有请求全部失败。原因基本是前端 baseUrl 写的是 localhost真机上 localhost 指手机自己或者电脑防火墙把 8080 端口拦了。解决方式是把 baseUrl 改成电脑的局域网 IP然后在电脑防火墙里放行对应端口。验证方法很简单手机浏览器直接访问 http://局域网IP:8080/某个接口能出 JSON 就说明网络通。坑四手机号获取失败。现象是用户点“手机号授权”按钮前端拿不到号码或者后端报 code expired。原因是微信早几年就改了规则getPhoneNumber 现在返回的是动态令牌而不是明文手机号前端拿到的是 code必须由后端拿 code 去微信接口换手机号而且这个 code 有效期极短且只能消费一次。如果你拿到的这套工程里还是老写法前端直接解密 encryptedData那就需要按新接口改造前端把 code 传给后端后端调微信官方接口解析。这条是很多毕设工程最容易被答辩老师挑刺的地方。坑五后端接口全部 404。现象是后端启动成功但访问任何接口都返回 404 或 401 的提示页面。原因通常是 Spring Boot 的主类包路径和 Controller 包路径不一致主类扫描不到 Controller。Spring Boot 默认扫描主类所在包及子包如果 Controller 写在别的包下又没加 ComponentScan接口就注册不上。解决方式是把 Controller、Service、Mapper 都放到启动类所在包的下层或者在启动类上显式指定扫描范围。我一般会先看 IDE 里有没有识别到 RequestMapping识别不到就优先排查包路径。6. 进阶调试抓包确认接口联调的最后一步很多人跑通界面后遇到接口报错就开始瞎猜前端还是后端的问题。我建议把抓包当成固定动作而不是玄学操作。先用微信开发者工具自带的 Network 面板找到那条失败的 wx.request点开看三个位置请求头里的 Content-Type 和 Authorization 有没有带上请求体 JSON 的字段名跟后端 DTO 是不是完全一致响应的 code 字段到底是 200 还是 401。大部分联调问题在这一步就能定位比如前端明明存了 token但 header 里的字段名写成了 auth后端拦截器取不到直接 401。小程序真机上的请求开发者工具抓不到时再用 Charles 补。给 Charles 安装并信任根证书后在 SSL 解密设置里把需要监听的小程序接口地址加进去然后清掉小程序后台进程重新进入页面避免漏掉第一条请求。抓包重点不是看数据内容而是对比“前端发出去的”和“后端收到的”是不是同一个包。字段名拼写、数组嵌套层级、日期格式这三类问题在报文对比面前一目了然。后端这边的日志也要同时开着尤其是 MyBatis 的 SQL 日志。抓到前端发的包是正常的但后端报了 500优先去后端控制台看异常栈而不是在小程序里反复点重试。异常栈里 SQLException 提示的是哪张表、哪个字段就回 MySQL 里核对表结构。抓包和日志配合着看基本能把问题精确到某一层。从那以后我每次拿到一套毕设源码都会强制走一遍“启动后端看日志、跑通登录、抓一次包确认 token 和请求体、再动页面”的顺序。这套流程帮我复现了多个项目最深的教训就是页面代码写得再花接口层不同步一切都白搭。这套个人健康管理系统也是按这个路子跑通的源码包就按项目名搜索能找到工程内部结构以压缩包实际内容为准希望帮到你。本文还有配套的精品资源点击获取
返回列表