news 2026/9/5 15:43:37

微信小程序+Spring Boot打造个人学习打卡系统:全栈开发实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微信小程序+Spring Boot打造个人学习打卡系统:全栈开发实战指南

简介:本资源是一个面向计算机专业学生与Java初学者的毕业设计/课程设计级实战项目,聚焦于微信小程序与Java后端协同开发的学习打卡系统,旨在帮助用户培养自律学习习惯并掌握前后端一体化开发流程。压缩包共71个文件,含12个JS逻辑文件(小程序页面交互)、9个WXML模板与11个WXSS样式文件(前端界面构建)、16个JSON配置及云函数定义、15张PNG界面截图与1个MP4演示视频(直观展示注册、打卡、统计等核心流程),以及需求文档、问题说明、数据库设计图和开发环境说明等关键教学材料,整体仅840KB,轻量易解压。已有503人学习下载,配套文档体系完整:从需求分析到云开发部署、从Spring Boot后端接口设计到小程序端数据绑定与API调用,再到常见问题排错思路,均覆盖详实;特别包含云开发版独立ZIP包,便于对比理解Serverless架构与传统Java后端的差异,是深入理解微信生态与Java工程实践的理想入门范例。

1. 项目概述与核心价值

最近几年,线上学习和自我管理成了很多人的刚需,尤其是学生和职场人士,总想找个趁手的工具来规划学习、记录进度。市面上的App要么功能太杂,要么收费不菲,要么就是数据不归自己管。正好,微信小程序以其“无需下载、即用即走”的特性,成了搭建轻量级应用的首选。所以,我决定动手做一个基于微信小程序的日常学习打卡系统,后端用Java来扛,前后端分离,把源码、说明文档和演示视频都打包好,方便有同样需求的朋友直接参考或者二次开发。

这个系统本质上是一个微型的个人学习管理工具。它的核心目标很明确:让用户能方便地在微信里创建学习计划,每天打卡记录,并直观地看到自己的学习轨迹和成果。别看功能听起来简单,但麻雀虽小五脏俱全,它涉及了微信小程序前端开发、Java后端服务、数据库设计、前后端通信(API接口)以及部署上线等一系列完整流程。对于想学习全栈开发,尤其是想切入微信小程序和Java Spring Boot技术栈的朋友来说,这是一个非常不错的练手项目,能帮你把知识点串起来,理解一个真实应用从零到一的构建过程。

2. 技术栈选型与架构设计思路

2.1 为什么选择这个技术组合?

做项目,技术选型是第一步,也是最关键的一步,它直接决定了开发效率和后期的可维护性。我选择“微信小程序 + Java Spring Boot + MySQL”这个经典组合,是基于以下几点考量:

前端(微信小程序):选择微信小程序而不是原生App或H5,核心原因在于其生态和用户体验。对于学习打卡这类低频、轻量级的工具型应用,让用户专门下载一个App的门槛太高了。微信小程序依托微信,用户基数庞大,传播和分享极其方便。它的开发框架(如WXML、WXSS、JavaScript)学习曲线相对平缓,且提供了丰富的原生组件和API(如用户登录、本地存储、云开发),能很好地满足我们的需求。更重要的是,小程序的审核和发布流程比App Store简单快速得多。

后端(Java Spring Boot):Java生态的成熟和稳定是毋庸置疑的。Spring Boot更是将这种优势发挥到了极致,它通过“约定大于配置”的理念,极大地简化了Spring应用的初始搭建和开发过程。对于这个打卡系统,我们需要处理用户认证、计划管理、打卡记录CRUD(增删改查)、简单的数据统计等业务逻辑。Spring Boot能快速集成MyBatis-Plus(数据访问)、Spring Security(安全,虽然本项目简化了)、Redis(缓存,可选)等组件,让开发者能专注于业务代码。此外,Java后端在性能、多线程处理以及后期如果需要扩展为更复杂的系统(比如加入社区功能)时,都有良好的基础。

数据库(MySQL):关系型数据库在数据一致性、复杂查询和事务支持方面有天然优势。学习打卡系统的数据结构非常清晰:用户、学习计划、每日打卡记录,它们之间存在明确的关系(如一个用户有多个计划,一个计划有多条记录)。MySQL作为最流行的开源关系型数据库之一,文档丰富、社区活跃,与Java Spring Boot的集成(通过JDBC或MyBatis)非常成熟。对于这个量级的项目,MySQL完全能够胜任,而且便于进行数据分析和导出。

