简介:这份资源是面向Java与微信小程序方向的学生及开发者的一套完整项目实践包,以日常学习打卡系统为主题,适合用作毕业设计、课程设计或前后端协同开发的练手案例。项目采用Java后端配合微信小程序前端,并引入云开发能力,覆盖用户注册登录、学习计划创建与加入、每日打卡记录、数据统计展示等核心业务,同时涉及数据库表结构设计、需求分析与常见问题排查等工程环节。压缩包共71个文件,约840KB,以json配置、js脚本、wxss样式、wxml页面结构及png截图为主,另含docx与doc说明文档、mp4演示视频和txt环境说明,便于快速理解项目全貌与运行流程。目前已有509人学习下载。通过研读源码、说明文档与演示视频,读者可掌握小程序页面路由、数据绑定与网络请求,以及后端数据持久化和云开发的基本用法,并借鉴实际项目中的架构组织与问题解决思路。
1. 从一份 Java 毕设压缩包说起:日常学习打卡系统到底解决了谁的痛点
打开招聘软件搜 Java 后端岗位,十个候选人里有六个简历上写着「基于微信小程序的 XX 管理系统」,其中打卡类项目出现频率最高。但真正把这份「java项目之基于微信小程序的日常学习打卡系统(源码+说明文档+演示视频).zip」解压开、跑起来、改到能讲清楚每一行代码的人,其实没几个。多数人的操作是:下载、解压、IDEA 打开、报错、关掉、换下一个。这个标题背后真正值钱的东西,不是那几百行 CRUD,而是一套完整的「小程序端 + Java 服务端 + 数据库」的最小闭环,以及说明文档里那些容易被忽略的配置项。它适合三类人:正在找毕设题目的学生、想补一个全栈项目经验的初级 Java 工程师、以及需要快速搭一套打卡类业务原型的开发者。接下来的内容,我按自己跑这类项目的顺序,把环境、登录、打卡逻辑、数据表、部署和踩坑一次讲透。
2. 跑通之前先想清楚:这套打卡系统的技术选型与最小依赖
2.1 为什么是 Spring Boot + 微信小程序原生开发
拿到一个 Java 项目压缩包,第一件事不是双击打开,而是先看它的技术栈能不能在你机器上跑起来。这类打卡系统常见的组合是 Spring Boot 做后端、MyBatis 或 MyBatis-Plus 做持久层、MySQL 存数据、微信小程序原生框架做前端。为什么不是 SSM?因为 SSM 的 XML 配置对新手太劝退,而 Spring Boot 的 starter 机制能把 Tomcat、数据源、JSON 序列化全部自动装配,启动类跑起来就是一个独立服务。为什么不是 uni-app?因为原生小程序对wx.login、wx.getUserProfile这类 API 的调用最直接,调试时不用多一层编译,出问题容易定位。
选型确认之后,你要检查的是版本兼容性。这是最容易翻车的地方。Spring Boot 2.7.x 配 JDK 8 是稳的,Spring Boot 3.x 强制要求 JDK 17,而很多毕设项目的代码写的是javax.servlet包,升到 3.x 会直接编译不过。微信开发者工具这边,基础库版本建议锁在 2.30 以上,否则wx.getUserProfile的返回结构可能对不上。MySQL 用 5.7 或 8.0 都行,但 8.0 要改连接串里的时区和驱动类名。
2.2 从压缩包到能启动:环境检查清单
在导入 IDEA 之前,先把下面这张表过一遍。缺什么补什么,别等报错了再回头找。
| 依赖项 | 推荐版本 | 检查命令 | 常见问题 |
|---|---|---|---|
| JDK | 1.8 或 17 | java -version | 版本与 pom.xml 不一致 |
| Maven | 3.6+ | mvn -v | 本地仓库路径含中文 |
| MySQL | 5.7 / 8.0 | mysql --version | 8.0 需改驱动类名 |
| 微信开发者工具 | 稳定版 | 工具内关于页 | 未登录无法预览 |
| Node.js | 非必须 | node -v | 原生小程序不需要 |
检查完环境,导入项目。IDEA 里选择File -> Open,指向解压后的后端目录,等 Maven 依赖下载完。如果卡在某个依赖上,换阿里云镜像。依赖拉完后,找到application.yml或application.properties,把数据库连接改成你自己的:
spring: datasource: url: jdbc:mysql://localhost:3306/checkin_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver这段配置里三个参数最容易出问题。serverTimezone不写,MySQL 8.0 会报时区错误;characterEncoding不写,中文打卡备注会变问号;driver-class-name在 MySQL 5.7 下可以省略,但 8.0 必须显式写成com.mysql.cj.jdbc.Driver。改完配置,执行项目根目录下的 SQL 文件建库建表,然后运行启动类。控制台出现Started Application in x seconds就算后端通了。
2.3 小程序端的目录结构与编译配置
后端跑起来之后,打开微信开发者工具,导入小程序端目录。这里有个细节:project.config.json里的appid如果是测试号,部分接口会受限。你可以在开发者工具里点「测试号」自动生成一个,但要注意测试号不支持真机预览的某些能力。导入后看app.json,里面定义了页面路由和 tabBar。打卡系统一般有四个 tab:首页、打卡、记录、我的。如果编译报错说找不到某个页面,检查pages数组里的路径和实际文件夹是否一致,大小写敏感。
小程序端还有一个容易忽略的配置是request合法域名。开发阶段可以在开发者工具里勾选「不校验合法域名」,但上线前必须在微信公众平台配置服务器域名。本地调试时,后端地址写http://localhost:8080是通的,但真机预览时手机访问不到你的 localhost,需要换成局域网 IP,比如http://192.168.1.100:8080,并确保手机和电脑在同一网段。
3. 登录与打卡:把核心业务链路拆成可复现的代码
3.1 微信登录换取 openid 的完整流程
打卡系统的用户体系建立在微信登录之上。流程分四步:小程序端调用wx.login拿到临时code,把code发给后端,后端拿code加appid和secret去请求微信接口换openid和session_key,后端根据openid查库,没有就注册,有就返回自定义登录态。很多项目在这一步偷懒,直接把openid当 token 用,这是不安全的,但毕设项目里很常见。
小程序端代码:
// pages/login/login.js wx.login({ success: (res) => { if (res.code) { wx.request({ url: 'http://localhost:8080/api/user/login', method: 'POST', data: { code: res.code }, success: (resp) => { // 后端返回自定义 token,存入本地 wx.setStorageSync('token', resp.data.data.token); wx.setStorageSync('userId', resp.data.data.userId); } }); } } });后端接收code并请求微信接口:
// UserController.java @PostMapping("/login") public Result login(@RequestBody LoginDTO dto) { String url = "https://api.weixin.qq.com/sns/jscode2session" + "?appid=" + appid + "&secret=" + secret + "&js_code=" + dto.getCode() + "&grant_type=authorization_code"; // 用 RestTemplate 发起 GET 请求 String response = restTemplate.getForObject(url, String.class); JSONObject json = JSON.parseObject(response); String openid = json.getString("openid"); // 查库或注册,生成 token 返回 User user = userService.findOrCreateByOpenid(openid); String token = JwtUtil.generate(user.getId()); return Result.success(new LoginVO(token, user.getId())); }appid和secret写在配置文件里,不要硬编码在 Java 代码中。jscode2session接口返回的session_key不要下发给小程序端,它只应该留在服务端用于解密敏感数据。如果返回错误码40029,说明code无效或已过期,检查是不是重复使用了同一个code。如果返回45011,是频率限制,等几分钟再试。
3.2 打卡接口的参数设计与防重复逻辑
打卡是核心业务。一个合理的打卡接口需要接收用户 ID、打卡类型(早起、阅读、运动等)、打卡备注,并记录打卡时间。防重复是重点:同一个用户同一天同一类型只能打一次卡。实现方式有两种,一种是在 Java 层查一次再插入,另一种是在数据库层加唯一索引。推荐后者,因为并发下更可靠。
// CheckinController.java @PostMapping("/do") public Result doCheckin(@RequestBody CheckinDTO dto, @RequestHeader("token") String token) { Long userId = JwtUtil.getUserId(token); // 先查今天是否已打卡 Checkin exist = checkinService.getTodayCheckin(userId, dto.getType()); if (exist != null) { return Result.error("今天已经打过卡了"); } Checkin checkin = new Checkin(); checkin.setUserId(userId); checkin.setType(dto.getType()); checkin.setRemark(dto.getRemark()); checkin.setCheckinTime(LocalDateTime.now()); checkinService.save(checkin); return Result.success("打卡成功"); }对应的数据库唯一索引:
ALTER TABLE t_checkin ADD UNIQUE KEY uk_user_type_date (user_id, type, checkin_date);这里checkin_date是一个单独的日期字段,由后端在插入时赋值,而不是用checkin_time的日期部分。这样做的好处是索引更紧凑,查询更快。如果只靠 Java 层的if判断,两个请求同时进来会都查到 null,然后都插入,唯一索引就是最后一道防线。捕获DuplicateKeyException并返回友好提示,比让用户看到 500 错误要好。
3.3 打卡记录分页查询与前端列表加载
记录页需要分页。后端用 MyBatis-Plus 的Page对象,前端用scroll-view的bindscrolltolower触发加载更多。这里有个常见问题:分页参数从 1 开始还是从 0 开始。MyBatis-Plus 的Page当前页从 1 开始,而有些前端组件传的是偏移量。统一约定:前端传page和size,后端返回total和records。
// CheckinController.java @GetMapping("/list") public Result list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size, @RequestHeader("token") String token) { Long userId = JwtUtil.getUserId(token); Page<Checkin> pageParam = new Page<>(page, size); LambdaQueryWrapper<Checkin> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Checkin::getUserId, userId) .orderByDesc(Checkin::getCheckinTime); Page<Checkin> result = checkinService.page(pageParam, wrapper); return Result.success(result); }前端加载更多时,要维护一个hasMore标志,当返回的records长度小于size时置为 false,避免继续请求。另外,scroll-view需要固定高度才能触发scrolltolower,用height: 100vh或者计算后的高度。如果列表不滚动,先检查这个。
4. 避坑与排查:跑这类打卡项目最容易翻车的五个地方
4.1 现象:小程序请求后端报「不在以下 request 合法域名列表中」
原因:微信开发者工具默认校验请求域名,localhost和局域网 IP 都不在白名单里。解决:开发阶段在开发者工具右上角「详情」->「本地设置」里勾选「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」。上线前需要在微信公众平台「开发」->「开发设置」->「服务器域名」里配置request合法域名,且必须是 HTTPS。
4.2 现象:后端启动报「Access denied for user 'root'@'localhost'」
原因:数据库密码不对,或者 MySQL 8.0 的认证插件变了。解决:先确认application.yml里的密码和本机 MySQL 密码一致。如果 MySQL 是 8.0,且用mysql_native_password插件创建的用户,连接串里加allowPublicKeyRetrieval=true。或者直接改用户认证方式:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '新密码';。
4.3 现象:打卡记录时间比实际时间少 8 小时
原因:MySQL 时区配置和 JVM 时区不一致。解决:连接串里加serverTimezone=Asia/Shanghai,同时在启动类上或者配置文件里设置spring.jackson.time-zone=GMT+8。如果用的是LocalDateTime,还要确认 MySQL 字段类型是datetime而不是timestamp,timestamp会随时区转换。
4.4 现象:真机预览时接口请求失败,开发者工具里正常
原因:手机访问不到电脑的localhost。解决:把小程序端请求地址改成电脑的局域网 IP,比如http://192.168.1.100:8080,并确保手机和电脑连同一个 WiFi。Windows 防火墙可能拦截 8080 端口,临时关闭防火墙或添加入站规则。另外,微信开发者工具里要开启「不校验合法域名」,真机调试时这个设置不生效,需要在手机端开启调试模式。
4.5 现象:同一用户短时间内重复打卡成功
原因:Java 层查重和插入之间有并发窗口。解决:数据库加唯一索引,捕获DuplicateKeyException。代码里不要只靠if (exist != null),这个判断在高并发下不可靠。另外,前端按钮点击后要置灰,防止用户连点。虽然后端唯一索引能兜底,但前端防抖能减少无效请求。
5. 从能跑到能讲:把这份源码变成你自己的项目经验
跑通一个打卡项目只是起点,真正让你在面试或答辩里站得住脚的,是能说清楚「为什么这么设计」和「如果量大了怎么改」。我一般会做三件事来把别人的源码变成自己的东西。
第一,画一张数据流图。从wx.login开始,到code换openid,到 token 生成,到打卡请求携带 token,到后端解析 token 拿 userId,到查库插入,到返回结果。这张图能帮你回答「登录态怎么维持的」「token 过期怎么办」这类问题。token 过期可以加 Redis 存 token 并设 TTL,或者用 JWT 的exp字段,前端在request拦截器里统一处理 401。
第二,压测打卡接口。用 JMeter 或 Apache Bench 对/api/checkin/do发 100 个并发请求,看唯一索引是否生效、响应时间是否可接受。如果用的是if查重,你会看到重复插入或者大量异常。这个测试能让你在答辩时说出「我考虑了并发场景」。
第三,改一个功能。比如把打卡类型从固定枚举改成数据库配置,或者加一个打卡提醒的定时任务。改的过程中你会碰到@Scheduled的 cron 表达式、时区问题、以及如何避免多实例重复执行。这些细节比背八股文有用得多。
最后说一个我自己的习惯:每跑通一个别人的项目,我都会把application.yml和建表 SQL 单独存一份,标注清楚版本和改动点。下次再遇到类似项目,直接对比差异,能省掉大量排查时间。希望帮到你。
本文还有配套的精品资源,点击获取