又到毕业设计季,我隔三差五就会收到私信:学长,我的题目是学习交流平台,老师建议用 PHP 做后端,微信小程序做前端,这组合行不行?说实话,行,而且只要别把需求想得太复杂,这套组合在毕设里属于标准的稳妥题。我最近帮人调试过好几个同题目的项目,发现大家的问题往往不在一两个大功能上,而是功能看着都有、一进真机流程就卡住,数据库字段没想清楚、中途加需求全得返工。这篇文章不打算给你贴整套源码,而是按我自己接手这类项目时的顺序,把整体设计、数据表、小程序端、PHP 接口、调试排查和答辩演示完整拆一遍,给正在做或者准备照着做的同学一个能落地的参考。
1. 为什么"学习交流平台+PHP+微信小程序"是标准稳妥题
1.1 这个题的功能盘子有多大
学习交流平台的本质,其实是一个简化的用户内容社区。说得直白点,就是让用户注册登录之后,能发内容、看内容、跟内容互动。把它拆成功能点,大概是这么一份清单:
- 用户模块:微信登录、个人信息维护、头像昵称修改
- 内容模块:帖子列表、帖子详情、发布帖子、分类筛选、关键词搜索
- 互动模块:评论、点赞、收藏
- 个人中心:我发布的、我收藏的、我的资料
这套功能看起来不算少,但仔细想一下,每个模块都是典型的前后端交互场景,而且数据关系非常清晰:帖子挂在分类下,评论挂在帖子下,点赞和收藏挂在用户和帖子之间。做毕业设计最怕的是题目太虚,讲不清楚要做什么;学习交流平台恰恰没有这个问题,每一张表、每一个按钮都能落到具体需求上。
我通常建议同学把功能分成两级。第一级是核心闭环:登录、浏览分类列表、看帖子详情、发帖、评论、点赞、收藏。这一级做完,项目已经"能跑通"了。第二级是加分项:搜索、热门排行、个人主页、消息通知。二级功能有没有都不影响及格,但做出来会明显提升项目的完整度。
1.2 PHP+小程序的组合好在哪,差在哪
先说结论:对于毕设这个场景,PHP 加微信小程序是很务实的组合,因为它的核心优势恰好命中毕设的痛点。
PHP 的优势是开发效率高、部署门槛低。你不需要为了一句话需求去折腾复杂的构建流程,写完接口直接就能跑。对于没有太多后端经验的同学来说,PHP 的排错成本也低,报错信息直观,网上资料多到看不完。微信小程序端的优势更明显:一套代码同时覆盖手机用户,不需要分别适配 iOS 和安卓;微信提供的登录协议已经把身份认证做掉了一大半;而且小程序审核上架流程相对短,答辩前能真机演示的机会大得多。
不过这套组合也有短板。最明显的是 PHP 的生态偏传统,如果你的题目强调高并发、实时通信、分布式部署,那 PHP 不是最优选择。但对学习交流平台这种业务型项目来说,这些短板根本碰不到。另一个容易被人忽略的点是,PHP 版本和运行环境差异会导致同样的代码在不同电脑上表现不一致,这也是我在调试时最常遇到的问题,后面我会专门讲。
1.3 扩展与缩水:让需求范围可控
很多同学一上来就把需求想得很大,什么关注、私信、群组、消息推送全都要做。我一般都劝他们先停下。毕设答辩的时间就那么十分钟,老师看的是你有没有把核心业务做扎实,不是看你功能列表有多长。需求做得越多,链路越长,出问题的概率越大,最后演示翻车的风险也越高。
这里有个判断标准:凡是涉及"一对多关系"又能明显展示数据变化的场景,优先做;凡是涉及"消息触达""实时同步"这种需要额外基础设施的场景,砍掉或往后排。比如评论和点赞,就是典型的一对多关系,数据一变就能在列表里看到,演示效果好;站内信通知则涉及消息表设计、未读数标记、触达时机,工作量翻倍且不好展示,不如不做。
我习惯在项目文档里保留一份"后续扩展规划",把砍掉的功能写进去。这样答辩被问"为什么没做关注功能"时,你可以说"我预留了用户关系表结构,但为了优先保证核心模块质量,没有在这期实现",这比支支吾吾强太多了。
2. 数据表设计:不返工的根基
2.1 六张必备表的字段设计
学习交流平台的数据模型,撑死六张表就能覆盖核心功能:用户表、分类表、帖子表、评论表、点赞表、收藏表。我自己设计表结构有个经验:字段宁多勿少,类型宁长勿短,因为等数据进去之后再改表,成本比一开始多想五分钟高得多。
用户表是基础,关键字段有这几个:
CREATE TABLE users ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, openid VARCHAR(64) NOT NULL UNIQUE COMMENT '微信身份标识', nickname VARCHAR(50) NOT NULL DEFAULT '', avatar VARCHAR(255) NOT NULL DEFAULT '', gender TINYINT NOT NULL DEFAULT 0 COMMENT '0未知 1男 2女', create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;这里最核心的一点是 openid 必须加唯一索引。openid 是微信用户在当前小程序下的唯一标识,登录逻辑全靠它来匹配老用户和创建新用户,一旦重复用户身份就全乱了。
分类表很简单:id、分类名称、排序值。帖子表是内容的核心,也是字段最多的:
CREATE TABLE posts ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id INT UNSIGNED NOT NULL, category_id INT UNSIGNED NOT NULL, title VARCHAR(100) NOT NULL, content TEXT NOT NULL, images VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '图片URL列表,JSON数组或逗号分隔', view_count INT UNSIGNED NOT NULL DEFAULT 0, like_count INT UNSIGNED NOT NULL DEFAULT 0, comment_count INT UNSIGNED NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 1 COMMENT '1正常 0隐藏', create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;注意,帖子表里我直接冗余了 view_count、like_count、comment_count 三个计数字段。这在范式上属于不完美设计,但对于列表页展示来说太实用了——每次查询列表都要统计评论数、点赞数,SQL 写起来复杂,数据量大时还慢。用冗余字段,只需要在评论、点赞发生时同步更新计数即可。评论区怎么做?每次点赞、取消点赞都先改点赞表,再更新 posts 表里的 like_count,两步逻辑放在一个事务里,问题不大。这个取舍在答辩时也能成为加分点,说明你理解空间换时间的思路。
2.2 点赞、收藏这种"关系型"数据怎么建表
点赞和收藏的数据结构很像,都是"某个用户"对"某个帖子"做了某个动作。我的建议是单独建表,不要为了省事把点赞记录塞进 JSON 字段里。
CREATE TABLE likes ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, post_id INT UNSIGNED NOT NULL, user_id INT UNSIGNED NOT NULL, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_post_user (post_id, user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE favorites ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, post_id INT UNSIGNED NOT NULL, user_id INT UNSIGNED NOT NULL, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_post_user (post_id, user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;联合唯一索引是这里的关键设计。它从数据库层面保证同一个用户对同一个帖子只能有一条点赞记录,即使前端重复提交、网络超时重发,也不会产生重复数据。这个细节经常被同学忽略,但效果立竿见影,而且答辩时老师问到"如何防重"你就直接甩这个设计。
评论表稍微复杂一点,因为要支持回复某条评论。我习惯加一个 parent_id 字段,根评论的 parent_id 为 0,回复某人的评论就填对应评论的 id。列表展示时,先查出帖子下的根评论,再根据 parent_id 查出嵌套回复,两层循环拼出树形数据。
2.3 初始化数据:目录分类和演示数据
表结构建完,最容易被忽略的是初始化数据。我不会把空数据库交给小程序去连,因为空列表页会带来两个问题:一是审核和演示时观感差,二是没法看出分页逻辑有没有正常跑。
分类表至少准备五个类别,比如:编程技术、考研升学、求职面经、项目实战、生活杂谈。每个分类下面预置几条帖子,内容要贴合分类主题,且保证有一条帖子带图片、有一条带较长的正文,方便测试富文本展示和图片列表效果。
演示用户也要准备。你不可能每次演示都用微信扫码现登录,所以在测试阶段我会在 users 表里手动插一两个测试账号,对应固定的 openid。这样开发工具里可以直接切换账号测试"不同用户对同一条帖子的点赞状态是否正确区分"。种子数据别乱写,要贴近真实内容,答辩时投影上的内容也是展示的一部分,全是"test123"这种太掉价。
3. 微信小程序端:跑通主流程的关键实现
3.1 登录态:openid和自建token两步走
学习交流平台的小程序端,第一步要解决的永远是登录。微信小程序的登录不是直接拿用户名密码,而是走一个两段式流程:
- 小程序端调用 wx.login 拿到一个临时 code;
- 把 code 通过 wx.request 发给自己的 PHP 后端;
- 后端拿着 code 去微信服务器换取 openid 和 session_key;
- 后端拿 openid 查用户表,没有就新建用户,有就更新登录时间;
- 后端自己生成一个业务 token 返回给小程序;
- 小程序把 token 存到 storage,之后所有请求都带上这个 token。
很多同学会对着第 2 步犯迷糊:为什么不直接在小程序里用 code 换 openid?因为换 openid 需要用到小程序的 AppSecret,这个密钥绝对不能出现在前端代码里。任何会下发到用户手机的代码都默认不可信,AppSecret 一旦泄露,别人就能冒充你的小程序做各种操作。所以必须由后端来做这个交换动作。
token 怎么存?最简单的方案是后端维护一张 token 表,字段就三个:token 字符串、用户 id、过期时间。每次客户端请求时校验 token 是否存在、是否过期。这个方案虽然原始,但逻辑清晰,也够用。
3.2 帖子列表、下拉刷新与触底加载
帖子列表页几乎是所有同学写的第一张页面,也是问题高发区。核心需求是分页。我见到的常见错误是直接把数据库里所有帖子一次性查出来全塞进列表,看起来能用,但帖子一多就卡,触底加载完全做不出来。
分页的逻辑不复杂,关键是状态管理。我习惯维护三个变量:page 表示当前页码、pageSize 表示每页条数、hasMore 表示是否还有更多数据。
onReachBottom() { if (!this.data.hasMore) return; this.loadPosts(); }, loadPosts() { const page = this.data.page + 1; wx.request({ url: `${app.globalData.baseUrl}/api/posts`, data: { page, pageSize: 10 }, success: (res) => { const list = res.data.code === 0 ? res.data.data.list : []; this.setData({ posts: this.data.posts.concat(list), page, hasMore: list.length >= this.data.pageSize }); } }); }这里有几个容易踩的点。第一个是下拉刷新后要重置 page 为 1,并且清空原列表,否则新数据会叠加到旧数据后面。第二个是判断 hasMore 的习惯问题:如果本次返回的条数小于 pageSize,说明已经到底了;如果刚好等于,则不能确定,要继续试下一页。第三个是 setData 的数据量,不要一次把整个大对象塞进去,列表拼接用 concat 生成新数组再 setData,否则性能会很差。
详情页也不要掉以轻心。帖子详情要同时展示内容、作者信息、点赞数、评论列表,这需要前端发起多个请求或者后端提供一个聚合接口。我倾向于后者:详情接口一次返回帖子正文加最新评论列表,减少前端串行请求,页面加载更快。
3.3 发帖与图片上传:chooseMedia和uploadFile的配合
发帖是学习交流平台的另一个核心动作,也是图片处理最集中的地方。小程序里选择图片用 wx.chooseMedia,这个 API 支持从相册选图或直接拍照,也可以配置最多选择张数。
但很多同学在这里犯了认知性错误:以为 chooseMedia 拿到的本地临时路径可以直接提交给后端保存。不对。临时路径只在当次小程序运行期间有效,而且后端根本访问不到这个路径。正确姿势是先调用 wx.uploadFile 把图片传到自己服务器,拿到服务器返回的图片 URL,然后把文字内容和图片 URL 列表一起提交给发帖接口。
上传文件时有一个细节要特别注意:wx.uploadFile 的 filePath 传的是临时路径,但 formData 是文本参数,受 2KB 长度限制。图片描述这种长文本不要往 formData 里塞,应该走单独的请求。而 name 字段要和 PHP 端接收的 $_FILES 键名保持一致,比如:
wx.uploadFile({ url: `${app.globalData.baseUrl}/api/upload`, filePath: tempFilePath, name: 'file', success(res) { const data = JSON.parse(res.data); // data.data.url 就是上传成功后图片的访问地址 } });对应的 PHP 接收端用 $_FILES['file'] 就能拿到文件信息,具体校验逻辑我在后面接口安全部分展开。整个发帖流程应该是:选图、逐张上传、收齐所有图片 URL、再提交帖子内容。如果上传中途失败,要给出明确提示并把已上传的图片清理掉,避免产生垃圾数据。
3.4 评论、点赞这种高频交互的UI细节
评论列表的展示相对简单,但"发表评论"的交互有不少门道。很多同学把评论输入框放在页面底部,但输入框很容易被键盘挡住。我的做法是给输入框加一个 relative 定位的外部容器,监听键盘高度变化,在 bindkeyboardheightchange 事件里动态调整容器 bottom 值,让输入框始终浮在键盘上方。
点赞按钮要特别注意交互反馈。最理想的体验是点击后立即变成红色,请求失败再回滚。如果先等接口返回再变色,用户会觉得卡顿。这里我用两层状态:接口请求前先乐观更新 UI,请求失败后恢复原样并 toast 提示。取消点赞的逻辑同理,唯一注意的就是后端要支持"幂等"处理——重复取消时返回成功但不报错。
收藏按钮和点赞类似,只是状态图标不同。还有一个容易被忽略的点:列表页里的点赞数、评论数,要和详情页保持一致。我建议列表页展示的数据直接取 posts 表里冗余的计数字段,详情页在用户发生互动后再重新拉一次详情,保证数据同步。
4. PHP接口层:代码安全问题集中在这
4.1 API约定与统一返回格式
小程序端和后端之间要有一套约定,不然联调时会扯皮。我习惯所有接口统一返回这个结构:
{ "code": 0, "msg": "success", "data": {} }code 为 0 表示成功,非 0 表示各种错误。这样前端只需要写一个公共 handler,先判断 code 再取 data,省得每个请求单独处理返回结构。
接口清单按功能模块整理:
| 接口 | 方法 | 说明 |
|---|---|---|
| /api/user/login | POST | 登录换 token |
| /api/categories | GET | 获取分类列表 |
| /api/posts | GET | 分页获取帖子列表 |
| /api/posts/{id} | GET | 获取帖子详情 |
| /api/posts/create | POST | 发布帖子 |
| /api/comments/create | POST | 发表评论 |
| /api/like/toggle | POST | 点赞/取消点赞 |
| /api/favorite/toggle | POST | 收藏/取消收藏 |
| /api/upload | POST | 上传图片 |
接口设计原则就一条:根据小程序端的实际页面来定。页面需要什么,接口就给什么。宁可一个接口多返回几个字段,也不要让前端为了拿一个数据发三次请求。
4.2 鉴权中间件的实现思路
接口写好之后,下一个问题是:不是所有接口都可以匿名访问。发布帖子、评论、点赞,这些操作必须要求用户已登录。我实现得比较简单但有效:在程序的公共入口处做一次 token 校验。
function authMiddleware() { $headers = getallheaders(); $token = str_replace('Bearer ', '', $headers['Authorization'] ?? ''); $userId = checkToken($token); if (!$userId) { jsonResponse(401, 'please_login', []); exit; } return $userId; }具体到项目里,我会把不需要登录的接口放在一个白名单数组里,比如登录接口、分类列表、帖子列表和详情。除了白名单,其他接口一律先过 authMiddleware,拿到的 userId 再传给业务逻辑。这样做的好处是安全感很强,后期加新接口时忘记加鉴权,默认也是受保护的,而不是默认裸奔。
4.3 防SQL注入与参数校验
PHP 写接口,最容易出的安全问题就是 SQL 注入,而且根源几乎都是字符串拼接。关于这一点我只重复一句:所有动态参数一律用 PDO 预处理,不要自己拼 SQL。
$stmt = $pdo->prepare('SELECT * FROM posts WHERE category_id = ? AND status = 1 ORDER BY id DESC LIMIT ?, ?'); $stmt->execute([$categoryId, $offset, $pageSize]);除了 SQL 注入,第二道防线是参数校验。前端传来的数据默认都是不可信的。比如分页参数 page 和 pageSize,必须强制转成整数,并且限制 pageSize 最大值;标题要 trim 去首尾空格,限制长度;content 不能允许任意长,否则一个超大请求就能拖垮服务。对字符串长度和数值范围的控制,写起来就是几个 if,但少了它们,各种莫名其妙的问题会在后期集中爆发。
第三道防线是输出转义。帖子内容里的 HTML 不能直接原样输出到小程序端,因为小程序端如果把这些内容当富文本渲染,脚本风险不小。我的做法是存储时用普通文本,展示时用 text 组件渲染,或者如果一定要支持富文本,就只允许白名单标签。
4.4 图片上传的服务端校验
图片上传接口是最容易被忽略安全细节的地方。很多同学直接把上传的文件保存到服务器就完了,结果出现两类问题:一类是上传目录变成可执行脚本的温床,另一类是磁盘被垃圾图片塞满。
我的服务端校验有四步。第一步,检查 $_FILES['file'] 是否存在,以及 error 是否为 0;第二步,检查文件大小,我一般限制在 5MB 以内;第三步,用文件扩展名白名单和 MIME 类型双重检查,只允许 jpg、jpeg、png、gif、webp 这几种;第四步,把文件重命名为时间戳加随机字符串,扩展名保持白名单内的值,避免用户上传的文件名直接落到服务器目录里。
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp']; if (!in_array($ext, $allowed)) { jsonResponse(400, 'invalid_file_type', []); } $newName = date('YmdHis') . '_' . uniqid() . '.' . $ext; move_uploaded_file($tmpName, $uploadDir . '/' . $newName);存储目录也要单独规划。我把上传目录放在 public 下的 uploads 目录,并且额外设置一个规则:uploads 里的文件一律按静态资源处理,不经过 PHP 解析。这样即使有漏网之鱼上传了伪装文件,也不会被执行。
5. 从本地调试到真机上线:高频问题排查
5.1 本地跑起来的三件套配置
拿到一份学习交流平台的源码,第一步肯定是在本地把它跑起来。本地环境需要三件套:PHP 7.4 或更高版本、MySQL 5.7 或更高版本、微信开发者工具。
很多同学卡在第一步是因为版本冲突。PHP 8 某些旧代码的写法不兼容,比如字符串函数行为变化、隐式类型转换报错,所以如果源码本身是在 PHP 7 时代写的,本地装个 PHP 7.4 跑起来会顺畅很多。另外,PHP 的 pdo_mysql 扩展必须开启,否则数据库连接直接报"找不到驱动"。
本地开发阶段,我不推荐立刻上 Apache 或 Nginx 完整环境,直接用 PHP 内置服务器顶一个月没问题:
php -S 0.0.0.0:8000在项目根目录执行这条命令,PHP 自带开发服务器就启动了。优点是没有端口配置和虚拟主机配置的烦恼,适合快速验证逻辑。唯一要注意的是生产环境和内置服务器在 URL 重写上有差异,但毕设阶段不需要担心这个。
数据库这边,把项目里的 sql 文件导入 MySQL,再确认配置文件里的数据库名、用户名、密码、host 和端口都对应上。这一步最容易出的问题是用 root 密码不对、或者 host 写成了 localhost 的 socket 方式而 PHP 走 TCP 连不上,建议统一写成 127.0.0.1。
5.2 真机调试的域名关
微信小程序从开发者工具跑通到真机调试,会撞上一面墙:要求所有 request 请求的域名都必须是已备案的 HTTPS 域名,并且要在小程序管理后台配置到合法域名列表里。
本地开发时,可以在微信开发者工具的详情设置里勾选"不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书",这样请求 http://127.0.0.1:8000 就能正常通。但一旦关掉这个选项,或者上真机预览,同样的地址就会报"request:fail url not in domain list"。
这里有个常见的误解:不是勾了"不校验"就能在所有场景用。真机预览如果你用"预览"功能而非"漫游调试",域名校验依然生效。我建议下:如果只是为了自己手机预览调试,就用开发者工具的"真机调试"功能配合不校验域名;如果要给同学、老师演示,最省心的还是配一个自己的域名和简单 HTTPS 证书,然后把域名填进后台白名单。至于云开发或内网穿透,属于另一种玩法,可以在答辩演示时作为备选方案。
5.3 我遇到过的几个典型报错
在帮人调这个项目的过程中,有几类报错几乎每个人都会碰到一遍,我把典型现象和原因列出来:
| 报错/现象 | 常见原因 | 解决办法 |
|---|---|---|
| request:fail url not in domain list | 域名未配置或校验收紧了 | 本地勾选不校验域名;上线前配好合法域名 |
| 数据库连接失败 | 数据库账号密码、端口、host 不匹配 | 逐项核对配置文件,用客户端工具独立连一次 |
| 中文乱码 | 连接字符集不是 utf8mb4 | PHP 连接后执行 SET NAMES utf8mb4;表结构也要 utf8mb4 |
| 列表数据一直为空 | 分页参数类型不对,字符串给到 int 字段 | intval() 强转 page 和 pageSize 再执行 SQL |
| 上传图片后 404 | 上传目录不存在或权限不够 | 创建 uploads 目录并给写权限;检查访问路径是否正确 |
| 时间差 8 小时 | PHP 默认时区不是本地 | php.ini 里 date.timezone 设为 Asia/Shanghai |
这些坑基本都不难,但它们有个共同特点:报错提示不会直接告诉你根因,要靠逐层排查。我一般建议同学遇到问题时把错误信息、请求参数、SQL 语句三个东西打印出来对照看,比瞎猜定位快得多。
6. 定制需求与答辩演示:怎么让项目"会说话"
6.1 常见的定制扩展点
拿到项目源码之后,你可能还会遇到"定制"这种要求。所谓定制,在毕设阶段一般就是下面几类需求:
一是后台管理。很多老师会期望项目有一个 admin 后台,用来管理分类、审核帖子、查看用户列表。如果前端已经是用 PHP 做的,后台用同一个框架套一个简单的登录页和列表页就好,工作量不大但观感提升很明显。
二是搜索。学习交流平台没有搜索总觉得缺了点什么。实现方式可以选择数据库的 LIKE 模糊查询,也可以做全文索引。毕设场景 LIKE '%关键词%' 够用,但要提醒自己:这个方案在数据量大时不高效,回答老师时要说清楚。
三是热帖排行。把文章的 view_count、like_count、comment_count 按权重算一个热度分,然后按分数倒序列表。这个功能代码量很小,却能展示你在"内容运营"层面的思考。
四是消息通知。比如有人评论你的帖子时通知你。这个功能涉及通知表、未读数逻辑,工作量明显上升,我一般建议做进扩展规划而不是当期实现。
无论哪种定制,我都要提醒一句:改代码前先理清楚你的数据结构。很多定制需求最后改崩,不是功能写不出来,而是原表设计不兼容新需求。所以在上手改之前,花半小时把表关系和现有接口梳理一遍,是非常值得的。
6.2 演示脚本怎么排
答辩演示是一门手艺。很多同学代码写得不错,演示时却像无头苍蝇一样乱点,全程老师都在看你找按钮。演示不需要把所有功能都点一遍,而是要讲一个流畅的业务故事。
我的标准演示脚本大概是这样:开场用一句话介绍项目是"基于 PHP 后端和微信小程序前端的轻量学习交流平台",然后从登录开始。登录后先展示分类列表,说明平台通过分类组织内容;点进一条帖子,展示正文、图片、评论列表;接着现场发一条新帖,带一张图片,让大家看到发布后的列表变化;发布后回到自己这条帖子,给别人的帖子点赞、收藏,再取消点赞,让数据变化直观可见。最后,打开数据库或后台页面,展示刚才发的帖子、点赞记录都真实落库了。整场控制在三到五分钟,全程只有一条主线,绝不东点西点。
这里有个小技巧:提前准备一份"演示数据剧本",让分类、帖子、用户都围绕一个统一的主题。比如平台主题是"考研上岸经验交流",所有种子数据都围绕这个主题设计,演示起来比随便抓几个帖子连贯得多。
6.3 容易被问到的技术问题准备
答辩老师不一定都会深入代码,但下面几个问题被问到的概率极高,建议提前准备好回答方向:
为什么选微信小程序而不是网页或 App?可以从微信生态的触达成本、不用安装、身份认证能力强、个人开发者门槛低这几个角度答。为什么选 PHP?可以答快速开发、部署简单、学习资料多,再补一句"本项目的业务场景对性能没有极端要求,开发效率是主要考量"。
token 过期了怎么办?可以设计成登录时签发七天有效期的 token,过期后前端收到特定错误码就引导用户重新 wx.login。解释清楚这个流程,老师会觉得你考虑过生命周期问题。
点赞并发怎么处理?第一层是数据库唯一索引兜底,避免重复插入;第二层是事务保证点赞表和计数更新的一致性。能答出这两层,基本就过关了。
图片为什么要传到自己服务器,不直接存小程序本地?因为小程序临时文件路径生命周期短,且后端无法访问,必须上传后再通过 URL 引用。这个问题其实是在测试你对小程序机制的掌握程度。
最后分享一个我自己带项目的经验:答辩前至少完整走三遍演示流程,每次都用真实的发布、评论、点赞操作,不要用提前准备好的静态数据。这个过程能暴露绝大多数"看着没问题、一跑就卡"的隐患,也能让项目讲解变成一件熟练且自信的事。如果能在演示最后主动点开数据库,让老师看到刚才的每条操作都有落库记录,那么整套项目的完成度就立住了。