整体架构:系统采用典型的前后端分离架构。微信小程序作为客户端,通过HTTPS请求调用部署在服务器上的Spring Boot后端提供的RESTful API。后端服务处理业务逻辑,并与MySQL数据库交互。这种架构清晰解耦,前端和后端可以独立开发和部署,也便于未来前端替换(比如增加一个管理后台网页)或后端服务化拆分。

2.2 核心功能模块设计

在动手写代码之前,先要把系统的功能边界和数据结构想清楚。我把整个系统拆解为以下几个核心模块:

  1. 用户模块:这是系统的入口。利用微信小程序的wx.login()wx.getUserProfile()(需用户授权)获取用户的openid和基本信息(如昵称、头像)。openid是微信用户的唯一标识,我们用它来关联系统内的用户数据。后端在用户首次登录时,将其信息存入user表。
  2. 学习计划模块:用户可以创建、查看、编辑、删除自己的学习计划。一个计划包含:计划名称(如“每日英语阅读”)、计划描述、每日目标(如“学习30分钟”)、计划开始日期、计划结束日期(可选)、计划状态(进行中/已暂停/已结束)等字段。这部分对应数据库的study_plan表。
  3. 打卡记录模块:这是系统的核心。用户每天针对某个计划进行打卡。打卡记录包含:关联的计划ID、打卡日期、实际完成内容或时长、打卡备注(如“今天学习了Unit 5”)、打卡状态(已完成/未完成/补卡)等。这里有一个关键设计点:是否允许补打卡?为了灵活性,我设计了允许用户在计划时间范围内补打之前日期的卡,但会在记录中标记为“补卡”。这部分对应checkin_record表。
  4. 数据统计与展示模块:用户需要直观的反馈。这个模块负责聚合数据,例如:显示当前连续打卡天数、本周/本月打卡日历(用不同颜色标记已打、未打、补打)、学习总时长趋势图等。这些数据通过后端API计算好后返回给前端渲染。

数据库的几张核心表之间通过外键关联,确保数据的完整性。user表是主表,study_plan表有user_id外键,checkin_record表有plan_iduser_id外键。

3. 开发环境搭建与项目初始化

3.1 后端(Spring Boot)环境准备

工欲善其事,必先利其器。后端开发我选择IntelliJ IDEA,它对Spring Boot的支持是最好的。

首先,通过 Spring Initializr 网站或IDEA内置的Spring Initializr来生成项目骨架。关键依赖选择如下:

  • Spring Web:用于构建RESTful API。
  • MyBatis FrameworkMyBatis-Plus:我强烈推荐MyBatis-Plus,它提供了强大的单表CRUD操作,能减少大量模板代码。
  • MySQL Driver:连接MySQL数据库。
  • Lombok:通过注解自动生成Getter/Setter等方法,让实体类代码更简洁。
  • Spring Boot DevTools:开发工具,支持热部署。

生成项目后,在application.ymlapplication.properties中配置数据库连接、服务器端口等。一个常见的配置示例如下:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/study_checkin_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 在控制台打印SQL语句,调试用 global-config: db-config: logic-delete-field: deleted # 全局逻辑删除字段名(如果要用) logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值

注意:数据库连接密码不要硬编码在配置文件中,尤其是在提交到Git等版本控制系统时。可以使用环境变量${DB_PASSWORD}或配置中心来管理。

接下来,创建对应的数据库和表。建议使用数据库版本管理工具如Flyway或Liquibase,但为了项目简单直观,这里先提供初始化的SQL脚本。

