基于微信小程序与Spring Boot的个人行政复议在线预约系统设计与实现

发布时间:2026/9/26 18:07:43
基于微信小程序与Spring Boot的个人行政复议在线预约系统设计与实现
计算机毕业设计里最不缺的就是“基于XX的XX系统”这个套路但真正能顺利通过答辩、让导师点头的往往是业务场景清晰、技术栈完整、能当场演示的项目。这次我整理的是一个基于微信小程序实现个人行政复议在线预约系统的完整思路前端用微信小程序承载用户操作后端负责预约管理和数据处理同时把项目源码、论文说明的整理逻辑一并讲透。如果你正在选毕设题目或者已经选了预约类项目但不知道功能怎么拆、数据库怎么建、并发怎么防超卖这篇文章可以帮你从头到尾走一遍。这个项目既不是纯前端写静态页面也不是只做后端CRUD它涉及微信登录、预约时段占用、防重复提交、管理员排期、消息通知等完整闭环。相比常见的图书馆预约、会议室预约个人行政复议在线预约最大的特点是业务约束更多同一人不能重复预约、每人只能有一个进行中的申请、管理员需要按时间段放号。这些约束一旦落到数据库和接口设计里很多隐藏问题就会浮出来。1. 项目定位与业务边界个人行政复议在线预约到底在做什么1.1 业务场景和角色拆分先别急着写代码把场景盘清楚。个人申请行政复议时按线下流程往往需要到窗口提交材料、核对身份、确认受理范围。过去大多靠电话预约或者现场排队问题很明显高峰期窗口压力大申请人不知道哪个时段人少电话占线也常见。这个系统要解决的就是让申请人通过微信小程序自助选择日期和时段预约成功后按时到现场办理后台管理人员能按日排期、查看预约名单、处理爽约情况。系统角色拆成两类就够普通用户微信授权登录后查看最近的开放时段填写申请类型、姓名、身份证号、联系电话选择日期和时间段提交预约之后可以在“我的预约”里查看状态或取消预约。后台管理员维护每日开放的预约时段、设置每个时段的名额对预约记录进行确认或标记完成查看统计报表操作日志留痕。1.2 功能边界要克制别把系统做成OA很多学生做毕设容易犯的错是功能越加越多最后变成了一个“什么都能干”的半成品。这个项目的边界应该非常明确只做预约闭环不做在线材料提交不做审批流。行政复议受理材料的预审属于线下业务环节放到线上只会让复杂度飞涨而且评审老师并不知道真实审批规则容易追问到无法收场。核心功能清单控制在下面这个范围用户登录与身份绑定查看可预约日期和时段提交预约申请含基础信息校验取消预约、查看预约状态管理员维护时段和名额管理员确认预约、标记完成或爽约按日期统计预约量1.3 为什么用微信小程序这几乎是唯一不需要犹豫的选型。一是用户打开微信就能用不需要安装App对这类低频公共服务场景非常合适二是微信开发者工具调试方便演示环节扫码即可不会出现环境差异三是毕设评审场景中小程序的前端界面视觉冲击力明显强于普通网页。相比H5小程序自带身份体系openid省去了自己设计账号密码注册登录的麻烦。2. 技术选型与工程结构从零搭建预约系统的架子2.1 前端选型原生小程序还是uniapp我在实际指导这类项目时会先问一个问题你只想做微信小程序还是以后想跨平台如果只做微信小程序原生WXMLWXSS就是最佳选择API文档直接、问题排查容易评审老师也看得懂。如果为了简历上多一个跨端技能点可以用uniapp但要注意编译到微信小程序时有兼容问题而且真机调试更容易踩坑。这个项目建议用原生小程序。原因很简单核心页面只有四五个不需要跨端没必要引入框架层让项目结构变臃肿。2.2 后端框架Spring Boot 比 SSM 更省心后端推荐Spring Boot 2.x MyBatis-Plus MySQL。Spring Boot简化了配置内嵌Tomcat启动一个项目就是run一个main方法MyBatis-Plus把单表CRUD几乎封装完了写Mapper的时候大部分接口不用手写SQL。对毕设来说代码量直接影响答辩深度这组选型可以用最少的代码覆盖最多的功能点。当然用SSM也不是不行但SSM要配一堆XML项目体积和纸张上的复杂度更高原理上却不比Spring Boot多讲出什么内容。考虑到后期还要写论文技术栈越主流参考资料越好找。2.3 工程目录结构一个标准的项目归档应该分成四块答辩时老师打开目录就能快速定位wechat-appointment/ ├── miniprogram/ # 微信小程序前端 │ ├── pages/ │ │ ├── index/ # 首页展示可预约日期 │ │ ├── booking/ # 预约表单页 │ │ ├── order/ # 我的预约列表 │ │ └── mine/ # 个人中心 │ └── utils/request.js # 请求封装 ├── backend/ # Spring Boot 后端 │ ├── src/main/java/com/llgong/... │ │ ├── controller/ │ │ ├── service/ │ │ ├── mapper/ │ │ └── entity/ │ └── src/main/resources/ ├── sql/ # 数据库建表脚本 └── docs/ # 论文、答辩PPT、运行说明2.4 开发环境的前置准备至少需要这些微信小程序账号个人主体就够但要记得个人主体没有部分高权限接口、微信开发者工具、JDK 1.8或11、Maven 3.6、MySQL 5.7或8.0、Navicat或Workbench。后端用IDEA还是Eclipse都行但IDEA的社区版免费而且配合Lombok和MyBatisX插件效率高很多。3. 数据库设计预约系统的三张核心表和状态机3.1 用户表用 openid 绑定身份小程序端不需要用户输入用户名和密码后端通过wx.login的code换取openid这是用户唯一身份标识。同时建议存一个手机号字段方便线下联系。CREATE TABLE t_user ( id bigint NOT NULL AUTO_INCREMENT, openid varchar(64) NOT NULL COMMENT 微信用户唯一标识, nickname varchar(64) DEFAULT NULL, phone varchar(20) DEFAULT NULL COMMENT 联系电话, role tinyint NOT NULL DEFAULT 0 COMMENT 0普通用户 1管理员, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3.2 预约时段表名额在这里而不是在预约记录里很多新手设计时会直接让用户提交一个自定义时间结果数据库里全是脏数据也没法控制同一时段重复预约。正确做法是管理员提前生成可预约的时段用户只能从这些时段里选。CREATE TABLE t_booking_slot ( id bigint NOT NULL AUTO_INCREMENT, slot_date date NOT NULL COMMENT 预约日期, start_time varchar(10) NOT NULL COMMENT 开始时段 09:00, end_time varchar(10) NOT NULL COMMENT 结束时段 10:00, total_count int NOT NULL DEFAULT 5 COMMENT 本时段总名额, booked_count int NOT NULL DEFAULT 0 COMMENT 已预约名额, status tinyint NOT NULL DEFAULT 1 COMMENT 1启用 0停用, PRIMARY KEY (id), UNIQUE KEY uk_date_time (slot_date, start_time, end_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3.3 预约记录表状态字段是核心预约记录要记录用户选了哪个时段、什么状态、什么时间取消的。状态机建议这样定义1待确认2已确认3已完成4已取消5爽约。这个状态流在后端代码里会反复出现论文里也能画一张图。CREATE TABLE t_appointment ( id bigint NOT NULL AUTO_INCREMENT, appointment_no varchar(32) NOT NULL COMMENT 预约编号, user_id bigint NOT NULL, slot_id bigint NOT NULL, real_name varchar(30) NOT NULL COMMENT 真实姓名, id_card varchar(18) NOT NULL COMMENT 身份证号, phone varchar(20) NOT NULL, status tinyint NOT NULL DEFAULT 1, remark varchar(255) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, cancel_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_appointment_no (appointment_no), KEY idx_user_id (user_id), KEY idx_slot_id (slot_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3.4 防止同一时段被抢空三个层面都要做数据库层面时段表用datestart_timeend_time做唯一约束避免管理员重复生成同一个时段业务层面查询时段时判断booked_count total_count更新名额时只在booked_count没超限的情况下做自增代码层面提交预约必须开启事务并在更新时对slot行加锁。这三层都做到了基本可以应付同类预约场景的并发问题。4. 小程序端实现细节从授权登录到预约成功4.1 登录链路code 换 openid 再换 token小程序端第一件事是登录。不能直接把openid放在前端也不应该每次都调用wx.login。标准流程是小程序调用wx.login拿到临时code传给后端后端拿着code去微信接口换成openid和session_key然后生成一个自定义token返回给小程序端。小程序端把token存在storage里后续请求带着它。这个链路里有一个反复踩坑的点code只能用一次而且有效期很短。如果后端处理异常导致没有换到openid前端又要重新触发wx.login才能拿到新code。所以登录按钮要做节流不能连续点击。4.2 手机号获取的限制个人主体别硬碰微信小程序现在想直接通过getPhoneNumber获取用户手机号要求小程序主体是企业个人主体用不了。这个项目建议改为在预约表单中手动填写手机号配合格式校验就好。如果你用了企业的AppID也可以申请手机号快速验证组件但毕设演示环境未必具备条件手动填更稳。4.3 预约表单页日期和时段选择预约页是核心页面交互流程大致是这样先选择日期再加载这个日期下的可用时段列表最后填入申请类型、姓名、身份证、手机号提交。async function loadSlots(date) { const res await request({ url: /api/slot/list, data: { date } }) // 后端返回时段时带上剩余名额bookedCount totalCount 才能选 this.setData({ slots: res.data.slots, selectedDate: date }) }提交前校验很有必要身份证正则、手机号正则、日期不能是过去日期、是否已经选择时段这四层校验缺一不可。还有一个细节提交按钮点击后立刻disabled防止用户手抖重复提交产生两笔预约。4.4 我的预约列表与取消预约“我的预约”用列表展示预约编号、日期、时段、状态状态用不同颜色区分。取消预约要向后端确认是否允许通常提前一天可以取消当天不能再取消否则会造成名额浪费。前端根据后端返回的code做提示而不是本地计算判断保证状态和数据库一致。4.5 订阅消息通知不是所有用户都会收到预约成功之后推送微信订阅消息能明显提升系统完整度。常见实现是用户在提交预约前先请求授权同意后后端拿到模板ID在预约成功时调用subscribeMessage.send发送通知。注意微信订阅消息是“一次授权一次推送”用户只点了一次同意你就只能发一条。论文里不要写“看状态实时提醒”这种话做成预约成功提醒就够了。5. 后端核心接口与并发处理真正能上线的预约逻辑5.1 接口清单和职责划分后端接口可以按用户端和管理端分两套接口方法说明/api/user/loginPOSTcode换openid并返回token/api/slot/listGET查询某日期的可预约时段/api/appointment/createPOST提交预约/api/appointment/myGET我的预约列表/api/appointment/cancelPOST取消预约/api/admin/slot/batchPOST管理员批量生成时段/api/admin/appointment/confirmPOST确认预约状态/api/admin/statsGET按日期统计预约量接口数量控制在15个以内比较合适既能体现工作量也不会让后端逻辑失控。5.2 创建预约接口的完整流程这是整个系统里最重要的接口我按事务顺序写一下校验token解析出userId校验参数slotId是否为空、姓名和身份证格式是否正确查询预约时段检查status是否启用检查该用户是否已有未完成预约状态是1或2存在则拒绝对slot行执行SELECT * FROM t_booking_slot WHERE id ? FOR UPDATE锁定这一行判断bookedCount totalCount否则返回“该时段已约满”执行UPDATE t_booking_slot SET booked_count booked_count 1 WHERE id ? AND booked_count total_count这步是为了兜底插入预约记录生成唯一预约编号事务提交。Override Transactional(rollbackFor Exception.class) public AppointmentResult createAppointment(CreateRequest req, Long userId) { BookingSlot slot slotMapper.selectByIdForUpdate(req.getSlotId()); if (slot null || slot.getStatus() 0) { return AppointmentResult.fail(时段不存在或已停用); } int count appointmentMapper.countActiveByUser(userId); if (count 0) { return AppointmentResult.fail(您已有一个进行中的预约); } if (slot.getBookedCount() slot.getTotalCount()) { return AppointmentResult.fail(该时段已约满); } int updated slotMapper.increaseBookedCount(slot.getId(), slot.getTotalCount()); if (updated 0) { return AppointmentResult.fail(预约人数已满请选择其他时段); } // 插入预约记录 ... }5.3 并发控制事务加行锁已经够用这类预约系统不是秒杀真实并发量不会很大但答辩时一定会被问“两个人同时提交怎么办”。最佳回答是通过数据库行锁和条件更新来保证同一个时段不会被超额预约。select for update把slot行锁住后第二个事务就必须等待等到第一个事务提交后再判断名额自然就不会出现超卖。如果后期真的要做高并发可以把预约改成Redis预扣名额再用消息队列异步落库但那是生产级方案对毕设来说过度设计。5.4 管理员端设计管理员端可以用简单的Vue后台也可以复用小程序做管理页面。我的建议是后台管理单独做一个Web页面因为管理员在电脑前操作更方便而且也能展示一个项目里的前后端分离能力。管理员功能重点就三个按日排期、确认预约、统计查看。排期做成交互式表格选日期每个时段设置名额一键生成。6. 从源码到论文毕业设计交付物的整理思路6.1 源码结构怎么组织评审老师才看得明白源码不是越花哨越好而是要让人一眼看出分层。后端严格按controller、service、mapper、entity分开控制器只做参数接收和结果返回业务逻辑全部放在service层。小程序端每个页面目录下保留js、wxml、wxss、json四个文件复用组件放到components目录。有一个习惯建议从第一天就养好写清楚运行说明文档。README里要写JDK版本、MySQL版本、AppID配置位置、数据库脚本执行顺序、启动步骤。很多项目明明代码没问题因为环境不对跑不起来答辩演示只能在“开发者工具中看到编译报错”太亏了。6.2 论文目录结构与每一章该写什么论文不需要写得像教科书逐章对齐项目的实际内容即可绪论背景从线下预约排队问题切入意义分别从用户和管理员角度写国内外现状别夸大就说现有预约系统各有侧重。相关技术写小程序框架、Spring Boot、MyBatis-Plus、MySQL重点写它们为什么适合本项目。需求分析角色分析加用例图功能需求用表格列清楚非功能需求写性能、安全、易用性。总体设计系统架构图、功能模块图、数据库ER图和表结构。详细设计与实现贴小程序页面截图列核心接口关键代码块写创建预约的并发控制逻辑。系统测试测试环境、测试用例表格、结果分析。总结与展望总结项目成果展望可以写对接统一身份认证、增加材料预审功能。6.3 测试用例怎么准备测试用例是论文里最容易被水过去的章节同时也是答辩时老师喜欢翻的部分。建议按业务流程写不要只写“输入正确数据系统正常”这种废话。可以这样列编号测试模块测试输入预期结果实际结果TC01用户登录首次微信授权自动注册并返回token通过TC02查询时段选择今天日期只返回启用且未约满时段通过TC03创建预约同一时段已满后提交提示“该时段已约满”通过TC04重复预约已存在待确认预约再提交提示“您已有一个进行中的预约”通过TC05取消预约预约当天取消提示“当天预约不能取消”通过6.4 答辩时容易被追问的五个问题为什么用token而不用session小程序不是浏览器环境没有传统Cookie机制token存在本地更可控。怎么保证同一时段不被多个人抢到事务加行锁配合条件更新做兜底。小程序如何识别用户身份wx.login拿code后端换openidopenid在微信下唯一。为什么用户表和预约记录表要分开避免单个表字段过多也方便用户管理预约历史。系统最大瓶颈在哪在数据库的名额更新这一行目前的行锁方案能应对中小并发再高就要引入Redis。7. 部署上线与踩坑记录小程序能跑通和能上线是两码事7.1 微信公众平台配置小程序开发的第一个坑不在代码里而在后台配置。开发者工具里可以勾选“不校验合法域名”爽一下但一到真机预览就全部请求失败。真正的上线版本必须在小程序管理后台配置request合法域名域名必须是HTTPS。如果后端只是跑在本地可以先用内网穿透工具做临时演示但正式答辩建议把后端部署到云服务器。配置路径在小程序后台“开发管理 - 开发设置 - 服务器域名”需要填入request合法域名、uploadFile合法域名。注意一个月内只能修改几次别测试一次改一次。7.2 HTTPS和nginx反向代理后端接口如果要被小程序访问必须走HTTPS。最简单的部署方案是云服务器上装nginx监听443端口配置SSL证书然后把符合/api/的请求反向代理到本地的Spring Boot端口。server { listen 443 ssl; server_name api.example.com; ssl_certificate /etc/nginx/cert/xxx.pem; ssl_certificate_key /etc/nginx/cert/xxx.key; location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }SSL证书可以用云厂商免费版配置完用浏览器访问一下HTTPS接口确认证书链完整。这一步在答辩前必须提前一天做好因为证书域名解析有生效时间。7.3 我在实际运行中踩过的问题第一个问题是时间精度。数据库日期用date类型前端传的是“2025-07-01”这种字符串一切正常但如果后端用了LocalDateTime接收时间就变成“2025-07-01T00:00:00”JSON解析直接报错。规范做法是前端固定传日期字符串后端用DateTimeFormat和LocalDate接收。第二个问题是取消预约后名额不释放。如果取消逻辑只是把状态改成4忘记把slot表的bookedCount回退那么一段时间后所有时段都会满。取消预约接口里必须同时做两件事更新预约状态为取消并且把对应slot的bookedCount减1。第三个是微信开发者工具和真机的差异。真机上日期组件返回的格式可能带“年/月/日”直接转字符串再传给后端会失败。稳妥做法是自己统一格式化不要信任不同平台的默认输出。第四个是订阅消息发送失败的静默问题。微信在用户拒收、模板下架等情况下不会抛出明显异常后端可能显示发送成功其实没有送达。调试时需要订阅消息模板块的发送记录一点点排查不能只看最终状态。7.4 演示前一定要做的检查答辩演示是最容易翻车的地方提前30分钟过一遍这个清单后端已启动、MySQL已启动、数据库脚本已执行、小程序AppID已改成自己的、开发者工具里已关闭“不校验合法域名”或域名已配置、手机号和身份证输入框能正常输入、预约成功后能从“我的预约”看到记录。另外准备一个已取消的预约和满时段提示的截图作为演示中的异常分支素材比临场操作可靠得多。最后再分享一点个人体会这类预约系统真正吃功夫的往往不是前端页面写得多好看而是状态管理和名额扣减是否经得起连续操作。把预约提交这个动作的并发和幂等处理好后面再叠加什么功能都很轻松。如果你正在做同类型的预约项目先在纸上画清楚状态流转图把数据库表设计稳定了再开始写页面进度反而会快很多。