
简介面向高校计算机相关专业学生与微信小程序开发者的毕业设计论文系统展示基于Spring Boot框架、MySQL数据库和微信小程序技术栈的健康管理平台设计与实现。论文内容层次清晰覆盖用户管理、健康数据记录、运动与饮食追踪、健康知识学习、社区互动等核心功能模块同时包含摘要、关键词、目录、开发工具介绍、需求分析、系统设计等完整章节既说明业务功能如何落地也呈现服务器端逻辑、数据存取与界面交互的实现思路可作为课题选题、论文写作、系统开发或答辩准备的参考范本。资源共1个doc文件压缩包大小约6MB以Word文档形式提供便于阅读、批注和按需修改。目前已有134人学习下载适合需要快速理解健康管理类小程序整体架构、梳理设计流程或撰写类似毕业设计论文的读者。1. springboot 健康管理小程序论文级的系统到底能不能直接跑作为一线工程师我经常遇到有人拿着一个毕设项目问我“这论文能跑吗”。这套基于 springboot 的健康管理微信小程序恰好是我拆过比较完整的一份后端是 Spring Boot前端是微信小程序业务覆盖用户注册登录、健康档案维护、每日健康数据记录、统计报告和健康提醒。它不是那种只有界面截图的空架子论文而是带真实代码和数据库访问逻辑的完整项目。如果你正在做毕业设计或者公司里需要快速搭一个健康数据采集的小程序这份资源能省掉从零设计表结构和接口的时间更关键的是你能从论文里把需求分析、业务流程抄到自己的设计文档中直接复用。适合理工科学生和刚转 Java 后端的开发者也适合想了解小程序登录闭环的老手快速过一遍。我下面会把拆包过程、核心实现和踩过的坑全部摊开照着走一遍你就能把系统跑起来。2. 业务拆分与数据模型用户、健康记录、报告表怎么设计才不返工2.1 为什么健康管理项目要把“用户”和“健康数据”分开建模很多健康类毕设项目翻车的第一个原因就是把所有字段塞进一张 user 表。血压、血糖、心率、体重全塞进去导致一张表几十个字段扩展一个指标就要改表结构。这套论文项目虽然原始但它的表设计是合理拆分的用户基础信息单独一张表体征记录按记录类型单独一张表周报月报靠统计查询而不是冗余存表。我一般照这套来改因为健康数据天生是时间序列必须用“用户 记录时间 指标类型”来定位。CREATE TABLE health_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL, record_type VARCHAR(32) NOT NULL COMMENT bp/glucose/weight/heart_rate, record_value DECIMAL(10,2) NOT NULL, measure_time DATETIME NOT NULL, remark VARCHAR(255), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_user_time (user_id, measure_time) );逻辑说明这个表把不同类型体征记录统一存起来record_type 表示血压、血糖、体重还是心率record_value 存数值再用 measure_time 记录测量时间。查询某用户某段时间的数据时走 idx_user_time 联合索引比在用户表里塞字段灵活得多。参数说明record_value 用 DECIMAL(10,2)能存到 99999999.99对健康数据完全够用record_type 用 VARCHAR 而不是 TINYINT是为了在小程序端直接展示可读值避免再做一次字典映射。如果你要支持血压的收缩压/舒张压两个值我建议拆出 detail 字段存 JSON或者加一条 child_record 表而不是修改 record_value 精度。2.2 用户表与登录凭证不要把 openid 当成唯一用户标识微信小程序登录的核心是 wx.login 拿到 code后端拿 code 向微信接口换 openid。很多项目偷懒直接把 openid 当主键但用户改了头像昵称、或者你要做管理员后台这套就难受了。这个项目里的结构是user 表自增 idopenid 做唯一索引另外存 nickname、avatar_url、phone 等扩展信息。健康记录全部用自增 id 关联这样以后要接会员体系或第三方登录都不用改业务表。CREATE TABLE user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, openid VARCHAR(64) NOT NULL, nickname VARCHAR(64), avatar_url VARCHAR(255), gender TINYINT, birth_date DATE, height_cm DECIMAL(5,2), weight_kg DECIMAL(5,2), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_openid (openid) );逻辑说明openid 只用来验证身份和创建用户业务数据都用 id 关联。birth_date、height、weight 这些基础档案放这里因为它们是“用户当前状态”不是时间序列数据。参数说明height_cm、weight_kg 用 DECIMAL(5,2) 最多存 999.99完全够OPENID 长度在 28 位左右VARCHAR(64) 留足余量。2.3 健康提醒与计划表状态机设计比定时任务更省事健康管理小程序除了记录数据一般都要提醒用户测量血压、喝水、吃药。这个项目的提醒表设计得比较典型plan 表存规则record 表存触发结果。我见过很多实现直接用一个定时任务扫全表用户量一上来就炸正确做法是把提醒做成“下次触发时间”字段轮询只查当前时间之前未触发的记录触发后更新下次时间。CREATE TABLE reminder_plan ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL, plan_type VARCHAR(32) NOT NULL COMMENT measure/medication/exercise, title VARCHAR(128) NOT NULL, cron_expr VARCHAR(64), next_run_at DATETIME NOT NULL, enabled TINYINT DEFAULT 1, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_next_run (enabled, next_run_at) );逻辑说明cron_expr 存“每天 08:00”这类规则next_run_at 是当前周期内下一次执行时间。定时器每五分钟执行一次“查 next_run_at 小于 now 且 enabled1 的记录”查到就发送模板消息然后把 next_run_at 按 cron_expr 更新为下一个时间点。这样不需要每秒扫全表。2.4 数据库脚本与初始数据先看 SQL 再启动我拿到这份资源后的第一件事就是把 SQL 脚本导入本地 MySQL然后逐个表核对字段。常见坑是论文里的 ER 图和实际 SQL 不一致这个包里的 SQL 是能对的上的。导入命令如下mysql -uroot -p health_mini sql/health_mini.sql逻辑说明health_mini.sql 通常包含了建库、建表和部分字典数据比如 record_type 的枚举说明。导入时要注意 MySQL 版本如果脚本用了 utf8mb4 而你的库是默认 latin1中文会乱码建议建库时指定字符集。参数说明-uroot -p 后面会提示输入密码health_mini 是我这边建的库名实际以你 SQL 脚本里的 CREATE DATABASE 为准。如果导入报错先打开脚本看开头的 COLLATE 与 ENGINE在 5.7 和 8.0 之间如果出现 default 语法差异手动替换掉再说。2.5 报表统计的 SQL 怎么写别再逐条记录 Count论文里的“健康报告”模块如果只是把列表数据搬出来那体现不了设计能力。正确做法是用聚合查询直接算均值、最大值、最小值而不是在后端循环里累加。下面的 SQL 能按天分组统计某类指标即使数据量到十万条也能快速响应。SELECT record_type, DATE(measure_time) AS d, AVG(record_value) AS avg_value, MAX(record_value) AS max_value FROM health_record WHERE user_id #{userId} AND record_type #{type} AND measure_time #{startTime} GROUP BY record_type, DATE(measure_time) ORDER BY d;逻辑说明DATE(measure_time) 把时间戳截断到日期group by 之后每条记录就是某天某指标的平均值。这样前端画折线图时不需要把原始记录全部拉过来只拿统计结果即可。注意这里没有把 endTime 条件写死由调用方传入避免漏查当天的数据。参数说明如果按小时统计把 DATE(measure_time) 换成 DATE_FORMAT(measure_time, %Y-%m-%d %H:00)但要注意时区问题数据库连接串没配 Asia/Shanghai 时结果会差八小时。另外AVG 函数会忽略 NULL如果某个测值为空统计出的平均值不代表全量数据建议在业务层强制要求 record_value 非空。3. 从配置到接口Spring Boot 后端与小程序前端的最小实现3.1 application.yml 里的三个关键配置这个项目后端是 Spring Boot主要配置数据库连接、MyBatis/JPA、微信小程序 appid 和 secret。我拆包时发现最容易配错的是小程序配置很多人把 appid 写成前端小程序的 appidsecret 写成开发环境密钥导致登录一直报 401。正确的配置方式如下server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/health_mini?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver wx: appid: wx1234567890abcdef secret: 你自己小程序的secret jwt: secret: health-mini-jwt-secret expire: 604800逻辑说明datasource 里的 serverTimezoneAsia/Shanghai 是很多同学忽略的MySQL 8.0 驱动默认时区与本地不同会导致时间字段偏移。jwt.secret 是签名密钥生产环境必须换成随机字符串不能直接用我这种示例。参数说明wx.appid 与 wx.secret 在微信公众平台的小程序管理后台获取appid 是公开的secret 是敏感信息不要提交到 Git。jwt.expire 单位是秒604800 是七天方便开发测试上线建议改成 259200030 天或配合 refresh token。如果你的项目里还用到 Redis可以在 spring 节点下加 redis 配置但不是必需。3.2 小程序登录接口code2session 的核心代码登录接口是整个小程序能不能跑通的关键。后端的 Controller 接收小程序传来的 code调微信接口换 openid再生成 JWT 返回给前端。核心逻辑如下RestController RequestMapping(/api/auth) public class AuthController { Autowired private WxService wxService; Autowired private UserService userService; Autowired private JwtUtil jwtUtil; PostMapping(/login) public Result login(RequestBody LoginRequest request) { String openid wxService.code2Session(request.getCode()); if (openid null) { return Result.error(code 无效或已过期); } User user userService.findOrCreateByOpenid(openid); String token jwtUtil.generateToken(user.getId(), user.getOpenid()); return Result.ok(token, user); } }逻辑说明LoginRequest 里只有 code 字段这是 wx.login 拿到的临时凭证。wxService 内部拼接 GET 请求https://api.weixin.qq.com/sns/jscode2session?appid...secret...js_code...grant_typeauthorization_code返回的 JSON 里有 openid 或 errcode。拿到 openid 后findOrCreateByOpenid 会先查库查不到就 new 一个默认用户。最后用 jwtUtil 生成 token前端后续请求都在 Header 里带这个 token。参数说明code 的有效期只有几分钟而且只能用一次如果同一个 code 被重复使用微信会返回 errcode 40029这类错误不要忽略前端必须重新走 wx.login。JwtUtil 是我这里封装的一个工具类核心就是 HS256 签名Claims 里放 userId 和 openid过期时间取自 jwt.expire 配置。3.3 记录健康数据的 POST 接口与参数校验健康记录接口是业务核心用户在小程序里填一个血压值前端请求后端保存。这个接口有两个容易翻车的地方一是参数校验不到位存了负数血压二是缺少归属校验用户 A 可以查用户 B 的记录。这个项目的代码里对第一点处理还可以第二点需要你亲手补上。PostMapping(/api/health/record) public Result addRecord(RequestBody HealthRecordDTO dto) { Long userId JwtUtil.getCurrentUserId(); if (userId null) { return Result.error(401, 未登录); } HealthRecord record new HealthRecord(); record.setUserId(userId); record.setRecordType(dto.getRecordType()); record.setRecordValue(dto.getRecordValue()); record.setMeasureTime(dto.getMeasureTime()); healthRecordMapper.insert(record); return Result.ok(record); }逻辑说明getCurrentUserId 是从 JWT 里解析出来的不是前端传 user_id这一步能防止横向越权。HealthRecordDTO 里 recordType 和 recordValue 是必填measureTime 不填就默认 LocalDateTime.now()。插入后返回完整记录前端可以拿 id 做后续的修改删除。参数说明登录拦截是写在拦截器或过滤器里的只有 /api/auth/** 和 /api/public/** 放行其余接口全部校验 Authorization Header。如果请求头不是 Bearer 开头拦截器直接返回 401解析失败返回 403。RecordType 后端还要再做一次白名单校验不能只靠前端下拉框因为 Postman 可以随意传值。3.4 小程序端 request 封装统一带 token 和处理 401小程序端的网络请求如果不做统一封装每个页面都写 wx.request 会很痛苦而且很容易漏掉 token。这个项目的 utils/request.js 是标准写法我一般也是直接抄这种const BASE_URL http://localhost:8080; function request(path, method, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL path, method: method, data: data, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) ? Bearer wx.getStorageSync(token) : }, success(res) { if (res.data.code 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/login/login }); reject(res.data); } else if (res.data.code 200) { resolve(res.data); } else { wx.showToast({ title: res.data.msg, icon: none }); reject(res.data); } }, fail(err) { wx.showToast({ title: 网络异常, icon: none }); reject(err); } }); }); } module.exports { request };逻辑说明request 函数把 wx.request 包成 Promise页面里可以这样用request(/api/health/record, POST, data).then(...)。Authorization 直接从本地存储取 token没有就不带。当后端返回 code 401 时说明 token 失效或未登录统一清掉 token 并跳转登录页避免每个页面都处理一次。参数说明BASE_URL 在开发时用本地局域网 IP真机调试时不能用 localhost要用电脑的局域网 IP比如http://192.168.1.5:8080并且要在微信开发者工具中勾选“不校验合法域名”。上线时 BASE_URL 必须换成备案过的 HTTPS 域名否则真机无法请求。3.5 小程序页面调用示例登录页和健康记录页光有请求封装还不够要在页面上真正调用。登录页面在 onLoad 里调 wx.login拿到 code 后传给后端健康记录页面在提交按钮点击后调 request。下面这段是登录页的核心onLoad() { wx.login({ success: (res) { if (res.code) { request(/api/auth/login, POST, { code: res.code }) .then((res) { wx.setStorageSync(token, res.data.token); wx.setStorageSync(userInfo, res.data.user); wx.switchTab({ url: /pages/index/index }); }); } } }); }逻辑说明wx.login 的 code 是临时凭证每次正好在登录前获取不能提前获取存起来因为五分钟就失效。拿到后端返回的 token 后存入本地存储下次启动小程序只要 token 没过期就不需要重新登录。如果 token 过期request 封装里的 401 跳转会重新触发 onLoad 里的 wx.login。参数说明wx.switchTab 只能跳转到 tabBar 页面如果你把首页配置成了 tabBar 就没事如果是普通页面要改成 wx.navigateTo。存储 token 用 wx.setStorageSync 即可不要用 cookie小程序环境不维护 cookie 机制。3.6 获取健康记录列表分页与时间过滤列表页不能一次查全部记录用户用两三个月后数据就能上万条不分页会非常卡。这个项目的列表接口应该至少支持 recordType、startTime、endTime、page、size 五个参数。后端写法如下GetMapping(/api/health/list) public Result list(RequestParam(required false) String type, RequestParam(required false) String startTime, RequestParam(required false) String endTime, RequestParam(defaultValue 1) int page, RequestParam(defaultValue 10) int size) { Long userId JwtUtil.getCurrentUserId(); PageResultHealthRecord result healthRecordService.queryPage( userId, type, startTime, endTime, page, size); return Result.ok(result); }逻辑说明userId 从 token 拿不传前端type、startTime、endTime 都是可选条件。page 和 size 本身有默认值防止空指针。PageResult 通常是包含 total、list、pageNum、pageSize 的对象前端可以根据 total 计算总页数。参数说明startTime 和 endTime 建议传yyyy-MM-dd HH:mm:ss格式的字符串在 Service 层用 DateTimeFormatter 解析解析失败时直接抛参数异常不要用空字符串判断。分页语句用 LIMIT #{offset}, #{size}offset (page-1) * size注意 page 从 1 开始。MyBatis 执行时如果 size 传 999 这种大值要加一个最大限制防止有人把全表拖出来。4. 常见坑排查登录、跨域、token 与数据同步的踩坑记录4.1 wx.login 的 code 拿去换了两次 openid第二次总是报 40029现象后端日志里出现 errcode 40029提示 invalid code前端用户点击登录始终进不来。第一次登录可以退出重进就失败。原因前端把 code 发了一次后端换完 openid 后前端又因为重复调用 wx.login 或把旧 code 存在全局变量里再次发送。微信官方明确规定 code 一次性有效哪怕 5 分钟没过期用过一次就失效。解决确认前端只在 onLoad 里调用一次 wx.login并且每次拿到新 code 后立即发送。不要在页面 onShow 里重复执行 wx.login除非你确定上次的 code 已经被消费。如果后端需要多次使用 code必须第一次就把它存到临时缓存并生成 token后续不再用 code。4.2 小程序请求 Spring Boot 接口一直 404/跨域真机比工具更严重现象开发者工具里点“不校验合法域名”能通但真机预览时请求直接 fail或者浏览器直接报 CORS 错误。原因真机环境要求请求地址必须是 HTTPS且域名要在小程序后台配置为 request 合法域名。开发者工具只是本地 mock不校验。Spring Boot 接口默认不开启跨域如果小程序端 BaseURL 是 http即使加了合法域名苹果和安卓也只会拦截。解决开发阶段用开发者工具关闭域名校验真机预览则必须满足两个条件后端接口用 HTTPS可用 Nginx 代理 SSL并且把备案域名配置到小程序管理后台的“开发管理-开发设置-服务器域名”。另外在 Spring Boot 里加一个全局 CORS 配置允许来自小程序请求源的跨域代码如下Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .maxAge(3600); } }逻辑说明allowedOrigins() 在开发环境方便线上如果不想放太开可以改成你的前端域名。allowedHeaders() 允许前端带 Authorization 请求头。小程序端对预检请求 OPTIONS 的处理比较特殊后端必须让 OPTIONS 通过否则真机请求会卡住。参数说明这段配置对 Spring Boot 2.4 以上版本有效如果是 Spring Boot 3.x需要把 WebMvcConfigurer 换成 WebMvcConfigurer 的包路径不同但方法一样。allowedOrigins(*) 时不能同时设置 allowCredentials(true)浏览器和安全策略会拒绝要特别注意。4.3 JWT 过期后 token 还在本地请求变成 401 死循环现象用户一周没打开小程序再打开时页面白屏请求一直失败即使跳转到登录页登录成功后还停在原页面不动。原因登录页 onLoad 从缓存读取 token发现存在就直接进首页但 token 已过期。首页的请求发出后返回 401request 封装里清掉 token 并跳转登录页登录页重新走 wx.login但登录成功后又跳回首页此时 token 是新 token理论应该正常。死循环通常是因为登录接口失败或者 JWT 解析时抛了异常、后端返回的不是 401 而是 500 导致的。解决在 JwtUtil 中先解析再判断过期时间如果解析失败或过期统一返回 401request 封装里 401 分支清掉 token 后同时调用wx.reLaunch({ url: /pages/login/login })用 reLaunch 清掉页面栈避免页面间互相跳转。还有一种保险做法在小程序启动时拉一个/api/auth/check接口验证 token无效就清缓存再引导登录。4.4 健康记录插入了负数数据库没有报错现象前端输入框用户可以输入 -10提交后后端竟然保存成功列表页出现一条离谱记录。原因后端 HealthRecordDTO 里的 recordValue 是 Double 类型没有加最小值和最大值校验。使用注解 Min/Max 或者手动 if 判断。解决在后端 DTO 上加 javax.validation 注解并在 Controller 方法参数前加 Validpublic class HealthRecordDTO { NotNull private String recordType; NotNull DecimalMin(value 0.0) DecimalMax(value 1000.0) private Double recordValue; PastOrPresent private LocalDateTime measureTime; }逻辑说明DecimalMin/DecimalMax 让 recordValue 被限制在 0 到 1000血压收缩压可能超过 200血糖一般不到 501000 的上限已经足够。measureTime 用 PastOrPresent禁止用户填未来时间。参数说明这里需要 spring-boot-starter-validation 依赖。如果项目里没有Controller 里的 Valid 不会生效只会静默通过一定要检查 pom 里有没有引入。另外前端 input 的 type 要设成 number 或 digit避免用户输字母。4.5 两张表的数据时间差了八小时现象小程序端显示的测量时间和数据库里的 create_time 差 8 小时早上的记录变成下午。原因MySQL 连接串没有加 serverTimezone 参数或后端 LocalDateTime 与数据库时区不一致。Spring Boot 默认 useSSLfalse 时连接串里的 serverTimezoneUTC导致存进去的时间比北京时间早 8 小时。解决把连接串改成 serverTimezoneAsia/Shanghai同时在 Spring Boot 的配置文件里设置spring.jackson.time-zone: Asia/Shanghai这样接口返回 JSON 时的时间也会正确。如果项目用了 MyBatis还要检查数据库连接池的初始化 SQL不要执行 SET time_zone 00:00。4.6 头像上传用 base64 塞进 JSON接口直接超时现象用户在小程序端选择头像后提交个人资料接口卡住十几秒甚至报“网络异常”。数据库里 user 表 avatar_url 字段变成了超长字符串。原因前端把图片用 canvas.toDataURL 转成 base64直接放 JSON 请求体传输。base64 比原图片体积多三分之一一张 2MB 照片传上去就是 2.7MB 文本加上数据库存储 TEXT 字段无论网络还是数据库都撑不住。解决改用 wx.uploadFile 走 multipart 表单上传后端用 MultipartFile 接收保存到本地磁盘或 OSS数据库只存文件 URL。核心前端代码如下wx.uploadFile({ url: BASE_URL /api/user/avatar, filePath: tempFilePath, name: file, header: { Authorization: Bearer wx.getStorageSync(token) }, success(res) { const data JSON.parse(res.data); if (data.code 200) { wx.setStorageSync(userInfo, data.data); } } });逻辑说明wx.uploadFile 会自动带上 multipart 请求体后端用 MultipartFile 接收。header 里照样要带 token。如果后端返回的 Content-Type 是 JSONres.data 是字符串需要先 JSON.parse 再拿 code。保存文件时不要用用户上传的原文件名要生成 UUID 后拼接后缀防止路径穿越和重名覆盖。参数说明后端接收文件时设置最大体积Spring Boot 里spring.servlet.multipart.max-file-size2MB超过直接拒绝。保存到本地的话要映射静态资源路径否则前端访问/upload/avatar/xxx.jpg会 404。保存到 OSS 就记得设置 Content-Type 和 MD5 校验。5. 跑通之后用 Swagger 验证接口、真机调试与健康趋势图进阶5.1 用 Swagger 快速验证登录与健康记录接口项目里如果引入了 springfox 或 springdoc启动后访问http://localhost:8080/swagger-ui.html就能看到接口文档。我习惯先调登录接口拿 token再在 Swagger 页面右上角全局添加 Authorization这样测健康记录接口就不会 401。如果项目里没有 Swagger也可以直接用 Postman但 Swagger 的优势是能看到 Controller 里的参数说明和返回结构方便你对照论文里的接口设计核验代码是否一致。springdoc: swagger-ui: path: /swagger-ui.html api-docs: path: /v3/api-docs逻辑说明springdoc 是 Spring Boot 3 常见的 Swagger 实现如果你的项目是 Boot 2用 springfox 的话配置项是springfox.documentation.swagger.v2.path。启动服务后接口列表里所有/api/**都是受保护接口需要先拿 token 才能测。参数说明Swagger 页面调试登录接口时返回的 data.token 字符串拷贝出来点击右上角 Authorize填Bearer token后面的请求就自动带上。这里要留意 Boot 3 项目有时候 swagger-ui 路径访问不到常见原因是静态资源被 Security 拦截放行/swagger-ui/**和/v3/api-docs/**即可。5.2 真机预览前要做的三件事小程序开发工具里模拟器正常不代表真机正常。我每次准备真机预览都会做一遍以下流程第一确认后端接口所在电脑和手机在同一个局域网或者后端已部署到云服务器第二把 request.js 里的 BASE_URL 从 localhost 改成局域网 IP 或正式域名第三在微信公众平台把该域名加进 request 合法域名。第三件事容易忘导致真机下拉刷新时接口全挂。# 后端启动命令注意开放端口 mvn spring-boot:run # 查看本机局域网 IP ipconfig # Windows ifconfig # Mac/Linux逻辑说明mvn spring-boot:run 是开发期最省事的启动方式不用先打 jar 包。启动后手机访问http://192.168.x.x:8080能通说明端口没被防火墙挡。如果通不了检查云服务器安全组或本机防火墙开放 8080 的入站规则。参数说明既然小程序是微信生态正式上线必须用 HTTPS。可以用 Nginx 做反向代理把https://api.example.com转发到本机 8080配置中要把proxy_set_header Host $host;写上避免 Spring Boot 拿不到正确的服务端信息。不配置的话某些微信接口的回调验签会失败。5.3 进阶在首页加一个健康趋势折线图论文的原始实现里数据可能只是列表展示但实际给导师或客户演示时一张折线图远比表格有说服力。我一般用 ec-canvasECharts 小程序版画近七天的体重或血糖趋势。页面数据从后端拿request(/api/health/trend?typeweightdays7, GET) .then((res) { const points res.data.map((item) { return [item.measureTime, item.recordValue]; }); chart.setOption({ xAxis: { type: time }, yAxis: { type: value }, series: [{ type: line, data: points }] }); });逻辑说明后端/api/health/trend按 days 天数查询该用户最近的健康记录返回的数组按时间升序。前端拿到数据后直接喂给 ECharts 的时间轴 series图表就会自动按时间分布显示点。这里 xAxis 用 type: timeECharts 会自动处理时间刻度比先格式化字符串再当 category 用要省事得多。参数说明ECharts 小程序版需要下载 ec-canvas 组件放到 components 目录页面 JSON 里注册组件后在 wxml 写ec-canvas idtrendChart canvas-idtrendChart ec{{ ec }}/ec-canvas。在 onReady 里用this.selectComponent(#trendChart)拿到实例否则图表会空白。这个坑我踩过一次图表区域只有灰色背景就是组件实例取早了。5.4 把提醒功能改成真正的订阅消息如果论文里只是“计划提醒”没有实际下发微信订阅消息那这项目还缺最后一公里。微信小程序早已不能主动给用户发消息必须让用户订阅一次才能在小程序订阅消息库里给你推送一次。这个项目里如果能补上 subscribeMessage 的实现答辩或验收就很有亮点。// 后端发送订阅消息示例 String accessToken wxService.getAccessToken(); String url https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token accessToken; JSONObject body new JSONObject(); body.put(touser, openid); body.put(template_id, 你的模板ID); body.put(page, pages/index/index); JSONObject data new JSONObject(); data.put(thing1, new JSONObject().put(value, 该测血压了)); body.put(data, data); // 使用 httpclient 发起 POST逻辑说明订阅消息发送前小程序端需要先调用wx.requestSubscribeMessage让用户点一次允许。后端发消息时要用 access_token而 access_token 有效期两小时不能每次都重新拉要缓存起来。这个环节最容易漏的是模板数据格式字段名必须和你在微信公众平台选的模板字段完全一致比如 thing1、time2 这种。参数说明模板关键词类型有严格限制比如“日期”必须用 time 类型“物品”必须用 thing 类型值长度也有要求。我曾经因为 thing 类型填了 30 个汉字直接被微信拒收返回 errcode 43101用户拒绝接收或 47003模板参数不匹配。建议先把模板 ID 和字段类型在后台复制好再对照代码里的 data map 检查一遍。5.5 上线前把接口和页面过一遍的清单每次我把项目跑通后都会强制自己走一遍完整清单避免上线翻车。第一用 Swagger 把所有接口都测一遍重点看没有参数的边界情况比如未登录、传负数、传空字符串。第二把 request.js 里的 BASE_URL 从局域网 IP 改成正式域名并确认小程序后台已经配置好 request 合法域名。第三在开发者工具里开启“不校验合法域名”关闭后再测一次真机预览确保所有请求都走 HTTPS。第四检查数据库里 user 表是否有重复 openid 记录如果出现重复说明你的 findOrCreateByOpenid 没有加事务控制。第五清理所有日志输出里的敏感信息小程序 secret 绝对不能打印到控制台。第六确认 register 组件没有把本地测试文件路径写死比如wx.setStorageSync(userInfo, res.data.user)里 res.data.user 如果为空下一次启动会直接崩溃。这六项不是浪费时间的表面工作。我见过太多项目在演示时突然白屏最后查出来是 token 失效后页面栈没有清空或者是因为上线前忘了把 BASE_URL 切到正式环境。从那以后我每次拆这种 springboot 微信小程序项目都会先跑通最小闭环登录 - 取 token - 提交一条健康记录 - 查询列表。只要这四个动作在一个小时内做完剩下的工作基本都是复制粘贴加参数调整。如果你现在也在跟这份论文和源码较劲建议按我上面的顺序先跑起来再改业务希望帮到你。本文还有配套的精品资源点击获取