我在大学最后一年接了个Spring Boot预约系统的毕设项目,边补基础边搭架构,前后折腾了大概六周。做完后发现这类题目在计算机毕业设计里出镜率极高,停车场预约、实验室预约、健身房预约、会议室预约,换一层皮就是一套新系统。但很多人拿到题目后第一反应是“这东西太简单了”,真正动手才发现定时任务、冲突检测、数据一致性、部署上线,每个环节都能卡你两三天。
这篇文章把我做这个基于Spring Boot的通用预约系统的完整思路、技术选型、后台业务逻辑、数据表设计、部署过程和踩坑记录全部捋一遍。目标是让拿到类似题目的同学能少走弯路,也让想用预约系统做小项目的同行有个可直接参考的落地方案。
这套系统最终实现了:多类型资源管理、按时间段开放预约、预约冲突自动检测、用户信用管理、管理员后台审核与统计、消息提醒和完整的部署文档。项目代码结构干净,Controller-Service-Mapper三层分离,前端采用轻量模板引擎渲染,数据库用MySQL,缓存放Redis,后台权限用Sa-Token+RBAC模型,整体可控、可讲、可答辩。
1. 通用预约系统的整体设计与思路拆解
1.1 为什么说“通用”是这套系统的核心考点
很多毕设题目的关键词是“通用预约系统”,这里的“通用”不是指能做出来一个像美团那样的商业平台,而是指系统的业务模型要能适配多种预约场景。我在设计之初就定了一个原则:资源永远是可配置的,不要为某一种具体场景写死逻辑。
怎么理解这个“可配置”?我当时做了一个类比:预约系统的本质就是一个“资源分配器”。假设你是学校图书馆的管理员,自习座位是资源,学生是使用者,时间就是约束条件。如果要做的是实验室预约,资源就变成了工位和设备,使用者变成教师和研究生,约束条件加上设备权限。如果抽象到这一层,系统的核心模块就只剩三个维度:谁去用、用什么、在什么时间用。
所以在数据库设计时,我引入了资源表(resource)、预约订单表(appointment)、时间段表(time_slot)、规则配置表(rule_config)。资源表里有个 resource_type 字段,用来区分座位、设备、房间等类型。很多初次做这类系统的同学容易犯的错误是把座位预约做成座位表,把会议室预约做成会议室表,最后拼接成一个表面丰富但实际无法复用的系统,中期评级时反而很难自圆其说。
我的建议是:与其纠结具体场景,不如把底层身份、资源、时间、规则四个对象做扎实。这样做有一个额外的好处——答辩时老师问“你这个系统能不能改成宠物医院预约系统”时,你完全不用慌。因为宠物、医生、时间段这三个元素正好落在资源、使用者、时间约束里,业务上你的系统已经覆盖了。
1.2 技术选型:为什么用Spring Boot而不是SSH或SSM
这个项目我选了Spring Boot作为后端基础框架。道理很简单:Spring Boot让配置和部署的心智负担大幅降低。如果你用传统的SSH(Struts+Spring+Hibernate)或者纯SSM框架,光配置文件就能写上几百行,中间只要有一个属性拼错,整个应用起不来。而Spring Boot通过自动配置把大量的默认行为固化下来,你只需要关注自定义部分。
从毕设答辩的角度看,Spring Boot也更有话题性。评委老师通常会问“为什么选用这个框架”,如果答案是“因为大家都在用”,这就是一个减分项。但如果你能说明Spring Boot的约定优于配置、内嵌Tomcat免部署、生态整合方便(Redis、MyBatis-Plus、Sa-Token都有成熟starter),再结合你实际整合过的组件逐一佐证,那这个问题就是你的加分项。
数据库层面我用的是MySQL 8.0,ORM框架选了MyBatis-Plus而不是原生MyBatis。原因有二:一是MyBatis-Plus的BaseMapper内置了常用的增删改查方法,写复杂SQL时又能退回到XML或注解,灵活性和开发效率都兼顾;二是MP的字段填充、逻辑删除、乐观锁插件对预约场景特别有用,比如乐观锁可以直接解决多人同时抢最后一个时段的并发更新问题。
缓存选Redis,不是简单为了“引入中间件”而引入,而是实际解决两个硬需求。第一,热门时段的剩余名额是高频读数据,每次请求都查数据库会把MySQL的QPS推得很高;第二,预约时段的碰撞检测需要原子操作,Redis的Lua脚本能帮我们做一步校验加扣减。这些在后面的章节详细说。
部署方向,我准备了本地和服务器两套方案。本地用Spring Boot内置的Tomcat直接打包运行,服务器用宝塔面板做Nginx反向代理,静态资源和动态请求分离。这个部署过程我在第4节完整讲一下。
1.3 核心流程设计:一次预约请求是怎么走完的
先画一遍核心链路,后面各节按这个链路细讲。
用户在前端选择资源类型,进入资源列表页,系统根据当前时间动态加载可用时段。用户选定时段点击预约,后端先做幂等校验(即防止同一用户同一时段重复提交),然后通过Redis Lua脚本完成“时段存在性校验 + 名额扣减”,成功后写入订单表并异步通知相关方。管理员后台可以查看所有订单、取消违规订单、配置资源容量与时段的开放策略。
这里面最容易出问题的环节就是“扣减名额”和“写订单”的一致性。如果先减库存再写单,写了单但系统重启前没提交事务,名额就白白扣掉了;如果先写单再减库存,并发下就会出现超卖——两个人同时抢最后一个名额,一个时段卖出去两张。这个问题在第3节详细讲我的解决方案,记得Mark一下那个Redis Lua脚本的部分。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据库设计与核心模块拆解
2.1 核心表结构设计(可直接抄作业)
预约系统的表数量不需要太多,但每张表都要经得起“为什么这样设计”的追问。我这里列出最主要的六张表。
先看用户表。用户表不存密码明文,密码字段存的是BCrypt加密后的哈希串,哪怕数据库泄露了,也不能反推出原始密码。角色字段用tinyint区分普通用户、管理员、超级管理员,权限拦截时直接校验当前登录用户的角色值。
资源表是“通用”的载体。resource_type区分LAB、SEAT、ROOM、EQUIPMENT等,type_config字段采用JSON格式存不同资源类型的特殊参数。比如设备预约需要“是否需审批”,会议室预约需要“最大容量”,这些参数如果都建列,表结构会很发散。松耦合设计就是让一类字段存在JSON里,业务层自己解析,真要说缺点也只是对复杂查询不友好,但作为预约系统,这个取舍是可以接受的。
时间段表的设计是另一个关键点。系统支持管理员预设每日的开放时间段,例如上午08:00-10:00、10:00-12:00,下午两段,晚上两段。time_slot表里存了start_time、end_time、total_capacity、remain_capacity、status,日期存的是date字段,精确时间存time字段,这样跨天预约(比如22:00到次日02:00)也能通过日期加时间的方式正确表达。
预约订单表是整张表设计的重心。业务单号appointment_no是全局唯一的,生成规则我用了日期前缀加Redis自增序列,形如APPT202406150001,这样数据库索引友好,业务反馈也直观。sla_status字段表示预约状态,包括待审核、已确认、已完成、已取消、爽约等状态。外键我只保留逻辑外键(resource_id, user_id, slot_id),不建物理外键约束,理由有两点:一是物理外键在删除和更新时容易拖累性能,二是分库分表场景下物理外键会变成大麻烦。因为表里用逻辑关联,代码里事务控制好一致性就够了。
规则配置表收敛了一些业务规则,例如“提前X天开放预约”“单用户每日最多预约Y次”“取消预约必须在开始前Z小时”。这些规则单独建表,好处是管理员调整业务策略时不用发版改代码,运营侧的需求变化被隔离到了数据层面。做毕设时这个表的存在本身就是一个亮点,能体现你对系统可维护性的思考。
整个表设计遵循了一个原则:所有的时间和状态字段都用规范的数据类型,时间可以是datetime或date+time组合,但绝不要用varchar。我见过有人把“2024-06-15 10:00:00”存成字符串,排序和范围查询全是坑,答辩时被老师一句“这个字段索引失效你知道吗”问得下不来台。
2.2 权限模型与后台管理模块
预约系统天然有多个角色:普通用户要在线预约和查看个人记录;管理员要配置资源、管理排班、审核订单;超级管理员要管理用户和系统参数。我用的权限模型是RBAC(基于角色的访问控制)。
实现层面引入了Sa-Token。这个框架比Shiro轻量,比Spring Security上手难度低很多,API风格也符合中文开发者习惯。登录成功后调用StpUtil.login(userId)生成令牌,前端后续请求在请求头带token,后端通过自定义拦截器校验登录状态和权限码。Sa-Token的注解鉴权非常方便,在需要管理员身份的Controller方法上标一行@SaCheckPermission("appointment:audit")就完成了权限声明,代码里几乎看不到硬编码的if else判断。
对于毕设项目,权限模型不需要做到无限细粒度。用户端、管理端、审核端三级足够覆盖大部分场景。真正值得花时间的是菜单权限的动态渲染,也就是说不同角色登录后台后左侧菜单不同,这个可以通过用户角色查询菜单表实现。这块做完后视觉效果提升明显,答辩演示时也是不错的加分点。
后台管理模块我拆成了三个子模块:资源管理(资源的增删改查、上架下架、容量设置)、时段管理(按周一到周日配置开放时段、批量生成未来N天的时间段数据、提前锁定特殊时段)、订单管理(订单列表筛选、取消订单、审核操作、导出日报)。其中批量生成时间段功能很有实用价值,管理员只需要设置好模板时段,系统跑一个循环就生成指定日期范围内的具体可约时段,不用每天都手动开。
2.3 预约碰撞检测:防止“一个时段被抢两次”
预约的核心约束是“互斥性”——同一个用户在同一时间内不能预约两个不同的资源(防止占着座位同时去占会议室),同一个时段的名额也不能超卖。
第一个约束相对好处理,在写入预约订单前,查询该用户在重叠时间范围内是否存在状态为“已确认”或“待审核”的订单,有则拒绝。这里SQL要注意用时间区间交叉判断,条件大概是:
start_time < new_end_time AND end_time > new_start_time
这个条件本身不难,难的是索引效率。订单表数据量上来后,如果user_id和start_time、end_time没有联合索引,这个查询会随着数据增长越来越慢。所以建表时我就创建了联合索引(idx_user_time),后来压测时一万条预约数据下查询耗时稳定在几十毫秒内,效果还是很明显的。
第二个约束是超卖问题,放到第3节并发处理里细说。
3. 并发预约与数据一致性实战
3.1 超卖问题的两种经典解法对比
预约系统的超卖本质上和秒杀系统是同构问题:有限的名额、大量的并发请求。如果你用最简单的“先查再改”方式,也就是Java代码里先select剩余名额,再update订单表,那么在高并发窗口下,多个线程同时读到剩余名额为1,接着同时执行insert,最终超卖—表中多出来两条或更多记录。
解决思路主要有两条路线。
第一条路线是数据库乐观锁。在预约订单表对应的资源时段行上加一个版本号字段version,更新时检查版本号,更新后版本号加一。SQL大致是:
UPDATE time_slot SET remain_capacity = remain_capacity - 1, version = version + 1 WHERE id = ? AND version = ? AND remain_capacity > 0
如果更新影响行数为0,说明版本不一致或名额不足,事务回滚,用户看到“手慢了”的提示。这条方案的好处是完全依赖数据库,不需要引入额外组件,用于毕设项目已足够。
第二条路线是Redis分布式锁加Lua脚本。把所有时段名额信息预加载到Redis,比如key为 slot:stock:2024061501,value为剩余名额。Lua脚本内部做“库存大于0则扣减并返回1,否则返回0”,Redis单线程执行脚本保证了原子性,天然消灭了并发覆盖问题。扣减成功后再异步去MySQL写订单和降库存,最终通过消息或定时任务保证两边数据的最终一致。
我在项目里两条线路都实现了,默认走Redis Lua方案,同时提供了一个开关可以切换回DB乐观锁方案。答辩时把这个对比过程讲清楚,尤其是“为什么Redis脚本能保证原子性”这个点上多讲两句,评委通常都会点头认可。
3.2 全局唯一业务单号生成的细节
给预约单生成编号看起来是个小事,但如果直接用System.currentTimeMillis()拼接随机数,并发下很容易重复。我在项目中用日期前缀加Redis自增序号实现,结构是:固定前缀 + yyyyMMdd + 当天自增数。用Redis执行INCR命令,凌晨跨天时自动重置。
这个方案兼顾了有序性和可读性。运维或管理员在后台看到APPT202406150001,一眼就能识别出这是6月15日的第一号预约单。MySQL里这个字段做唯一索引,再配合程序里的异常捕获,即便极端情况下Redis数据丢了,也会有数据库兜底防止真正重复。
这里有个实操细节要注意:Redis的序号自增不能和订单写入MySQL放在一个事务里,因为Redis事务和MySQL事务是两套体系。我的处理是,先拿自增号,再写数据库。如果数据库写入失败,单号就废弃掉。Redis这边偶尔跳几个号完全不影响业务正确性,没有人会关心预约单号是不是完全连续。
3.3 防重复提交与消息提醒
用户在页面上手一抖连点了两次预约按钮,如果没有防重措施,系统可能创建两笔一模一样的订单。前端可以做按钮置灰,但真正可靠的防重必须在后端。我在后端用了两个手段:
一个是用Sa-Token的会话信息配合Redis做短时锁。用户请求到达时,先尝试向Redis写入一个key为user预约锁的分布式锁,如果setnx成功则说明这是首次请求,继续业务;如果失败则直接返回“正在处理中”,防止重复提交。锁的过期时间设为10秒,足够一个预约请求处理完成。
第二个手段是数据库层面的唯一约束。我在预约订单表上建了一个联合唯一索引,字段是user_id + date + time_slot_id + status,把“同一用户同一天同一个时段只能有一条有效预约”在数据库层面物理约束死。这样即便代码偶有疏漏,数据库也会拒绝重复插入。
消息提醒我接了两种方式:站内信和邮件通知。预约成功、预约取消、审核结果这几类事件都会触发通知。实现上用了Spring的@Async注解做异步发送,避免邮件SMTP拖慢接口响应时间。这里还有个细节,发邮件的账号密码不要在代码里写死,配置到application.yml里,同时用环境变量覆盖,这样传项目到GitHub时不会泄露密钥。
4. 部署环境与配置细节
4.1 本地环境搭建:从零到能跑通的完整步骤
我假设你机器上已经装了JDK 1.8及以上版本、Maven 3.6+、MySQL 8.0和Redis 6.x。如果还没装,装的时候注意版本对应关系:Spring Boot 2.7.x配JDK 8或者JDK 11都可以,MySQL 8.0配Navicat或MySQL Workbench都方便。
第一步,用Spring Initializr创建项目骨架,依赖勾选Spring Web、MySQL Driver、MyBatis-Plus、Validation、Redis、Sa-Token。Initializr生成的项目默认是0.0.1-SNAPSHOT版本号,我习惯改成1.0.0-RELEASE。这不是必须的,但导出后README里写“v1.0正式版”更有交付感。
第二步,准备数据库。在MySQL里创建数据库appointment_db,字符集统一utf8mb4,排序规则选utf8mb4_unicode_ci。然后执行项目的sql脚本初始化表结构和基础数据。初始化数据里我预置了管理员账号、资源类型字典和默认时段模板,这样系统一启动就有内容可演示,不用手动一条条录入。
第三步,修改配置文件application.yml。这里最容易被卡住的是数据库连接串和Redis地址连不上。数据库连接串我推荐加这几个参数:useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false。serverTimezone不设置的话,高版本MySQL驱动会用默认时区,你存进去的时间和实际北京时间可能差8个小时,排查起来非常迷惑。
第四步,启动Redis,然后启动Spring Boot项目。浏览器访问http://localhost:8080,看到登录页就说明基础环境没问题了。如果出现白页或404,优先看控制台日志,无外乎端口被占(改server.port就行)、Redis未启动、数据库密码错误这三类问题。
4.2 服务器部署:多环境配置与Nginx反向代理
本地跑通只是第一步,毕设通常还要在小机器上部署给老师演示,或者干脆放在云服务器上供同学访问。我部署用的环境是腾讯云轻量服务器,2核4G,操作系统选了Ubuntu 22.04。这个配置带一个Spring Boot应用加MySQL加Redis完全够用,最低甚至1核2G也能扛住几十个人的并发访问演示。
部署前我没直接写死生产环境配置,而是做了多环境配置拆分:application-dev.yml给本地开发用,application-prod.yml给服务器生产用,公共配置放application.yml。启动时通过spring.profiles.active指定环境,比如java -jar appointment-system.jar --spring.profiles.active=prod。多环境配置的价值是,你本地测试时数据库连接指向localhost,上了服务器只需要在启动命令或者环境变量里覆盖数据库地址和密码,不用改代码重新打包。
部署完Java进程后,我没有让用户直接用IP加端口访问,因为HTTP协议默认80端口更友好,而且在服务器上把8080端口直接暴露公网也不够规范。我的做法是安装Nginx,监听80端口,配置反向代理到本地的8080端口:
nginx复制server {
listen 80;
server_name your.domain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
这样一个简单的反向代理就让应用跑在标准端口上,同时关闭了Tomcat直接对外的端口暴露面,安全性和可用性都提升了一档。
4.3 MinIO对象存储与扩展预留
预约系统会涉及图片上传吗?实际上很多场景都会碰到,比如实验室设备需要上传照片、会议室需要上传平面图、用户头像也要有存储位置。如果我用Tomcat本地磁盘存储,部署到服务器后重启或者迁移时,图片路径就容易失效。所以我预集成了MinIO对象存储客户端。
MinIO是一个开源的对象存储服务,API兼容亚马逊S3,单机部署只要一条命令。Spring Boot这边引入minio依赖后,写一个MinIOConfig配置类,注入endpoint、accessKey、secretKey、bucketName,然后封装一个MinioService,提供上传、下载、删除文件的通用方法。控制器里接收MultipartFile后先上传,再把返回的文件URL存进数据库字段。
对毕设来说,引入MinIO有两个好处:第一是文件存储变得专业且有扩展性,不只停留在本地IO;第二是答辩时有东西可讲,对象存储、存储桶策略、预签名URL这些都是评委感兴趣的点。如果你时间紧张,不接MinIO也完全不影响主流程,但如果有余力,花半天时间集成一下绝对值得。
5. 常见问题与排查技巧实录
5.1 时间相关Bug:时区、日期格式与跨天预约
做预约系统,时间问题是我遇到最多的一类坑,而且很多坑在本地测不出来,上线才爆。第一个坑是MySQL连接串没加serverTimezone参数,导致数据库读出来的时间与前端预期差8个小时。解决办法就是前面说的,在JDBC连接参数里显式声明Asia/Shanghai。
第二个坑是前端提交的时间格式与后端LocalDateTime解析不匹配。比如前端传过来的是2024-06-15 10:00:00,而后端用的是LocalDateTime.parse()默认格式2024-06-15T10:00:00,中间有个T字的差别就会报DateTimeParseException。解决方法是统一前端格式,开发规范里约定好接口把所有时间字段都用yyyy-MM-dd HH:mm:ss格式,同时在LocalDateTime字段上加@JsonFormat(pattern=...)注解。
第三个坑是跨天预约。一个预约时段如果是22:00到次日02:00,判断“用户是否已有重叠预约”时,如果只比较开始时间或者只比较结束时间,逻辑就会有漏洞。需要按照时间段交叉公式来校验:新的开始时间小于已有结束时间,且新的结束时间大于已有开始时间,这两个条件同时成立才算重叠。这个逻辑我在单元测试里单独写了测试用例,特意覆盖跨天场景,后面改代码时测试一遍跑过才放心重构。
5.2 Redis和数据库不一致:库存对不上怎么办
就算有Lua脚本保护,长时间运行后仍可能出现Redis缓存中的时段剩余人数和MySQL中的实际记录不一致。常见原因有:Redis键过期了但MySQL还有未完成订单、系统重启时Redis数据丢失后重新预热失败、补偿任务没有正确执行。
我的处理方式是为库存预热和修正写一个管理命令,通过一个Admin接口或者启动时ApplicationRunner实现:系统启动时扫描未来三天内所有开放时段,把剩余名额和容量刷新进Redis;也可以定时每隔半小时执行一次,将MySQL余量覆盖回Redis。你可能会问,这样直接用DB覆盖Redis,在并发预约时会不会出问题?实际上半小时内的并发预约,Redis扣减的速度远快于DB覆盖速度,覆盖动作只会把Redis校准到当前真实的DB余量,真正执行预约扣减时还是要走Lua脚本。所以这套策略我用下来是稳定的。
5.3 防黑与数据安全的基本功
预约系统本身业务不复杂,但如果随便上线暴露公网,坏人第一个盯上的是未授权接口和SQL注入。我在这块做了四个基础的防护:
第一是所有涉及到用户数据的接口都必须登录后才能访问,通过Sa-Token的鉴权拦截器统一把控,Config里注册拦截器时指定放行路径(比如登录接口、注册接口),其余路径全部进入鉴权。
第二是在MyBatis-Plus的XML里写SQL时一律用#{}占位符,不要用${}。这个习惯要养成,${}直接把参数拼接到SQL字符串里,用户输入一个 1; DROP TABLE user 就完蛋了,而#{}会走预编译,参数只是参数,永远不可能变成SQL语句的一部分。
第三是对文件上传做类型校验和大小限制。MultipartFile不能只检查文件后缀名,还要通过文件头部字节识别真实类型。比如一张改名成.jpg的php脚本,后缀名是骗不过服务端的,但文件头识别能辨别出来。上传目录要设在Web应用的可写目录之外,禁止用户直接通过URL访问上传目录。
第四是数据权限校验。用户只能查看和操作自己的预约订单,不能通过改URL里的订单号越权查看别人的数据。这个权限校验不能在Controller里只靠前端传的id,而要在Service层通过当前登录用户的ID过滤查询条件。否则随便一个人把自己的id参数换成别人的,就把别人订单看光了,这在毕设答辩演示时是很容易被现场试出来的漏洞。
5.4 部署后的性能观察与优化笔记
系统上线后我压测了一下简单场景:50个用户同时抢同一个热门时段。默认配置下Spring Boot内嵌Tomcat是200线程池上限,MySQL连接池是HikariCP默认10个连接。我观察到的瓶颈在MySQL的连接等待,部分请求在获取数据库连接时排队超过500ms。
这里有必要讲一下算力配比:预约系统属于IO密集型而不是计算密集型业务。每个预约请求里真正计算的部分微乎其微,大头都在网络IO和数据库连接管理上。所以优化方向不是增加CPU,而是增加并发吞吐,核心手段包括:
一是调大HikariCP连接池配置,我调到了30个上限。机器4G内存跑MySQL加Spring Boot完全扛得住,连接池参数不是越大越好,超出数据库负载能力反而会有反效果。
二是把频繁查询的时段库存从MySQL搬到Redis,热点数据走内存查询。Redis单实例10万级QPS对这种预约场景的读压力绰绰有余。
三是对于非核心链路(比如邮件通知、站内信),全部改异步执行。Spring Boot里用一个@EnableAsync开启异步支持,然后在发送通知方法上标@Async,这样预约接口本身不会因为慢速邮件服务被拖到几秒超时。
四是压缩后端接口响应的JSON体积。用Jackson配置把值为null的字段不序列化,响应体减少了约20%。这个优化虽然不起眼,但是在网络条件一般的手机上访问时体感差异还是明显的。
如果到这你觉得性能还有提升空间,下一步就是加消息队列削峰,比如引入RabbitMQ或本地用Spring事件机制做异步削峰。预约请求进来后先返回“排队中”给用户,后台再慢慢消费写库。毕设项目不一定走到这一步,但把这条优化路径在论文里写出来,技术纵深就有了。
6. 写在最后的几个实操心得
做完这个预约系统,我最大的体会是:毕设题目的技术含量高低,往往不取决于框架多新多耀眼,而在于你是否把一个业务场景里的边界问题想清楚了。预约这件事,表面上就是选时间、点预约、管理员确认,但往深里走,并发超卖就是一个典型的分布式系统问题,时间碰撞检测就是一个时间区间算法问题,权限控制又是一个RBAC模型落地问题。把一个常见场景拆到这些深度,论文和项目都能立起来。
另外一个很实在的建议:写代码时尽量多留测试和截图。不要等到全部完成了再统一补测试,而是每完成一个模块就把接口测试记录保存下来。我是在开发过程中用ApiPost(或Postman)把每个接口的请求和返回数据存成文档,最后写论文时直接把请求参数、后端逻辑、返回结果三段式整理成表格,效率非常高,也让论文的“系统实现”章节显得特别扎实。
给即将做类似题目的人一个具体的操作顺序参考:先把数据库表结构和ER图定下来,再写后端核心业务(资源管理、时段管理、预约下单、订单管理),再接权限,再画前端页面,最后做分布式锁优化和部署。这个顺序背后有一条逻辑链:数据模型是一切的基础,权限是系统安全的骨架,优化是锦上添花,部署是交付闭环。按这个顺序推进,你每个阶段完成时都能看到一个能跑的半成品,心态会稳很多。
最后分享一个小技巧:部署时不要忘记在服务器的防火墙和安全组里放行80端口。如果配置了Nginx但外网无法访问,先检查安全组策略,再检查Nginx监听状态,然后在服务器本地curl一下,三步定位法能解决90%的访问问题。我在第一次部署时就是明明Nginx配置没问题,结果安全组忘了放行80端口,排查了半个多小时才反应过来。
