news 2026/10/15 7:14:16

微信小程序+SpringBoot运动健康项目全流程开发复盘

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微信小程序+SpringBoot运动健康项目全流程开发复盘

前阵子刚把一个运动健康小程序完整跑通,从需求梳理、数据库设计、到后端接口实现和小程序端联调,前前后后踩了不少坑。整体技术栈用的是微信原生小程序 + SpringBoot + MyBatis-Plus + MySQL,后端提供 RESTful 接口,小程序负责页面展示和交互。这算是个人开发和课程设计里最稳的一套组合了,但真正动手做的时候,很多细节文档里根本不会写清楚——比如微信登录的 code 换 openid 要注意一次性问题、数据库时区会导致统计结果偏差、真机调试必须走 HTTPS 合法域名这些,都是实际跑一遍才能体会到的。

这篇文章就把这个项目的完整过程复盘一遍。我尽量按照真实开发的思路来讲,从为什么这么选型、表怎么设计、接口怎么写、小程序怎么对接,到最后的联调和部署坑点,全部展开。不管你是准备拿这个方向做课程设计,还是单纯想练习前后端分离项目的开发,这篇文章应该都能给你一个可以直接落地的参考框架。

1. 项目定位与选型:为什么是“小程序 + SpringBoot”的组合

1.1 先理清需求,这个项目到底要做什么

运动健康类的产品听起来很大,但作为个人开发项目,必须把边界划清楚。我一开始也想把步数接入、心率监测、社交打卡全塞进去,后来发现根本做不完。最后把核心圈定在四个模块上:

  • 用户体系:微信一键登录,自动注册,支持完善身高、体重、昵称、头像等个人资料。
  • 运动数据管理:用户手动记录跑步、步行、骑行等运动类型,填写时长和距离,系统自动估算消耗卡路里,并生成每日汇总和近7天趋势。
  • 健康档案:根据身高体重计算 BMI,生成健康等级和简单的运动建议。
  • 计划与打卡:用户可以创建运动计划,比如“每周跑步3次,持续4周”,每天运动后打卡,记录执行情况。

管理后台我只留了最基础的接口:用户列表、运动数据总览。因为核心价值在前端用户侧,管理端做得太复杂会挤占时间。这个需求边界很重要,越清晰的项目越容易在一个可控周期内完成,尤其是一个人要负责全部开发的情况下。

这里也要想清楚目标用户。我定的是一般的大学生和年轻上班族,他们的核心诉求很简单:记录自己今天的运动量,看看这周有没有坚持,顺便知道自己的体重状态。不需要专业运动员那种详细配速、心率区间分析,所以数据模型也不用设计得太复杂。

1.2 技术选型对比:为什么不用 uni-app,为什么不用云开发

技术选型这块我确实纠结过,先说结论:前端用微信原生小程序,后端用 SpringBoot 2.7 + MyBatis-Plus 3.5 + MySQL 8.0 + Maven。

为什么不用 uni-app?uni-app 确实是跨端利器,一套代码能编译到微信、H5、App。但这个项目只在微信小程序里跑,用 uni-app 反而多了一层框架概念要理解,而且遇到问题排查时,你得先分辨是框架的问题还是微信平台的问题。原生小程序虽然写起来偏啰嗦,但接口全是微信官方行为,遇到问题查文档最快,学习成本其实更低。

为什么不用云开发?如果纯粹是为了快速上线,微信云开发确实很香,云函数、云数据库、云存储一条龙。但这就绕开了后端这个核心学习目标。项目既然选 SpringBoot,就是要练接口设计、数据库建模、鉴权流程这套东西。用了云开发,这些能力完全锻炼不到。

为什么后端选 SpringBoot + MyBatis-Plus?SpringBoot 的生态成熟度不用多说,内置 Tomcat、自动配置、大量 starter,开发效率很高。MyBatis-Plus 则负责简化数据库操作,单表 CRUD 基本不用写 SQL,自带分页插件和逻辑删除,省下很多重复劳动。MySQL 8.0 是当前最普及的版本,资料多,出了问题好搜。

