ARTICLE DETAIL

资讯详情

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

个人日程管理微信小程序与SSM后端开发实战全解析

个人日程管理微信小程序与SSM后端开发实战全解析 做个人日程管理这种小程序说难不难说简单也不简单。最近我把一个完整的“个人日程安排微信小程序 SSM后端”项目从数据库设计到接口对接再到小程序前端适配和发布流程整体梳理了一遍踩了不少坑也沉淀了不少可以直接抄作业的方案。如果你正准备做类似的毕业设计、课程设计或者单纯想给自己做一个轻量级的待办工具这篇文章应该能帮你少走几段弯路。这个项目说白了就是一个“日程规划管理工具”用户在小程序里登录后可以添加日程、设置开始时间和提醒时间、按分类管理待办事项、查看日程列表并按时间顺序展示。后端用 SSM 框架Spring SpringMVC MyBatis提供接口小程序负责交互和展示。它最核心的价值不是功能有多炫而是把“用户在微信里顺手记一条日程”这件事做顺畅同时让后端开发者能把 Java Web 的常规套路练一遍。适合的人群也比较明确正在做 Java 方向毕设的学生、想把 SSM 基础再梳理一遍的初级开发者以及想快速搭一套经典“小程序 后台管理”结构的同学。1. 项目整体设计与技术选型1.1 核心需求解读这个小程序到底在解决什么问题个人日程安排类应用的核心痛点其实就三个随手记录、到点提醒、快速查看。拿纸质本子和系统自带日历对比前者不便于搜索和分类后者功能太死板。而微信小程序的形态恰好解决了“安装门槛”的问题用户在微信里搜索就能打开不需要下载 App也没有注册流程的负担用微信登录就能直接建立自己的数据身份。从功能需求的角度拆解这个项目至少要包含这几块用户系统基于微信登录获取用户 openid建立用户身份记录用户昵称、头像、手机号等信息。日程管理支持新增日程、编辑日程、删除日程日程字段包含标题、内容、分类、开始时间、结束时间、提醒时间、完成状态。分类管理日程需要归属到某个分类比如工作、学习、生活、运动这样在列表展示时可以按分类筛选。日程列表与查看按时间倒序列出当前用户的日程支持按日期分组、按状态筛选、分页加载。提醒机制通过微信订阅消息在日程开始前给用户发提醒。为什么偏偏需要这五块因为它们正好构成一条完整的用户路径登录进入系统 → 添加一条日程 → 设置分类和提醒 → 在列表里看到这条日程 → 到点收到提醒 → 完成后标记状态。任何一块缺失产品都不闭环。1.2 技术选型解析为什么还是选 SSM 微信小程序先说框架选择。SSM 这三件套放到今天的企业项目里确实不算新潮Spring Boot 已经成了主流但放在毕业设计和课程设计场景里SSM 依然是一个非常稳妥的选择。原因是它的分层结构足够清晰Spring 管 Bean 和事务SpringMVC 管请求路由和参数绑定MyBatis 管数据库操作。这种“一个请求进来Controller 找 ServiceService 找 MapperMapper 操作数据库”的链路能非常直观地展示后端开发的基本功评审老师一看就知道你理解 Java Web 的经典架构。再说前端形态。微信小程序不是那个最复杂的方案但它是最贴近场景的方案。日程管理这种工具核心使用场景是“临时打开记一笔”小程序即点即用而且天然支持微信登录、订阅消息、手机号授权这些能力不需要自己搞短信验证码、也不需要单独做账号体系省掉了大量重复造轮子的工作。相比之下如果做成 H5 网页提醒功能就非常难做如果做成原生 App光安装和学习成本就劝退一批用户。1.3 功能模块拆分与页面逻辑从小程序前端角度看主要页面可以分成四个首页展示日程列表顶部有自定义导航栏下方按日期分组展示该天的日程支持下拉刷新和上拉加载。日历页可选以月历形式展示每天对应的日程数量点击某一天查看当日日程这个页面很能体现前端功底也是加分项。新增/编辑页一个表单页包含标题、内容、分类选择器、开始时间、结束时间、提醒时间、是否开启提醒等字段。我的页面展示用户昵称和头像显示当前用户下未完成日程的数量提供“一键清除已完成日程”等功能。后端按这个结构提供对应的 RESTful 接口前端每进入一个页面就请求一批数据。整体开发顺序先做后端再对前端这样能最有效地确认数据结构没问题。2. 数据库设计与核心表结构2.1 从需求反推表设计个人日程系统的数据量不大但它涉及用户、日程、分类三个实体关系也比较清晰。我习惯先从查询场景反推表结构用户打开小程序后最常用的操作是“查我今天的日程”和“查我的所有未完成日程”偶尔会做“按分类筛一下”。按照这个逻辑最核心的一张表就是日程表它必须能高效支持这两个查询。2.2 用户表、日程表、分类表的字段规划用户表t_user字段名类型说明idint主键自增openidvarchar(64)微信 openid唯一索引nicknamevarchar(32)用户昵称avatar_urlvarchar(255)用户头像地址phonevarchar(20)用户手机号create_timedatetime注册时间日程表t_schedule字段名类型说明idint主键自增user_idint所属用户 idtitlevarchar(128)日程标题contenttext日程内容描述category_idint所属分类 idstart_timedatetime开始时间end_timedatetime结束时间remind_timedatetime提醒时间statustinyint状态0未完成 1已完成create_timedatetime创建时间update_timedatetime更新时间分类表t_category字段名类型说明idint主键自增user_idint所属用户 idnamevarchar(32)分类名称icon_urlvarchar(255)分类图标colorvarchar(16)分类显示颜色这里有个很容易踩的坑分类表要不要加 user_id如果只做单用户的 demo有人会直接把分类写死在前端比如固定“工作、学习、生活”三个标签。但一旦用户多了之后每个人想要的分类都不一样合理的做法是每个用户看到自己创建的分类列表。2.3 核心查询索引设计与理由日程表最频繁的查询是SELECT * FROM t_schedule WHERE user_id #{userId} AND start_time BETWEEN #{begin} AND #{end} ORDER BY start_time;所以我在设计时给(user_id, start_time)建了一个联合索引。为什么不用两个单独索引因为 MySQL 底层执行时一般只会选择一个最优索引user_id单独索引虽然能快速定位到该用户的所有日程但还要再对时间做文件排序两个单列索引也往往被优化器合并成一个交集索引使用效果反而不如一个联合索引直接覆盖“按用户找再按时间排”的场景。2.4 时间字段的存储格式与前端对齐这一块我要单独说一下因为它是项目里最容易出 bug 的地方之一。数据库的datetime类型不带时区Java 后端实体类用Date接收JSON 序列化给前端时默认输出的是时间戳微信小程序端拿到的是数字时间戳需要手动new Date(timestamp)转换。最稳妥的做法是后端接口统一返回时间戳毫秒前端使用一个公共的工具函数做格式化。同时新建日程时前端表单里的时间选择结果也要先转成时间戳再提交给后端后端new Date(timestamp)后直接存入datetime字段。这样全程用时间戳传递就不会出现“前端显示的时间比数据库早 8 小时”的时区错位问题。3. SSM 后端实现要点3.1 工程分层与目录结构SSM 项目通常采用标准的 Maven 多模块或者单模块分层结构个人日程这种规模用单模块就够。核心包结构如下com.example.schedule ├── controller # 接口层接收前端请求 ├── service # 业务层处理业务逻辑 ├── mapper # 数据访问层接口 XML ├── pojo # 实体类和查询条件对象 ├── config # 配置类比如拦截器、跨域配置 └── util # 工具类比如 token 生成、时间格式化Controller 层只做三件事接收参数、调用 Service、包装返回结果。不要在 Controller 里写任何 SQL 逻辑。Service 层负责业务规则比如新增日程时校验时间合法性、删除日程时判断是否属于当前用户。Mapper 层就是 MyBatis 的接口和 XMLSQL 写在这里。3.2 统一返回结果类的设计前后端分离的项目接口返回格式必须统一否则前端每个请求都要单独处理各种情况。我习惯写一个通用的Result类public class ResultT { private Integer code; private String msg; private T data; public static T ResultT ok(T data) { ResultT result new Result(); result.setCode(200); result.setMsg(success); result.setData(data); return result; } public static T ResultT error(String msg) { ResultT result new Result(); result.setCode(500); result.setMsg(msg); return result; } }前端拿到响应后只需要判断code 200就取数据否则弹出错误消息。这个看起来简单的类能让前端逻辑变得干净很多。3.3 微信登录与 token 鉴权机制小程序登录整套流程是这样的前端调用wx.login()获取临时登录凭证code。后端拿到code后调用微信的接口GET https://api.weixin.qq.com/sns/jscode2session ?appid你的AppID secret你的AppSecret js_code{code} grant_typeauthorization_code微信返回openid和session_key。后端拿openid去查用户表如果不存在则创建新用户存在就直接返回旧信息。生成一个随机字符串作为token保存到user表或者单独的token表返回给前端。前端每次请求头里带上token后端通过一个拦截器统一校验登录状态。有一个必须注意的安全细节微信返回的session_key绝对不能返回给前端。它是一个敏感字段只在后端使用用于解密手机号等私密信息。如果把session_key暴露出去别人拿到后就能配合 intercepted 数据包解密用户信息这是安全事故级别的问题。3.4 手机号获取流程与常见失败原因获取手机号前端要用微信提供的特殊按钮方式不能直接自己调用接口去拿。按钮代码如下button open-typegetPhoneNumber bindgetphonenumbergetPhoneNumberHandler 获取手机号 /button用户点击后前端会通过e.detail拿到encryptedData、iv和code。注意新版小程序已经把手机号获取改成了code换手机号的方式把code传给后端后端调微信接口换取手机号。最早的老版本是后端拿session_key和iv解密encryptedData整个流程步骤多、还容易报 AES 解密错误。新版流程简单多了后端实现是// 用 code 换取手机号 WxMaPhoneNumberInfo phoneInfo wxMaService.getUserService().getNewPhoneNo(code);换回来的手机号直接存到用户表。这一块容易失败的原因大多是AppID 和 AppSecret 对不上、request 合法域名没配置到位、开发环境打开调试模式但基础库版本太低。按顺序排查问题基本能在五分钟内定位。3.5 日程 CRUD 接口设计后端接口按 RESTful 风格来设计不需要过度设计满足前端调用就行接口方法路径功能新增日程POST/api/schedule/add创建一条日程日程列表GET/api/schedule/list分页拉取日程日程详情GET/api/schedule/detail?id1查看单条日程更新日程POST/api/schedule/update编辑日程删除日程POST/api/schedule/delete删除日程完成日程POST/api/schedule/complete标记完成查询分页建议传入pageNum和pageSize后端用 MyBatis 的PageHelper插件或者手写LIMIT实现。手写 LIMIT 的 SQL 也不复杂select idselectList resultTypecom.example.schedule.pojo.Schedule SELECT * FROM t_schedule WHERE user_id #{userId} if teststatus ! null AND status #{status} /if ORDER BY start_time DESC LIMIT #{offset}, #{pageSize} /select3.6 定时提醒基于 Spring Task 与微信订阅消息“到点提醒”是整个项目里最绕的一个功能方案选择上要提前想清楚。小程序的定时器在页面切到后台后会停止不能依赖前端 setTimeout。真正可行的方案是后端定时扫描日程表找出即将开始的日程调用微信订阅消息接口发送提醒。后端实现思路如下配置定时任务每分钟执行一次Scheduled(cron 0 * * * * ?) public void checkScheduleRemind() { // 查询未来5分钟内需要提醒的日程 ListSchedule schedules scheduleMapper.selectNeedRemind(new Date(), DateUtil.addMinutes(new Date(), 5)); for (Schedule schedule : schedules) { sendSubscribeMessage(schedule); } }调微信的subscribeMessage.send接口前用户必须提前授权订阅过对应模板。小程序端在创建日程时如果勾选了“开启提醒”就弹出订阅授权wx.requestSubscribeMessage({ tmplIds: [模板ID], success(res) { // 用户点击允许后记录该用户已授权 } })后端存储用户对该模板的授权次数发送一次扣减一次。注意微信订阅消息是一次性的用户授权一次只能发一条如果用户创建的日程有 10 个提醒得引导用户连续订阅或者接受只能提醒一次的现状。这个部分我的建议是不要在设计上做太强的承诺明确告诉用户“每周最多订阅 3 次提醒”产品逻辑更现实也能避免发不出去被用户投诉。4. 微信小程序前端实现要点4.1 小程序工程目录结构与 app.json 配置小程序工程结构相对固定我习惯这么组织miniprogram/ ├── app.js # 入口文件初始化全局数据和登录逻辑 ├── app.json # 全局配置页面路由、窗口样式、tabBar ├── app.wxss # 全局样式 ├── pages/ │ ├── index/ # 首页日程列表 │ ├── add/ # 新增/编辑日程 │ ├── calendar/ # 日历月视图 │ └── mine/ # 我的页面 ├── utils/ │ ├── request.js # wx.request 封装 │ └── util.js # 时间格式化、日期计算 ├── static/ # 静态资源 └── components/ # 自定义组件在app.json里如果底部导航只有两个 tab可以配置 tabBar。通常首页和“我的”作为 tabBar 页面新增日程不放在 tabBar 里而是通过加号按钮跳转这样交互更自然。4.2 顶部导航栏高度计算的正确姿势“小程序顶部导航栏高度”是实操里特别容易出问题的地方尤其是自定义导航栏的时候。如果不自定义默认导航栏由微信统一渲染标题居中无需操心。但很多日程类页面希望导航栏颜色能跟着页面风格走这时就要用自定义导航栏模式在 app.json 中把页面navigationStyle设为custom。自定义之后导航栏可用高度需要手动计算。靠谱的计算公式是const systemInfo wx.getSystemInfoSync() const menuButtonInfo wx.getMenuButtonBoundingClientRect() // 状态栏高度 const statusBarHeight systemInfo.statusBarHeight // 导航栏高度 (胶囊上边界 - 状态栏高度) * 2 胶囊高度 const navBarHeight (menuButtonInfo.top - statusBarHeight) * 2 menuButtonInfo.height // 导航栏上下 padding胶囊上边界 - 状态栏高度 const navBarPaddingTop menuButtonInfo.top - statusBarHeight这里为什么是(胶囊上边界 - 状态栏高度) * 2原因是微信把胶囊放在了导航栏垂直居中的位置胶囊上边到状态栏底部的距离约等于导航栏总高度的一半用这个差值乘 2 再加上胶囊高度就是完整导航栏高度。拿到这些值后页面里为自定义导航栏占位给内容区域留出statusBarHeight navBarHeight的padding-top。4.3 首页日程列表按日期分组与时间线首页设计成时间线形式按日期分组。接口返回的是一整列待办日程前端拿到后用util.js里的groupByDate函数按start_time的日期部分分组function groupByDate(scheduleList) { const groups {} scheduleList.forEach(item { const dateStr formatDate(item.startTime) if (!groups[dateStr]) { groups[dateStr] [] } groups[dateStr].push(item) }) return Object.keys(groups).sort().reverse().map(date ({ date, list: groups[date] })) }渲染时外层wx:for遍历日期分组内层wx:for遍历当天日程每个日程卡片显示标题、时间、分类标签带颜色、完成状态。点卡片右侧的复选框可以快速把日程标记为已完成已完成的卡片置灰并显示删除线。这个交互虽然简单却是日程管理类 App 最常用的原型。4.4 日历视图的实现思路日历月视图算是一个不错的加分项但不必上第三方组件手写一版也不复杂。核心难点是计算某个月的天数和第一天的星期几function getMonthDays(year, month) { // month 从 0 开始计数 return new Date(year, month 1, 0).getDate() } function getFirstDayWeek(year, month) { return new Date(year, month, 1).getDay() }拿到这两个值之后渲染一个 6 行 7 列的网格。月份相同时显示日程标记点点击某一天时切换下方列表下方列表直接复用首页的日程卡片逻辑。这样写出来的日历页既能体现逻辑能力也能让项目截图更丰富。4.5 wx.request 的 Promise 封装与 token 注入小程序自带的wx.request是回调风格的用起来很啰嗦。我通常在utils/request.js里封装成 Promisefunction request(url, method, data) { return new Promise((resolve, reject) { wx.request({ url: getApp().globalData.baseUrl url, method: method || GET, data: data || {}, header: { Content-Type: application/json, token: wx.getStorageSync(token) }, success: (res) { if (res.data.code 200) { resolve(res.data.data) } else if (res.data.code 401) { // 登录过期跳转登录页 wx.navigateTo({ url: /pages/login/login }) reject(res.data) } else { wx.showToast({ title: res.data.msg, icon: none }) reject(res.data) } }, fail: (err) reject(err) }) }) } module.exports { get: (url, data) request(url, GET, data), post: (url, data) request(url, POST, data) }封装的核心价值就一个其他地方只管await request.get(/api/schedule/list, {...})拿到数据不需要重复处理 token、错误提示、登录过期这三件事。4.6 日期时间选择器的使用与默认值处理新增日程页的表单里标题、内容、分类都好处理最麻烦的是时间选择。小程序的picker组件分为 modedate和time两种模式分开用picker modedate value{{startDate}} bindchangeonStartDateChange view{{startDate || 请选择日期}}/view /picker picker modetime value{{startTime}} bindchangeonStartTimeChange view{{startTime || 请选择时间}}/view /picker这里很容易踩的坑是date模式返回的是一个YYYY-MM-DD字符串time模式返回HH:mm字符串提交给后端时得先把这两个字符串拼成YYYY-MM-DD HH:mm:ss再转成时间戳。我写了一段拼接逻辑const fullTime ${this.data.startDate} ${this.data.startTime}:00 const timestamp new Date(fullTime.replace(/-/g, /)).getTime()注意这里用replace(/-/g, /)转成斜杠格式再 new Date否则 iOS 上解析YYYY-MM-DD HH:mm:ss会返回Invalid Date。iOS 对日期字符串的解析比安卓严格这是个经典兼容性坑。4.7 单选框、图片上传与授权处理分类选择我建议直接用单选框实现简单直接。小程序里单选框用radio-group包裹一组radio遍历分类列表渲染即可。要注意的是 radio 的value属性在bindchange事件里取出来的是字符串提交时要转成数字再传给后端const categoryId parseInt(e.detail.value, 10)头像上传则使用wx.chooseMedia选择后wx.uploadFile传给后端。上传接口要求后端能接收 multipart 文件SSM 项目里用 CommonsMultipartResolver 配置一下就能支持。如果只是个人日程工具头像也可以直接用微信默认头像不必单独实现上传逻辑减少工作量。4.8 “我的”页面用户信息展示与取消订阅“我的”页面负责展示微信登录用户信息包括头像、昵称、手机号以及一些简单的统计信息比如“本周已完成”“待办数量”。如果用户允许获取手机号则在用户信息下方展示手机号没有授权就显示“获取手机号”按钮点击后走上面说的getPhoneNumber逻辑。这个页面还有个容易忽略的交互用户在小程序设置里关闭了订阅消息授权前端可以引导用户点击“重新开启”做法是wx.openSetting({ success: (res) { if (res.authSetting[scope.subscribeMessage]) { // 已打开授权 } } })5. 常见问题与排查技巧实录5.1 请求域名未配置导致 request fail小程序开发环境默认可以勾选“不校验合法域名”但真机预览或体验版上这个选项不生效。第一次发布体验版时最常见的报错就是request:fail url not in domain list。解决方式是在微信公众平台后台的“开发管理 - 开发设置 - 服务器域名”中配置request合法域名。域名必须是 HTTPS且已备案。如果只是自己调试可以先在开发者工具右上角“详情 - 本地设置”勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”本地能跑通但要记住上线之前一定要配置真实域名。5.2 后端接口跨域问题小程序请求不存在浏览器同源策略的问题但如果你在 PC 浏览器调试接口或后端有独立的 web 管理端就会遇到 CORS。SSM 后端配置一个简单的拦截器加响应头response.setHeader(Access-Control-Allow-Origin, *); response.setHeader(Access-Control-Allow-Methods, GET, POST, PUT, DELETE); response.setHeader(Access-Control-Allow-Headers, Content-Type, token);如果是 SpringMVC 4.2 以上版本可以直接在 Controller 类上标注CrossOrigin但注意它不能替代全局拦截器对 OPTIONS 预检请求的处理。在配置 WebMvcConfigurer 时重写addCorsMappings是最干净的方式。5.3 登录态过期与 token 失效前端保存 token后端拦截器在每个请求前校验 token。如果 token 已经过期返回code: 401。前端统一在 request 封装里处理清掉本地 token跳转登录页让用户重新登录。有两个注意点一是登录页不要设计成“点击登录”小程序登录应该是静默的用户打开就自动 wx.login 换 token不要给用户制造障碍二是 token 失效后要跳转到一个透明的中转页重新登录再返回原页面避免点击列表时被强制踢到登录页打断操作。5.4 时间显示相差 8 小时这个坑在前期反复出现把排查思路记在这里。如果你的 MySQL 数据库连接串里设置了serverTimezoneAsia/ShanghaiJava 的 Data 对象输出的 JSON 却是 UTC 时间戳前端 new Date 之后显示的是北京时间本来应该一致。但如果出现 8 小时偏移多半是两个原因数据库连接串的 serverTimezone 与服务器系统时区不一致JSON 序列化时把 Date 转成了 UTC 格式字符串。我建议统一输出时间戳前端格式化。在 Jackson 配置里设置disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)不会生效时直接给实体类的日期字段加上JsonFormat(timezone GMT8, pattern yyyy-MM-dd HH:mm:ss)简单粗暴。5.5 订阅消息发不出去的排查顺序订阅消息发不出去一般按这个顺序排查确认小程序后台已经申请了订阅消息模板并且拿到了模板 ID。确认用户真的授权过该模板且授权次数没有被消耗。授权次数可以在后端记录每成功发送一次减 1。确认page参数配置了跳转页面且该页面在 app.json 的页面路径中存在。确认发送接口调用时touser传的是用户的 openid而不是小程序的 appid。确认模板字段data里的参数个数和类型和模板一致比如模板要求thing1、time2传成char类型也会报错。最后一点很隐蔽微信要求同一个模板 ID 每用户每天只能接收有限次数的订阅消息一旦超过限制接口会返回43101错误码用户拒绝接受消息。产品侧要在用户授权时就约定好“只发送最关键的那一条提醒”。5.6 小程序包体积超过 2MB基础库、图片、第三方组件库加在一起很容易超过 2MB。打包时报source size 2612kb exceed max limit 2mb实际解决办法有这几个图片资源从本地静态文件改成云端 URL不要放本地 base64。按页面拆分启用分包加载。把“日历页”和“我的页面”放为分包主包只留核心首页和新增页。用npm run build压缩代码移除不必要的 console 和无用依赖。检查是不是引入了整套 UI 框架比如 Vant Weapp如果只是用到几个组件做按需引入。5.7 开发调试技巧用抓包确认前后端数据真相前后端联调的时候经常遇到“我觉得前端传了”、“我觉得后端没收到”的扯皮。这种场景下抓包是最好的裁判。常用的抓包工具 Charles 在小程序调试里也很顺手原理是让手机走 PC 上的代理同时安装 Charles 的 SSL 证书就能解密 HTTPS 流量。具体步骤是Charles 开启 Proxy - SSL Proxying Settings添加*开启所有域名的拦截手机 WiFi 手动设置代理指向电脑 IP 和 Charles 默认端口 8888手机浏览器访问chls.pro/ssl下载并安装证书之后小程序发出的每条请求都会在 Charles 里显示。看到请求头里的 token、请求体里的参数、响应里的 JSON问题定位就是一眼的事。5.8 其他零散但高发的坑picker 组件在 iOS 上高度滚动时偶发失效可在 bindchange 里重新赋值 value 解决。小程序 canvas 绘制海报时真机上wx.canvasToTempFilePath的destWidth要设成 750 的倍数否则导出模糊。下拉刷新要在页面 json 配置enablePullDownRefresh: trueonPullDownRefresh 里重新拉接口之后必须手动wx.stopPullDownRefresh()。自定义导航栏后页面顶部内容会被状态栏遮住一定要给第一个元素预留状态栏高度的 padding。数据库datetime默认值不要用CURRENT_TIMESTAMP如果你的 MySQL 版本比较老它不会自动更新需要额外配置ON UPDATE CURRENT_TIMESTAMP。6. 文档组织与源码工程结构6.1 毕业设计文档怎么写才不空洞这个项目的文档一般包含六章。第一章绪论写研究背景和意义多引用一些移动应用和日程管理相关的数据说明时间管理的重要性。第二章相关技术介绍依次写微信小程序、SSM、MySQL重点写为什么选它们不要大段粘贴官方简介。第三章需求分析画用例图列功能需求表。第四章系统设计画系统架构图、功能结构图、时序图附上核心表结构说明。第五章系统实现挑两三个关键页面截图并贴核心代码。第六章系统测试写测试用例表格加测试结果。写文档时有个技巧先用系统的界面截图把每个功能过一遍对应写“实现效果”再补充关键代码。截图比文字更有说服力。测试用例表格要覆盖正常流程和异常流程比如“提交空标题日程系统能提示”“重复点击完成按钮不会报错”这几条都是评审老师爱看的内容。6.2 源码工程结构建议可读性优先后端源码要保持“一个请求进来能顺着接口找到实现”的直觉所以 Controller、Service、Mapper 三个目录命名一定要清晰。Maven 工程中依赖版本别用最新的Spring 用 5.xMyBatis 用 3.5.xMySQL 连接器用 8.0.x配合 Maven 的 dependencies 管理即可。前端源码的重点是app.js里只放全局数据和公共方法页面自己的请求要写在页面里不要在Page的data里嵌套过多层级setData 更新深层路径容易性能崩。把utils/request.js封装好之后所有页面的请求都走它后期改造接口地址只需要改一个 baseUrl。6.3 从毕业设计到真实可用上线路线与扩展思路做到这里项目基本完成交付。如果想让它真正跑起来供用户使用还需要走完部署链路买一台云服务器最低配即可装 JDK 8、Tomcat 8.5、MySQL 5.7 或 8.0把后端打成 war 包扔进 Tomcat 的 webapps配置域名并买 HTTPS 证书小程序管理后台把域名配置成合法请求域名提交审核发布。如果想在这个基础上继续扩展方向很明确把 token 从数据库存储升级为 Redis 存储提高并发能力和登录态过期处理效率。日程列表增加“拖拽排序”或“优先级标记”。在“我的”页面里加一个数据统计模块展示本周完成率用echarts的按需引入画一个简单柱状图。用uni-app重构小程序后续可以一套代码同时发布到支付宝小程序、百度小程序和 H5。给日程表增加remind_type字段支持“提前 10 分钟”“提前 1 小时”“提前一天”三种提醒策略后端按策略计算发送时间。我个人在做这个项目时最深的体会是技术栈并不需要高大上SSM 加小程序完全能撑起一个结构完整、逻辑自洽的毕业设计关键是每一步都要想清楚“为什么这么设计”。数据库的表为什么这样建提醒功能为什么用订阅消息导航栏高度为什么这样算这些“为什么”才是项目真正的价值所在也是答辩或面试时能展示出来的核心思考。如果你正在复制这个项目试试把每一层代码都亲手敲一遍再配上抓包工具去理解请求全链路你从项目里得到的会比写在文档里的多得多。
返回列表