CREATE DATABASE IF NOT EXISTS `study_checkin_db` DEFAULT CHARACTER SET utf8mb4; USE `study_checkin_db`; -- 用户表 CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `openid` varchar(255) NOT NULL COMMENT '微信用户唯一标识', `nickname` varchar(255) DEFAULT NULL COMMENT '用户昵称', `avatar_url` varchar(500) DEFAULT NULL COMMENT '用户头像', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_openid` (`openid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -- 学习计划表 CREATE TABLE `study_plan` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `user_id` bigint(20) NOT NULL COMMENT '用户ID', `plan_name` varchar(100) NOT NULL COMMENT '计划名称', `description` varchar(500) DEFAULT NULL COMMENT '计划描述', `daily_target` varchar(200) DEFAULT NULL COMMENT '每日目标', `start_date` date NOT NULL COMMENT '开始日期', `end_date` date DEFAULT NULL COMMENT '结束日期', `status` tinyint(4) DEFAULT 1 COMMENT '状态:1-进行中,2-已暂停,3-已结束', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), KEY `idx_user_id` (`user_id`), CONSTRAINT `fk_plan_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学习计划表'; -- 打卡记录表 CREATE TABLE `checkin_record` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `user_id` bigint(20) NOT NULL COMMENT '用户ID', `plan_id` bigint(20) NOT NULL COMMENT '计划ID', `checkin_date` date NOT NULL COMMENT '打卡日期', `content` varchar(1000) DEFAULT NULL COMMENT '打卡内容', `duration` int(11) DEFAULT NULL COMMENT '学习时长(分钟)', `status` tinyint(4) DEFAULT 1 COMMENT '状态:1-正常打卡,2-补打卡', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_user_plan_date` (`user_id`, `plan_id`, `checkin_date`), -- 防止同一天对同一计划重复打卡 KEY `idx_user_id` (`user_id`), KEY `idx_plan_id` (`plan_id`), CONSTRAINT `fk_record_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE, CONSTRAINT `fk_record_plan` FOREIGN KEY (`plan_id`) REFERENCES `study_plan` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='打卡记录表';

3.2 前端(微信小程序)环境准备

前端开发使用微信官方提供的 微信开发者工具 。下载安装后,新建一个小程序项目。

  • AppID:如果你有已认证的小程序,可以填写;如果是个人学习,使用测试号即可。
  • 项目目录:选择一个空文件夹。
  • 模板:选择“不使用云服务”(本项目后端独立部署)。

项目创建后,你会看到一个标准的目录结构:

  • pages/:存放各个小程序页面,每个页面通常包含.js(逻辑)、.wxml(结构)、.wxss(样式)、.json(配置)四个文件。
  • app.js:小程序入口文件,定义全局逻辑。
  • app.json:小程序全局配置,包括页面路径、窗口样式、网络超时等。
  • app.wxss:全局样式。
  • project.config.json:项目配置文件。

首先,在app.jsonpages数组中注册我们需要的页面,例如:首页(计划列表)、计划详情/打卡页、我的页面、统计页面等。开发者工具会自动在pages目录下创建对应的文件夹和文件。

接下来,需要设计一个统一的后端API请求模块。在根目录下创建一个utils文件夹,里面新建一个http.jsapi.js文件,使用小程序的wx.request进行封装,统一处理请求基地址、请求头(如携带Token)、错误处理等。

// utils/http.js const BASE_URL = 'https://your-api-domain.com'; // 替换为你的后端服务地址 const request = (url, method, data) => { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + url, method: method, data: data, header: { 'content-type': 'application/json', 'Authorization': wx.getStorageSync('token') // 从本地存储获取登录令牌 }, success(res) { if (res.statusCode === 200) { // 假设后端统一返回格式为 { code: 200, data: ..., msg: 'success' } if (res.data.code === 200) { resolve(res.data.data); } else { // 业务逻辑错误,如未登录、参数错误等 wx.showToast({ title: res.data.msg, icon: 'none' }); reject(res.data); } } else { // HTTP状态码错误 wx.showToast({ title: `请求失败: ${res.statusCode}`, icon: 'none' }); reject(res); } }, fail(err) { wx.showToast({ title: '网络连接失败', icon: 'none' }); reject(err); } }); }); }; // 导出常用的方法 export const get = (url, data) => request(url, 'GET', data); export const post = (url, data) => request(url, 'POST', data); export const put = (url, data) => request(url, 'PUT', data); export const del = (url, data) => request(url, 'DELETE', data);

4. 核心功能实现与代码解析

4.1 用户登录与身份鉴权流程

这是小程序与后端交互的第一个关口,也是最容易出错的地方。微信小程序的登录流程和传统的账号密码登录不同。

前端(小程序端)流程:

  1. 调用wx.login()获取临时登录凭证code。这个code有效期很短(5分钟)。
  2. code发送到我们自己的后端服务器。
  3. 后端服务器用appidsecret和这个code,调用微信接口服务https://api.weixin.qq.com/sns/jscode2session,换取用户的openidsession_key
  4. 后端生成一个自定义的登录态标识(例如一个JWT Token),将openid等信息存入其中,并关联到我们数据库的user表(如果该openid不存在则创建新用户)。
  5. 后端将这个 Token 返回给小程序。
  6. 小程序将 Token 存储在本地(如wx.setStorageSync('token', token))。
  7. 后续所有需要身份验证的 API 请求,都在请求头中携带这个 Token(如Authorization: Bearer <token>)。

后端关键代码(Spring Boot Controller):

@RestController @RequestMapping("/api/auth") public class AuthController { @Autowired private UserService userService; @Autowired private JwtTokenProvider jwtTokenProvider; // 一个自定义的JWT工具类 @Value("${wechat.appid}") private String appid; @Value("${wechat.secret}") private String secret; @PostMapping("/login") public ApiResponse<String> login(@RequestBody LoginRequest request) { // 1. 用code调用微信接口 String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appid, secret, request.getCode()); // 使用RestTemplate或HttpClient发送请求 WechatSessionResponse wechatResp = restTemplate.getForObject(url, WechatSessionResponse.class); if (wechatResp == null || wechatResp.getOpenid() == null) { return ApiResponse.error("微信登录失败"); } String openid = wechatResp.getOpenid(); // 2. 根据openid查找或创建用户 User user = userService.findOrCreateByOpenid(openid, request.getNickname(), request.getAvatarUrl()); // 3. 生成JWT Token String token = jwtTokenProvider.generateToken(user.getId().toString(), user.getOpenid()); // 4. 返回Token给前端 return ApiResponse.success(token); } }

实操心得appidsecret是敏感信息,绝对不能写死在小程序前端代码里,必须从后端配置读取。后端调用微信接口时也要注意错误处理,比如code失效、网络超时等情况。另外,session_key不应该返回给前端,它在后端用于解密用户敏感信息(如手机号)时使用。

4.2 学习计划与打卡记录的CRUD实现

这部分是业务核心,使用MyBatis-Plus可以极大简化开发。

实体类(Entity)示例:

@Data @TableName("study_plan") public class StudyPlan { @TableId(type = IdType.AUTO) private Long id; private Long userId; private String planName; private String description; private String dailyTarget; private LocalDate startDate; private LocalDate endDate; private Integer status; //1进行中,2暂停,3结束 private LocalDateTime createTime; private LocalDateTime updateTime; }

Mapper接口:直接继承MyBatis-Plus的BaseMapper,基础的CRUD方法就有了。

public interface StudyPlanMapper extends BaseMapper<StudyPlan> { // 如果需要复杂查询,可以在这里定义方法,并在对应的XML中写SQL // 例如:查询用户某段时间内的所有计划 List<StudyPlan> selectPlansByUserAndDateRange(@Param("userId") Long userId, @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate); }

Service层:在Service中封装业务逻辑。例如,创建计划时要校验日期、结束日期不能早于开始日期等。

@Service public class StudyPlanServiceImpl extends ServiceImpl<StudyPlanMapper, StudyPlan> implements StudyPlanService { @Override public boolean createPlan(StudyPlan plan, Long userId) { // 业务校验 if (plan.getEndDate() != null && plan.getEndDate().isBefore(plan.getStartDate())) { throw new BusinessException("结束日期不能早于开始日期"); } plan.setUserId(userId); plan.setStatus(1); // 默认进行中 return this.save(plan); } @Override public Page<StudyPlan> getPlanPage(Page<StudyPlan> page, Long userId, Integer status) { LambdaQueryWrapper<StudyPlan> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StudyPlan::getUserId, userId); if (status != null) { wrapper.eq(StudyPlan::getStatus, status); } wrapper.orderByDesc(StudyPlan::getCreateTime); return this.page(page, wrapper); } }

Controller层:提供RESTful API接口,并利用Spring Security或自定义拦截器进行权限校验(确保用户只能操作自己的数据)。

@RestController @RequestMapping("/api/plan") public class StudyPlanController { @Autowired private StudyPlanService planService; @PostMapping public ApiResponse<Long> createPlan(@RequestBody StudyPlan plan, @CurrentUserId Long userId) { // @CurrentUserId 是自定义注解,从Token中解析出当前用户ID planService.createPlan(plan, userId); return ApiResponse.success(plan.getId()); } @GetMapping("/page") public ApiResponse<Page<StudyPlan>> getPlanPage(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) Integer status, @CurrentUserId Long userId) { Page<StudyPlan> page = new Page<>(pageNum, pageSize); Page<StudyPlan> result = planService.getPlanPage(page, userId, status); return ApiResponse.success(result); } }

打卡记录(CheckinRecord)的实现逻辑类似,但有一个关键点:打卡日期的唯一性约束。我们在数据库表设计中设置了UNIQUE KEY (user_id, plan_id, checkin_date),这意味着同一天对同一个计划只能打一次卡。在插入打卡记录前,需要先检查是否存在,如果存在则执行更新(比如修改打卡内容),否则插入新记录。这个逻辑应该在Service层实现。

4.3 数据统计与可视化接口设计

用户需要看到自己的努力成果,因此统计接口至关重要。这部分SQL会稍微复杂一些。

示例:获取用户当月的打卡日历

后端API需要接收年份和月份,返回一个数组,标记出当月每天是否有打卡(以及是正常打卡还是补卡)。

@GetMapping("/calendar/{year}/{month}") public ApiResponse<List<DayStatusVO>> getCheckinCalendar(@PathVariable Integer year, @PathVariable Integer month, @CurrentUserId Long userId) { List<DayStatusVO> calendar = checkinRecordService.getMonthCheckinStatus(userId, year, month); return ApiResponse.success(calendar); }

Service层和Mapper需要编写自定义SQL:

<!-- CheckinRecordMapper.xml --> <select id="selectCheckinStatusByMonth" resultType="com.yourproject.vo.DayStatusVO"> SELECT DATE(checkin_date) as date, COUNT(*) as count, MAX(status) as status -- 假设同一天只有一条记录,或者取一个代表状态 FROM checkin_record WHERE user_id = #{userId} AND YEAR(checkin_date) = #{year} AND MONTH(checkin_date) = #{month} GROUP BY DATE(checkin_date) </select>

这个查询会按天分组,返回当月有打卡记录的日期和状态。前端拿到这个列表后,就可以在日历组件上渲染,把有打卡的日期高亮显示。

连续打卡天数计算:这是一个经典的SQL问题。思路是:找到今天(或最近一天)的打卡记录,然后向前追溯,直到出现断档的那一天。可以使用变量或窗口函数来实现。一个相对简单的实现方式是:先查出用户所有打卡日期,排序后,在程序逻辑中计算最大连续天数。对于数据量不大的个人应用,这种方式是可以接受的。

// 在Service中实现逻辑计算 public int getCurrentStreak(Long userId) { List<LocalDate> dates = checkinRecordMapper.selectDistinctCheckinDates(userId); // 对dates排序(降序),然后遍历计算连续天数 // 如果今天没打卡,则从昨天开始算 // ... return streak; }

5. 前后端联调与部署上线

5.1 本地开发与联调技巧

前后端分离开发,联调是必经之路。有几点经验可以分享:

  1. 接口文档先行:在开发前期,前后端一起定义好API的路径、方法、请求参数、响应格式。可以使用Swagger(Springfox或Springdoc)来自动生成后端API文档,这样前端开发者可以随时查看和测试接口。在pom.xml中引入依赖,并在启动类加@EnableOpenApi注解即可。
  2. 解决跨域问题:本地开发时,小程序开发者工具请求localhost:8080会遇到跨域问题。有两种解决方法:一是在Spring Boot后端通过@CrossOrigin注解或配置WebMvcConfigurer来允许跨域;更推荐第二种:在微信开发者工具中,勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”。这样在开发阶段可以畅通无阻。
  3. 使用网络调试工具:除了微信开发者工具的Network面板,还可以使用抓包工具(如Charles、Fiddler)来查看详细的请求和响应数据,对于调试复杂接口非常有用。
  4. 模拟数据(Mock):在后端接口还没开发完时,前端可以利用小程序的本地模拟数据,或者使用一些Mock服务器来模拟接口返回,保证前端开发不阻塞。

5.2 服务器部署与HTTPS配置

开发完成后,需要将后端服务部署到公网服务器,小程序才能真机访问。

后端部署:

  1. 打包:使用Maven命令mvn clean package -DskipTests将Spring Boot项目打成可执行的JAR包。
  2. 服务器准备:购买一台云服务器(如阿里云ECS、腾讯云CVM),安装好Java运行环境(JRE 8或11)。
  3. 上传与运行:将JAR包上传到服务器。可以使用nohup java -jar your-app.jar &命令在后台运行。更推荐使用进程管理工具如systemdSupervisor来托管应用,实现开机自启和自动重启。
  4. 域名与Nginx:为你的服务器绑定一个域名。然后安装Nginx作为反向代理。Nginx负责处理HTTPS、静态文件,并将API请求转发给后端Spring Boot应用(默认运行在8080端口)。

一个简单的Nginx配置示例如下:

server { listen 443 ssl; server_name your-api-domain.com; # 你的域名 ssl_certificate /path/to/your/certificate.crt; ssl_certificate_key /path/to/your/private.key; location / { proxy_pass http://127.0.0.1:8080; # 转发到Spring Boot应用 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

重要提示:微信小程序要求后端接口必须使用HTTPS协议。你需要为你的域名申请SSL证书。各大云服务商都提供免费的SSL证书(如Let‘s Encrypt),申请后下载Nginx版本的证书,并按上述配置即可。

小程序配置:在小程序管理后台的“开发”->“开发设置”中,将你的后端API域名(如https://your-api-domain.com)添加到“服务器域名”的request合法域名列表中。否则,真机上将无法请求你的后端服务。

5.3 小程序提交审核与发布

  1. 代码上传:在微信开发者工具中点击“上传”,填写版本号和项目备注。
  2. 提交审核:登录小程序管理后台,在“版本管理”中找到上传的版本,提交审核。需要填写小程序信息、设置服务类目(教育-在线教育或工具-效率比较合适)、准备测试账号等。
  3. 审核与发布:等待微信审核(通常1-7天)。审核通过后,即可发布上线。你可以选择“全量发布”或“分阶段发布”。

6. 项目优化与常见问题排查

6.1 性能与体验优化点

项目基本跑通后,可以考虑以下优化来提升用户体验:

  1. 接口响应优化
    • 数据库索引:确保查询频繁的字段(如user_id,plan_id,checkin_date)上有索引。我们之前建表时已经加了一些。
    • SQL优化:避免SELECT *,只查询需要的字段。对于复杂的统计查询,考虑是否可以在业务低峰期预计算,将结果缓存起来。
    • 分页查询:列表接口(如计划列表、打卡历史)一定要支持分页,避免一次性加载过多数据。
  2. 缓存策略:对于一些不常变化但频繁读取的数据,如用户基本信息、计划的基本信息,可以引入Redis进行缓存。例如,用户登录后,将其信息缓存一段时间,减少数据库查询。
  3. 小程序端优化
    • 图片优化:用户头像等图片使用CDN并适当压缩。
    • 本地存储:将一些不敏感且不常变的数据(如枚举值、配置信息)存储在本地Storage中。
    • 请求合并与懒加载:首页加载时,避免同时发起多个并行请求,可以适当合并或使用Promise.all。列表页使用触底加载更多。
  4. 错误监控与日志:后端集成日志框架(如SLF4J+Logback),将错误日志记录到文件,并配置日志切割。可以考虑接入简单的应用性能监控(APM)工具。

6.2 开发与部署中的常见“坑”

  1. 微信登录失败code无效:最常见的原因是appidsecret配置错误,或者code被重复使用(前端每次调用wx.login都会刷新code)。确保后端用最新的code去请求微信接口。
  2. 真机无法请求后端接口:检查三点:1) 小程序后台是否配置了合法域名;2) 域名是否备案且支持HTTPS;3) Nginx配置是否正确,后端服务是否正常运行(curl https://your-api-domain.com/api/health测试)。
  3. 数据库连接超时或断开:在长时间不活动后,数据库连接池中的连接可能失效。需要在Spring Boot的数据库连接池配置(如HikariCP)中设置test-while-idlevalidation-query等参数来保活和验证连接。
  4. 时区问题:打卡日期涉及LocalDate,务必确保服务器、数据库和应用程序的时区一致(建议统一使用Asia/Shanghai)。在连接数据库的URL中指定serverTimezone=Asia/Shanghai,在Spring Boot启动命令或Docker环境中设置-Duser.timezone=GMT+08:00
  5. 小程序审核被拒:常见原因包括:类目选择不当、功能不完整(如只有登录没有内容)、存在测试数据、隐私协议不规范。提交前仔细阅读微信的审核规范,确保小程序有完整可用的功能,并准备好清晰的测试指引。

6.3 源码与文档说明

在提供的源码+说明文档+演示视频.zip压缩包中,你将会找到:

  • backend/:完整的Spring Boot后端项目源码,包含实体、Mapper、Service、Controller、配置等。
  • frontend/:微信小程序前端源码,包含所有页面、组件、工具函数和配置。
  • database/:包含数据库初始化SQL脚本。
  • docs/:详细的说明文档,包括环境搭建步骤、配置说明、接口文档、部署指南。
  • 演示视频.mp4:一个简短的屏幕录制视频,展示了小程序从登录、创建计划、打卡到查看统计的完整操作流程。

这个项目从构思到实现,涵盖了从技术选型、数据库设计、前后端编码、联调测试到部署上线的全流程。对于学习者而言,最大的价值不在于代码本身,而在于理解每个环节为什么这么做,以及遇到问题时如何排查和解决。希望这个项目和这些经验,能为你开启全栈开发之路提供一块扎实的垫脚石。

本文还有配套的精品资源,点击获取

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

OmniVoice 维吾尔语 TTS 完整部署指南

OmniVoice 维吾尔语 TTS 完整部署指南一、前言有一个本人非常不舒服的地方官方的图像界面有丑有慢&#xff0c;还不如直接命令行跑&#xff01;本文档旨在帮助用户在 Windows 10/11 系统上从零开始部署 OmniVoice 维吾尔语 TTS&#xff0c;实现批量语音合成。OmniVoice 是小米 …

作者头像 李华
网站建设 2026/9/5 15:41:11

Unity 图集底层揭秘:一张“拼图“如何拯救你的帧率

引子:一个让 GPU "累到崩溃"的午后 假设你在做一款 2D 卡牌游戏。界面上有 100 张卡牌,每张卡牌有独立的图片:card_001.png、card_002.png……你满心欢喜地把它们拖进场景,运行—— 帧率从 60 掉到了 20。手机开始发烫,风扇狂转(如果它有风扇的话)。 你百思…

作者头像 李华
网站建设 2026/9/5 15:40:42

Simulink储能模型合集:从锂电到燃料电池的多物理场仿真实践

简介&#xff1a;本资源是一套面向新能源汽车与储能系统研究者的动力电池及电化学储能器件Simulink建模仿真资料合集&#xff0c;覆盖锂离子电池、铅酸电池、燃料电池、超级电容器四大类核心能源部件的系统级建模方法。资源共70个文件&#xff0c;包含12个可直接运行的.slx模型…

作者头像 李华
网站建设 2026/9/5 15:38:56

移动App进度90%后的收尾清单:从边界补全到崩溃治理

今天在整理 Hermes Studio App 的每日开发进度时&#xff0c;我把整体完成度标记为 90%。这个数字看起来非常接近终点&#xff0c;但在移动端项目里&#xff0c;90% 往往是最容易产生误判的阶段&#xff1a;功能列表上的需求都开发完了&#xff0c;界面也能正常跑通&#xff0c…

作者头像 李华
网站建设 2026/9/5 15:37:32

C# USB HID上位机开发实战:从协议解析到工程化框架设计

简介&#xff1a;本资源是一套面向C#初学者与嵌入式USB开发者的USB HID通信上位机完整源码工程&#xff0c;聚焦于Windows平台下HID设备的数据收发实践&#xff0c;解决上位机与游戏手柄、自定义HID模块等免驱设备的稳定通信问题。压缩包共98个文件&#xff0c;含32个核心C#源码…

作者头像 李华