至于 Redis,我明确没有引入。单机项目、用户量很小的情况下,token 存数据库完全够用。Redis 的好处是缓存和分布式场景,对这个项目来说属于过度设计,还会增加部署和运维成本。以后确实需要再引入也不迟。

2. 数据库建模:运动健康类数据该怎样设计表

2.1 核心表结构:用户、运动记录、健康档案

数据库设计是整个项目的地基,表关系理不清楚,后面接口写起来全是麻烦。我最终保留了五张核心表,下面把最重要的三张展开讲。

用户表 user:

字段名类型说明
idBIGINT主键,自增
openidVARCHAR(64)微信用户唯一标识,唯一索引
nicknameVARCHAR(32)昵称,默认“微信用户”
avatar_urlVARCHAR(255)头像地址
genderTINYINT性别,0未知 1男 2女
heightDECIMAL(5,2)身高,单位 cm
weightDECIMAL(5,2)体重,单位 kg
create_timeDATETIME注册时间
update_timeDATETIME最后更新时间

运动记录表 sport_record:

字段名类型说明
idBIGINT主键
user_idBIGINT用户ID,逻辑外键
sport_typeTINYINT1跑步 2步行 3骑行 4其他
duration_minutesINT运动时长,单位分钟
distance_kmDECIMAL(6,2)运动距离,单位公里
caloriesINT估算消耗卡路里
record_dateDATE运动日期,业务日期
create_timeDATETIME记录创建时间

联合索引 idx_user_date:user_id + record_date。这个索引很重要,因为最常用的查询就是“某个用户某个日期范围的记录”,没有这个索引,数据量上来以后统计接口会变得很慢。

健康档案表 health_profile:

字段名类型说明
idBIGINT主键
user_idBIGINT用户ID
heightDECIMAL(5,2)本次档案身高
weightDECIMAL(5,2)本次档案体重
bmiDECIMAL(4,2)计算后的BMI值
health_levelVARCHAR(16)健康等级:偏瘦/正常/偏胖/肥胖
adviceVARCHAR(255)对应的运动建议
record_dateDATE记录日期

健康档案我按“快照”来设计,也就是说每次用户更新身高体重,都会生成一条新记录。这样做的原因是健康等级和建议会随体重变化,保留历史快照以后可以回看用户的体脂状态变化趋势,比只保留当前值更有分析价值。

2.2 计划与打卡表的设计思路

计划表 plan 和打卡表 plan_checkin 是另一个模块。计划表记录用户创建的健身计划,打卡表记录每天的执行情况。

plan 表的关键字段:id、user_id、plan_name、sport_type、target_days(计划总天数)、start_date、end_date、status(1进行中 2已完成 3已放弃)。

plan_checkin 表的关键字段:id、plan_id、user_id、check_date、duration_minutes、calories、create_time。这里必须加一个唯一索引 uk_plan_date,约束同一计划同一天只能打卡一次,防止前端重复提交导致同一天被记录两次。

为什么计划表和打卡表要分离?因为计划和打卡是一对多的关系,如果合并在一张表里,计划信息会在每次打卡时重复存储,数据冗余不说,后续修改计划的目标天数还要连带更新所有历史打卡记录。拆开以后,计划只有一条记录,打卡只是往子表里追加,逻辑清晰又省空间。

2.3 数据表之间的关系与数据流转

从用户进入小程序开始,数据流大概是这样的:

  1. 用户通过 wx.login 拿到临时 code,后端拿 code 向微信接口换取 openid。如果是新用户,自动在 user 表注册一条记录,然后生成 token 返回。
  2. 用户在运动页面添加一条运动记录,小程序把运动类型、时长、距离提交给后端,后端根据公式计算卡路里,写入 sport_record 表。
  3. 用户完善或修改身高体重,后端计算 BMI 和健康等级,写入 health_profile 表。
  4. 用户创建计划后,每天运动结束,调用打卡接口,写入 plan_checkin 表,并更新计划表的执行状态。

这个数据流其实非常简单,但每一步都有值得注意的设计点。比如计算卡路里不交给前端,而是后端统一算。为什么?因为同一套算法只能在后端维护,否则版本更新后老数据和新数据标准不一致,统计口径就乱了。

2.4 建表时的几个实践细节

