十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

微信小程序与SSM实现个人日程管理全栈开发实践

微信小程序与SSM实现个人日程管理全栈开发实践 简介这是一份基于SSMSpring、SpringMVC、MyBatis框架开发的微信小程序个人日程安排系统完整源码包适合Java后端开发者、微信小程序初学者以及需要快速搭建日程管理工具的个人或团队参考。资源共1178个文件其中包含大量png、jpg图标素材js逻辑文件、wxml/wxss页面文件、java后端代码、vue后台管理页面、json配置以及sql数据库脚本整体约46.74MB从文件构成看既涵盖小程序前端展示层也包含基于SSM的接口服务与后台管理模块便于直接导入开发工具运行学习。目前已有119人浏览学习。代码结构完整包含可执行bat脚本、数据库初始化脚本和项目配置文件能够帮助开发者省去从零搭建环境的时间快速理解微信小程序与SSM后端交互、日程增删改查及提醒功能的实现思路适合用于毕业设计、课程项目或企业内部日程管理二次开发。1. 个人日程安排微信小程序与SSM从课程设计到可交付的完整链路看到这个标题第一反应是一个毕业设计压缩包但“微信小程序 SSM”这个组合放在个人日程管理上恰恰把前后端分离里最典型的场景全串起来了用户登录、增删改查、日期时间处理、状态流转、提醒触发。日程管理听起来只比“待办清单”复杂一点可一旦要考虑多用户隔离、按日视图查询、提醒授权、真机时区工程量就会迅速膨胀。这篇文章不依赖压缩包里任何源码直接给你一条可以照做的完整路径从数据库表设计、SSM 接口实现到小程序端登录、列表、编辑页面再到上线前的自测和导出技巧。适合正在做课设、毕设或者想从纯前端模板开发转全栈的工程师。2. SSM后端个人日程的数据库设计与接口实现2.1 从“日程”实体反推数据库表个人日程管理需要回答四个问题谁的事、什么事、什么时候、做完没有。所以数据库至少要两张表用户表负责认证日程表通过user_id关联用户。建表语句用 MySQL 方言字符集选 utf8mb4让备注文本可以正常存少量表情符号。CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, openid varchar(64) NOT NULL COMMENT 微信openid, nickname varchar(64) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE schedule ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL, title varchar(128) NOT NULL, content text, schedule_time datetime NOT NULL COMMENT 计划开始时间, remind_time datetime DEFAULT NULL COMMENT 提醒时间, status tinyint(4) DEFAULT 0 COMMENT 0-待办 1-已完成, category varchar(32) DEFAULT work COMMENT work/life/study, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_time (user_id, schedule_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;schedule_time和remind_time分开存因为提醒通常比计划时间早 10 或 30 分钟。status用 tinyint 映射为 Integer比 String 省空间。category用字符串而不是写死枚举后续加“学习”“健身”分类不用改表结构。联合索引idx_user_time服务高频查询某用户某一天的全部日程WHERE user_id ? AND schedule_time BETWEEN ? AND ?再按时间排序。在 SSM 环境里这两张表交给 MyBatis 映射。openid必须唯一同一个微信号不能注册两个账号。实际项目中 token 会话可以放 Redis个人项目直接放内存或数据库缓存都可以。2.2 SSM 三层架构Controller 只做转发Service 才写业务SSM 指 Spring SpringMVC MyBatis。常规分层是 Controller - Service - Mapper。个人日程的 Controller 不写业务判断只做参数绑定和返回统一结构。下面是一组典型接口。接口方法参数说明/schedule/listGETdate (yyyy-MM-dd)查询某天日程/schedulePOST日程 JSON新增日程/schedule/{id}PUT日程 JSON修改日程/schedule/{id}DELETE无删除日程/schedule/{id}/statusPUTstatus (0/1)切换完成状态Controller 层用RestController直接返回 JSON。代码示例RestController RequestMapping(/api/schedule) public class ScheduleController { Autowired private ScheduleService scheduleService; GetMapping(/list) public Result list(RequestParam String date, RequestAttribute(userId) Integer userId) { return Result.ok(scheduleService.listByDay(userId, date)); } PostMapping public Result create(RequestBody Schedule schedule, RequestAttribute(userId) Integer userId) { schedule.setUserId(userId); scheduleService.addSchedule(schedule); return Result.ok(); } PutMapping(/{id}) public Result update(PathVariable Integer id, RequestBody Schedule schedule) { schedule.setId(id); scheduleService.updateSchedule(schedule); return Result.ok(); } }注意RequestAttribute(userId)它由拦截器注入。拦截器从Authorization请求头中解析出 token再查出用户 ID 放到 request 属性里。Controller 不负责解析身份每个接口自然带上了当前用户也能避免用户越权操作。updateSchedule内部必须校验日程所属的user_id和当前 userId 一致否则 A 用户能改 B 用户的日程。Service 层加Transactional日程写入和日志写入保持原子性个人项目虽然事务粒度不大但习惯要养好。2.3 MyBatis 动态 SQL按日期查询和状态更新MyBatis 的 XML 映射文件写 SQL。列表查询要精确匹配某天但schedule_time是 datetime 类型所以需要把当天零点到次日零点作为查询区间。select idlistByDay resultTypecom.example.entity.Schedule SELECT * FROM schedule WHERE user_id #{userId} AND schedule_time gt; #{start} AND schedule_time lt; #{end} ORDER BY schedule_time ASC /selectXML 里大于号和小号必须转义这里的gt;和lt;分别对应和。start和end在 Service 通过LocalDate.parse(date).atStartOfDay()与.plusDays(1).atStartOfDay()计算。用而不是是为了避免把第二天的零点数据重复统计进当天。状态更新只改status字段直接写一条动态 update 就可以不要整条记录传回来。2.4 自测接口curl 与 Postman后端写完先用命令行工具自测不要等着小程序界面。最常用的两个 curl 命令# 登录把小程序传过来的 code 发给后端后端换 token curl -X POST http://localhost:8080/api/login \ -H Content-Type: application/json \ -d {code:wxCode123} # 查询当日日程Header 带 token curl -X GET http://localhost:8080/api/schedule/list?date2025-04-01 \ -H Authorization: Bearer your-token-here登录接口的标准做法是小程序端把wx.login()返回的 code 提交到后端后端拿 code 向微信服务端换取openid和session_key然后生成自己的 tokenUUID 或 JWT返回给前端。这就是“微信小程序用 code 换 token”的落地方式。token 有效期一般设 7 天前端启动时检查 token 不存在则重新登录。本地开发时给 SpringMVC 配置 CORS 允许任意来源但小程序真机请求不受浏览器跨域限制只有开发者工具需要勾选“不校验合法域名”。3. 微信小程序前端个人日程登录、列表、编辑页的实现3.1 全局配置与请求封装小程序端所有请求最好走统一出口后端地址一变不至于几十个页面逐个改。常见的做法是在app.js的globalData里维护baseUrl用request.js封装wx.request为 Promise。开发时baseUrl写成http://127.0.0.1:8080真机调试要改成电脑局域网 IP例如http://192.168.1.8:8080手机和电脑必须连同一个 Wi-Fi。// utils/request.js const request (url, method, data) { return new Promise((resolve, reject) { wx.request({ url: getApp().globalData.baseUrl url, method, data, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) || }, success: (res) { if (res.statusCode 200 res.statusCode 300) { resolve(res.data); } else if (res.statusCode 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/login/login }); reject(new Error(token expired)); } else { reject(new Error(res.data.msg || 请求失败)); } }, fail: (err) reject(err) }); }); }; module.exports { request };这段代码把 token 自动放进请求头调用方不需要在每个页面拼 header。成功时只返回data部分失败时按状态码分类处理。401 触发的自动跳转登录页很实用。若使用 JWTAuthorization的值可以自包含用户信息后端解析后放入请求属性。3.2 登录页面code 换 token 的最小实现登录页通常只放一个按钮点击后调用wx.login获取 code再发给后端换取 token。// pages/login/login.js Page({ async handleLogin() { try { const { code } await wx.login(); if (!code) return; const res await request(/api/login, POST, { code }); wx.setStorageSync(token, res.data.token); wx.setStorageSync(userId, res.data.userId); wx.switchTab({ url: /pages/index/index }); } catch (e) { wx.showToast({ title: 登录失败请重试, icon: none }); } } });这里必须加 try/catch因为wx.login成功不代表后端接口一定成功。request用相对路径切换线上域名时只改baseUrl一个文件。3.3 首页日程列表日期切换与长按操作首页用scroll-view做横向日期栏下方列表展示当天日程。长按日程项可以弹出编辑/删除菜单。下面是简化版结构!-- pages/index/index.wxml -- scroll-view classdate-bar scroll-x enable-flex view classdate-item wx:for{{weekList}} wx:keydate bindtaponPickDate >// pages/edit/edit.js Page({ data: { id: null, title: , category: work, date: 2025-04-01, time: 09:00, content: }, onSave() { if (!this.data.title.trim()) { wx.showToast({ title: 请填写标题, icon: none }); return; } const payload { title: this.data.title, category: this.data.category, scheduleTime: ${this.data.date} ${this.data.time}:00, content: this.data.content, remindTime: null }; const url this.data.id ? /api/schedule/${this.data.id} : /api/schedule; const method this.data.id ? PUT : POST; request(url, method, payload).then(() { wx.navigateBack(); }); } });表单校验先做非空判断实际项目可加长度限制和格式校验。模板字符串拼出的时间格式后端可以直接解析。分类选择器可以用radio-group实现“个人日程分类”的单选通常放工作/生活/学习三个选项。3.5 列表状态更新与局部刷新切换完成状态不需要重新拉列表调用状态接口成功后更新本地数组。这里有一个极端容易踩的坑this.data.scheduleList[index].status 1之后直接setData同一对象视图不会刷新。必须用新数组或路径更新// 正确示例 this.setData({ [scheduleList[${index}].status]: 1 });路径更新只改动一个节点性能更好代码也直观。索引要先通过列表数据计算出来或者用 map 生成新数组再 setData。别用“先改 data 再 setData 整个 data”的方式否则 diff 算法容易忽略深层对象变化。4. 提醒、状态同步与微信小程序日程管理的排查点4.1 用订阅消息实现日程提醒个人日程如果只靠用户打开小程序才看到提醒等于摆设。微信小程序提供订阅消息服务端可以推送通知到微信。前提是用户主动授权每次点击“开启提醒”时调用wx.requestSubscribeMessage订阅行为会被记录后端获得一次推送机会。注意每次推送消耗一次授权不是无限发。wx.requestSubscribeMessage({ tmplIds: [模板ID_1], success(res) { if (res.errMsg requestSubscribeMessage:ok) { request(/api/schedule/${scheduleId}/remind, POST, {}); } } });模板 ID 在微信公众平台小程序后台申请选择“日程提醒”类目。真机调试必须使用真实模板 ID开发者工具模拟器经常不弹授权框。后端收到提醒注册请求后把remind_time写入数据库再由定时任务或消息队列在指定时间调用订阅消息接口。个人项目用 Spring 的Scheduled每分钟扫描一次即可。4.2 状态同步与下拉刷新状态存在后端小程序端要保证数据新鲜。如果用户在多端操作上端改了状态下端还显示旧数据就需要下拉刷新。页面 json 配置enablePullDownRefresh: true然后在onPullDownRefresh回调里重新请求列表最后wx.stopPullDownRefresh()停止动画。个人项目不需要 WebSocket这种同步方案成本最低。4.3 长按拖拽排序的思路默认按schedule_time排序其实已经符合日程语义。如果老师要求展示“长按拖拽滚动”可以增加一个sort_order字段使用官方 sortable 组件基础库 2.12或 movable-view 手写。手写时要处理拖拽过程中的节流和防抖每次移动都向后端提交排序结果会造成大量请求。我的建议是个人日程不要做拖拽排序因为时间字段固定了拖拽后还要改写schedule_time逻辑复杂且容易造成数据冲突。4.4 三个值得警惕的坑第一个是时区问题。后端LocalDateTime序列化成 JSON 时若用默认时间戳格式小程序端收到的是1743469200000这种数字而不是2025-04-01 09:00:00。解决办法是在application.yml配置spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8第二个是setData的性能。官方单次 setData 数据量建议不超过 1MB列表更新尽量用路径写法比如setData({[scheduleList[ index ].status]: 1})。第三是scroll-view内嵌套textarea的层级问题textarea 是原生组件在低端机容易遮住列表。编辑页如果用多行备注建议单独用一个页面承载表单不要在滚动列表里直接弹textarea。5. 个人日程小程序上线前的自测清单与导出Excel技巧5.1 上线前的自测清单检测项操作方式通过标准接口功能Postman 跑通增删改查返回码 2xx数据正确越权访问用 A 用户的 token 请求 B 的日程被拦截或返回 403token 过期修改过期时间后调用接口返回 401前端跳登录日期边界查询 2025-03-31 和 2025-04-01数据不重不漏真机兼容微信开发者工具真机预览时间选择器正常scroll-view 流畅弱网开发者工具 Network 模拟慢速加载提示和超时处理正常自测时重点关注schedule_time的边界值跨月、跨年、夏令时区域用户的本地时间。如果面向国内用户统一GMT8即可。5.2 把个人日程导出为 Excel 的实用路径个人日程经常要导出到电脑端整理。常见做法是后端生成 Excel 文件小程序下载后用wx.openDocument打开。后端接口返回文件流GetMapping(/api/schedule/export) public ResponseEntitybyte[] export(RequestAttribute(userId) Integer userId) throws Exception { ListSchedule list scheduleService.listAll(userId); // 使用 Apache POI 生成 XSSFWorkbook写入标题行和数据行 byte[] bytes workbookToBytes(workbook); return ResponseEntity.ok() .header(Content-Disposition, attachment; filenameschedule.xlsx) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(bytes); }小程序端下载代码wx.downloadFile({ url: getApp().globalData.baseUrl /api/schedule/export, header: { Authorization: wx.getStorageSync(token) }, success(res) { wx.openDocument({ filePath: res.tempFilePath, fileType: xlsx, showMenu: true }); } });wx.downloadFile的临时文件只存在当前会话wx.openDocument支持在微信内预览。设置showMenu: true之后用户点右上角菜单还能发送给文件传输助手这就打通了手机和电脑的数据流转。导出接口建议加缓存因为同一用户频繁导出会压榨后端性能表格列头固定为“标题、分类、开始时间、提醒时间、状态、备注”状态可以转为“待办/已完成”可读文本。本文还有配套的精品资源点击获取
返回列表