实际建表时,我习惯在所有表里都加上 create_time 和 update_time 这两个字段,配合 MyBatis-Plus 的自动填充功能,省去每次手动 set 时间的操作。还有逻辑删除字段 deleted TINYINT,默认0,MyBatis-Plus 注解 @TableLogic 标注后,所有删除操作都自动变成 UPDATE。这样误删除还能恢复,对个人项目来说很重要。

日期字段我统一用 DATE 存业务日期,而不是 DATETIME。这个细节很关键:如果用户在 23:59 打卡,因为所在时区转换问题,DATETIME 存储的可能是第二天的时间,统计当天的运动记录就会出现跨天误差。把业务日期独立出来作为 record_date,查询时直接按这个字段过滤,就完全绕开了时区问题对业务的影响。

3. 后端接口实现:登录鉴权、运动记录与健康计算

3.1 登录鉴权完整流程:code 换 openid 与 token 方案

后端最核心的入口是登录接口。小程序端先调用 wx.login 获取临时 code,然后通过 wx.request 把 code 发给后端。后端拿到 code 后,调用微信官方的 jscode2session 接口,传 appid 和 secret 以及 code,换回 openid 和 session_key。

这个流程里有几个初学者容易犯的错误。

第一,code 只能用一次,有效期通常为5分钟。前端绝对不能把登录请求重发好几遍,否则第二次拿 code 去换就会报错。我在前端做了一个判断:同一时刻只允许一个登录请求在途,已经拿到 token 就不再重复发起。

第二,session_key 是敏感数据,千万不要返回给前端。微信官方文档也强调过,session_key 不能下发到客户端。我们自己的后端拿到 session_key 后,既不用也不能存,直接用 openid 去查用户表,然后发自己的 token 就行。

第三,token 用什么方案?我用的是 JWT。JWT 的好处是无状态,服务器不用存 session,认证拦截器拿密钥解析一下就能确认身份。JWT 里我只放了 userId 和过期时间,不塞多余数据。如果你需要“强制用户下线”或“吊销 token”的能力,那就要在数据库里维护一张 token 表,或者加 token 版本号字段。个人项目我建议先用 JWT 把流程跑通,能力上够用。

登录接口的代码大致是这样的:

@RestController @RequestMapping("/api/auth") public class AuthController { private final WxService wxService; private final UserService userService; private final TokenService tokenService; @PostMapping("/login") public Result<UserVO> login(@RequestBody LoginDTO dto) { String openid = wxService.code2Session(dto.getCode()); User user = userService.findByOpenid(openid); if (user == null) { user = userService.register(openid); } String token = tokenService.createToken(user.getId()); return Result.success(new UserVO(user, token)); } }

注册逻辑里,新用户默认昵称统一叫“微信用户”,头像给一个默认占位图。为什么不让用户一进来就授权昵称头像?因为从基础库2.21.2版本开始,获取用户昵称头像必须在用户主动点击按钮后触发,无法在页面加载时自动拉取。强制弹窗授权会让用户感到被打扰,不如先给默认信息,等用户有需要了再去个人中心完善。

3.2 鉴权拦截器与统一返回结构

除登录接口外,其他接口都必须校验 token。SpringBoot 里用 HandlerInterceptor 实现拦截最方便:

@Component public class AuthInterceptor implements HandlerInterceptor { private final TokenService tokenService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { String token = request.getHeader("Authorization"); Long userId = tokenService.parseToken(token); if (userId == null) { response.setStatus(401); return false; } request.setAttribute("userId", userId); } return true; } }

写完后在 WebMvcConfigurer 里注册,注意要 excludePathPatterns 排除登录接口和静态资源路径。

统一返回结构也是一个被很多人忽略的点。项目里所有接口统一返回如下格式:

public class Result<T> { private Integer code; // 业务状态码,200成功 private String message; // 提示信息 private T data; // 数据载荷 }

有人会觉得 SpringBoot 本身就有 HTTP 状态码,何必再包一层?原因在于 wx.request 只要网络层面收到了响应都会进 success 回调,新手容易在 fail 回调里处理业务错误,结果发现业务异常根本不会过来。统一返回结构之后,前端只判断 code 字段,401 表示未登录,500 表示业务异常,清爽很多。

3.3 运动记录添加与卡路里计算背后的公式

运动记录接口是数据核心,前端提交运动类型、运动时长、距离,卡路里由后端计算。这里我用了 MET 代谢当量的简化估算公式。

MET 是“代谢当量”,1 MET 相当于静坐时的能量消耗速度。不同运动强度对应不同 MET 值,常见取值是:步行 3.5,跑步 8,骑行 6,其他 4。卡路里计算公式为:

卡路里(kcal) = MET × 体重(kg) × 运动时间(h)

比如一个 65kg 的人跑步 30 分钟,计算就是 8 × 65 × 0.5 = 260 千卡。这个估算结果和健身App的数据会有偏差,因为没考虑个体差异、心率、坡度等因素,但作为个人记录已经够用了,而且公式来源可靠,比随便填一个数科学得多。

后端计算代码:

public Integer calcCalories(Integer sportType, BigDecimal weightKg, Integer minutes) { double met = getMet(sportType); double hours = minutes / 60.0; return (int) Math.round(met * weightKg.doubleValue() * hours); }

有一个细节:如果用户体重没填,默认按 60kg 计算,并在接口返回里带一个提醒字段,提示“请完善个人资料以获得更准确的卡路里估算”。这个小互动比默默计算更有温度,用户也愿意去完善资料。

3.4 统计接口:近7天趋势怎么写最清晰

统计接口是首页要用的。前端需要两种数据:当天的运动总时长和总卡路里,以及近7天的趋势。

当天汇总用 MyBatis-Plus 的 LambdaQueryWrapper 就能解决,条件就是 user_id 和 record_date,然后对 duration_minutes 和 calories 字段做聚合。但近7天趋势涉及分组和排序,用 LambdaQueryWrapper 写起来很别扭。我的做法是复杂统计直接写在 XML 里,自定义 SQL:

<select id="selectTrend" resultType="com.example.vo.TrendVO"> SELECT record_date, SUM(duration_minutes) AS totalMinutes, SUM(calories) AS totalCalories FROM sport_record WHERE user_id = #{userId} AND record_date BETWEEN #{startDate} AND #{endDate} GROUP BY record_date ORDER BY record_date </select>

MyBatis-Plus 解决 80% 的单表 CRUD,剩下 20% 的聚合统计交给 XML,这是团队开发中比较推荐的分工方式。拿到的结果如果某天没有记录,前端要把缺失日期补 0,否则折线图会断掉。这个补 0 逻辑我在前端做,后端只返回真实有的数据,职责更单一。

3.5 健康计算与建议规则的实现

BMI 的计算很简单:体重(kg) / 身高(m)的平方。算完以后对照区间生成健康等级和建议。要注意的是,这里给出的只是通用运动建议,不是医疗诊断,我在接口返回的 advice 后面加了“建议咨询专业人士”的提示文案,避免误导。

建议规则我写成一个静态方法,映射关系用枚举维护:

等级BMI 范围运动建议
偏瘦< 18.5适当增加力量训练,注意营养补充
正常18.5 ~ 23.9保持规律运动,每周至少150分钟中等强度运动
偏胖24.0 ~ 27.9控制饮食,增加有氧运动频率
肥胖>= 28.0建议循序渐进,初期选择快走、游泳等低冲击运动

用户每次修改身高体重都会生成一条 health_profile 记录,同时更新 user 表里的最新值。这样运动和健康档案两条线就打通了,后续扩展“体重变化曲线”功能时直接用历史快照数据就行。

4. 小程序端关键页面与前后端数据联动

4.1 页面目录结构与请求封装

小程序端我使用的是原生语法,目录结构很常规:

pages/ index/ 首页 sport/ 运动记录页 plan/ 计划页 profile/ 我的页 utils/ request.js wx.request 的 Promise 封装 auth.js token 的存取与校验

请求封装是所有页面的基础,我在 utils/request.js 里做了几个处理:自动读取存储中的 token 放到请求头、返回码为 401 时自动清除 token 并跳转到登录页面、统一在响应里解包 data 字段。这样每个页面调用接口时只需要关心业务数据,不用重复写异常处理逻辑。

4.2 首页数据展示与生命周期刷新策略

首页是整个小程序的门面,展示今日运动汇总、近7天趋势、健康等级和今日提醒。这里有一个我踩过的坑:刚开始数据请求写在了 onLoad 里,结果从运动页新增一条记录返回首页后,首页数据完全不刷新,因为 onLoad 只在页面初次加载时执行一次,之后页面从后台翻回来不会再触发。

正确的做法是用 onShow。每次页面显示都会执行,保证用户返回首页时能看到最新数据。但 onShow 每次触发都会发请求,如果网络慢会出现闪白。我的优化方案是:首次 onLoad 时显示 loading 动画,后续 onShow 静默刷新,先展示上一次的缓存数据,新数据回来后再覆盖。这样体验明显好很多。

4.3 趋势图组件:手绘 canvas 还是引入图表库

首页需要展示近7天运动时长的趋势图。要不要引入 echarts的小程序版,我犹豫了一阵。ec-canvas 确实好看,支持各种图表类型,但包体积较大,而且一个趋势折线图真没必要上这么重的库。

最后我决定用原生 canvas 2d 手绘折线图。数据点最多7个,坐标换算逻辑也就几十行。要注意的是新版 canvas 2d 接口和老版本不一样,必须通过 SelectorQuery 获取节点信息拿到 canvas 实例,绘制时使用节点实际的像素宽高,而不是直接写死宽度。如果还用旧的 wx.createCanvasContext 写法,在真机上会出现坐标错位甚至画不出来的情况。

手绘折线图的大致逻辑是:将日期数组映射到 x 轴坐标,将运动时长数组映射到 y 轴坐标,先画坐标轴网格,再用移动画笔的方式连接各点,最后在点上方标注数值。这个功能不复杂,但对理解 canvas 坐标系很有帮助。

4.4 运动记录表单:类型选择、校验与提交细节

运动记录页包括一个表单:运动类型 picker、时长输入框、距离输入框、提交按钮。这里有几个特别容易翻车的小细节。

第一,小程序里输入框 input 拿到的值永远是字符串。如果直接提交给后端,后端的 Integer 参数绑定很可能直接报 400。前端必须在提交前用 Number() 转换一次,并且做合法性校验:时长要大于0且为整数,距离要大于等于0,保留两位小数。

第二,运动类型我用数字枚举对应:1跑步、2步行、3骑行、4其他。前端展示文案,后端存数字。这种设计在数据库和接口传输上都很精简,但前端要维护一个类型映射表。

第三,提交成功不能只弹一个 toast 就完事,要带返回值跳转。我的处理是提交成功后 wx.navigateBack 返回上一页,同时通过上一页 onShow 里的刷新逻辑把列表更新掉。这样用户看到的是完整闭环:记录成功,列表里立刻多了一条数据。

4.5 登录态管理:静默登录与授权按钮的配合

登录态这块,我的最终设计是首次打开小程序就自动 wx.login 并调用后端登录接口,全程无感完成注册和登录。因为拿到 token 后,用户信息接口再根据 userId 查库,不需要用户主动授权啥。

但个人资料完善需要用户主动触发。个人中心页放了一个“编辑资料”按钮,用户点击后才弹出授权窗口获取昵称和头像。可能有人会觉得多了一步,但从数据收集角度看,自动注册能保住 100% 的进入用户,主动授权则只影响少数愿意完善资料的人,两边不冲突。

token 过期处理也要想好:JWT 过期时间是 7 天。如果前端收到 401,就清除本地 token 并自动重新走一遍静默登录流程,然后重放刚才失败的请求。这样用户几乎感知不到登录过期,不用没事就重新授权。

5. 联调部署与踩坑复盘

5.1 本地联调:开发者工具、局域网和真机的差异

开发阶段,我先把后端跑在本地 8080 端口,然后用微信开发者工具打开小程序前端。在开发者工具的“详情-本地设置”里勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”,模拟器里就能直接访问 http://localhost:8080 了。

但真机调试完全是另一个世界。手机上的微信小程序默认只允许访问小程序后台配置过的合法 HTTPS 域名,如果你只是在开发者工具里勾了不校验域名,真机一打开,所有请求全部被拦。想临时让手机真机也走本地服务,只能让手机和后端处在同一个局域网,然后把请求地址改成电脑的局域网 IP,不过即便如此真机依然会拦截 http 请求。

所以我的建议是:开发和功能验证阶段以开发者工具模拟器为主,把接口全调通;等要上真机测试时,后端已经部署到服务器,域名备案和 SSL 证书也配置好了,在小程序后台把 HTTPS 域名加入 request 合法域名列表,再重新编译体验版,真机就能正常访问。

5.2 MySQL 8.0 驱动、时区与日期格式的连环坑

联调期遇到最有代表性的问题就是数据库连接这一块。SpringBoot 2.7 的默认数据源是 HikariCP,MySQL 驱动类要从旧的 com.mysql.jdbc.Driver 换成 com.mysql.cj.jdbc.Driver。如果 URL 没指定 serverTimezone,MySQL 8 会直接报时区错误。正确配置如下:

spring: datasource: url: jdbc:mysql://localhost:3306/health?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver

时区问题不止影响连接,还影响日期展示。小程序端传 "2025-01-15" 这样的日期格式给后端,如果 DTO 字段是 java.util.Date 类型,默认格式化解析很容易失败。我在 DTO 里直接用 String 接收日期,然后在 Service 层用 LocalDate.parse 转成日期对象,彻底避开格式解析问题。配合数据库里的 record_date DATE 类型,统计查询稳定可靠。

另一个值得说的坑是 MySQL 默认时区跟本地不一致,导致查询当天数据时出现偏差。所以服务器上部署时,我不仅配置了连接串里的 serverTimezone,还在 MySQL 配置文件里把 default-time-zone 设置为 +08:00,双重保险。

5.3 部署上线:jar 包、Nginx 反向代理与小程序后台配置

部署流程我整理成了一套固定操作:

  1. 本机执行 mvn clean package -DskipTests 把后端打成 jar 包。
  2. 将 jar 包上传到云服务器,放在 /opt/app 目录下,用 systemd 配置守护进程,保证进程崩溃能自动重启。
  3. 域名解析到服务器 IP,配置免费 SSL 证书。
  4. 用 Nginx 做反向代理,把所有 /api 开头的请求转发到 127.0.0.1:8080。
  5. 在小程序管理后台,把 https://api.example.com 添加进 request 合法域名。

Nginx 的关键配置片段:

server { listen 443 ssl; server_name api.example.com; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

这套流程走完,后端就正式可用了。数据库备份我是用最简单的方式,每天凌晨用 cron 跑一次 mysqldump 生成 SQL 文件,保留最近30天。个人项目这个级别已经足够,不需要上专门的备份系统。

5.4 踩过的几个典型问题排查过程

问题一:登录接口间歇性报错。排查后确认是前端反复发送 wx.login 请求,第一个请求还没返回,第二个又带着新 code 来了,导致微信接口那边提示 code 已被使用。解决方案:在请求封装里加一个全局登录请求的 Promise 单例,同一个时间内只允许一个登录请求在途。

问题二:统计接口查询结果比实际数据少一天。定位到是 MySQL 会话时区跟 JVM 时区不一致,保存“今天”这个日期时两边算出的已经是不同日期。最终靠统一 serverTimezone 和 default-time-zone 解决。

问题三:小程序端偶尔收到 401 并且跳转空白页。原因是拦截器返回 401 后,前端立即清理 token 并跳转选择页面,但此时首页还有多个并发请求正在返回,出现了跳转覆盖和重复跳转。我的修复方案是加一个标记位 loginRedirecting,已经跳转过一次就不再重复跳转,等新 token 返回后再继续之前的请求。

问题四:HikariCP 默认最大连接数只有 10,模拟器、真机、管理端同时调试时会出现连接等待超时。调大最大连接数为 30,并设置了最小空闲连接数和连接超时时间,之后就没再出现。

5.5 这样的项目做完,下一步还能往哪里扩展

很多开发完第一个完整项目的人会陷入一个瓶颈:感觉会的东西已经全用上了,但离“工作中真正的系统”又差了一截。

这个项目其实留下了不少扩展点。比如权限可以引入 Spring Security 或 Sa-Token,把目前的简单拦截器换成完整的认证授权体系;运动数据可以增加按周、月的汇总报表;可以加入排行榜功能,让相同目标的用户互相激励;还可以接入对象存储,把用户头像、运动图片都托管到云端。

我不建议一上来就把这些全加上,而是选择一个对你最有价值的方向深入。比如如果目标是找后端开发相关工作,就把权限体系做深一点,弄懂过滤器链、角色继承、权限表达式这些;如果目标是做独立开发,就研究小程序分享裂变、订阅消息通知这类增长能力。

最后再分享一点个人心得。这类前后端分离的项目,最容易翻车的不是某个复杂算法,而是接口约定不一致。我自己调试时,因为日期字段类型和参数名对不上,浪费了大半天。如果一开始就把接口文档写清楚,联调会快很多。项目整体并不复杂,但把它完整走一遍,从数据库设计到后端接口再到小程序页面,整个链路都打通以后,再做其他项目会顺手非常多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 7:13:57

Spring Boot+Vue3在线考试系统实战:从架构设计到部署上线的完整经验

做在线考试系统这件事&#xff0c;我踩过的坑和攒下的经验&#xff0c;这次一次性说清楚。先说结论&#xff1a;前后端分离 Spring Boot Vue3 MyBatis MySQL&#xff0c;这套组合用来做在线远程考试系统&#xff0c;是目前中小型项目里最稳、性价比最高的选型之一。我前后参…

作者头像 李华
网站建设 2026/10/15 7:13:56

Selenium爬京东手机页实战:解决动态渲染与反爬绕过

1. 项目概述&#xff1a;为什么用Selenium爬京东手机页&#xff0c;而不是requestsBeautifulSoup&#xff1f;最近有好几个做电商数据分析的朋友在问&#xff1a;京东手机分类页的商品列表&#xff0c;明明F12能看到HTML结构&#xff0c;为什么用requests直接请求返回的页面里根…

作者头像 李华
网站建设 2026/10/15 7:13:49

高校校车调度管理系统开发实践与优化策略

1. 项目背景与核心价值校车调度管理系统是高校后勤管理数字化转型的关键环节。传统人工排班方式存在三大痛点&#xff1a;调度员需要手动处理Excel表格和纸质登记表&#xff0c;耗时且易出错&#xff1b;师生无法实时获取车辆位置和座位余量&#xff1b;管理部门缺乏数据支撑来…

作者头像 李华
网站建设 2026/10/15 7:13:43

GNSS广播星历与TLE轨道参数对比:从开普勒六要素到SGP4模型

2. GNSS卫星历书与星历的底层逻辑&#xff1a;广播星历为什么能"预报"轨道2.1 从开普勒轨道参数说起&#xff1a;六要素是理解历书的钥匙聊GNSS卫星轨道之前&#xff0c;先得把最基础的开普勒轨道六要素讲清楚。不管是GPS、北斗还是GLONASS&#xff0c;卫星绕地球运动…

作者头像 李华
网站建设 2026/10/15 7:13:12

基于Python的开放自习室座位预约系统:并发控制与状态机实战解析

先说个真实场景&#xff0c;我今年帮某高校的开放自习室做了一套基于Python的座位预约管理系统。那间自习室大概200个座位&#xff0c;考试季永远一座难求&#xff0c;平时却有大片空位&#xff0c;管理员每天要花大量时间清理“人不在、书在”的占座座位。折腾了大概三周&…

作者头像 李华
网站建设 2026/10/15 7:13:05

Tarjan算法详解:一次DFS求解强连通分量、割点与桥

遇到带环的图论问题&#xff0c;很多人第一反应是“跑一遍拓扑排序试试”&#xff0c;但拓扑排序只适合有向无环图&#xff0c;一旦图里出现强连通分量&#xff0c;结果立刻乱套。这时候就要请出 Tarjan 算法。Tarjan 是基于深度优先搜索&#xff08;DFS&#xff09;的图论算法…

作者头像 李华