简介:面向毕业设计场景的场地预约小程序完整项目,基于微信小程序+SSM+MySql技术栈开发,适合计算机相关专业学生作为选题参考、功能扩展或二次开发起点。系统实现场地类型管理、场地管理、预约管理、取消申请与押金退回等功能,分为管理员和用户双角色,覆盖从查询场地、在线预约、支付费用到使用场地、退回押金的完整闭环流程,解决传统体育馆现场预约费时费力的问题。压缩包共936个文件,约42.64MB,以vue前端页面、java后端逻辑、SQL数据库脚本、mp4演示视频及doc论文文档为主,附含开题报告、毕业论文和视频演示,可直接用于答辩准备与功能演示。已有291人学习下载,资源目录结构清晰,便于按源码、数据库、文档模块检索学习,同时提供运行脚本简化环境配置,省去从零搭建的时间成本。
1. 场地预约小程序到底要做什么:一个毕设题目的真实拆解
毕设题目定了“场地预约小程序”之后,很多人第一反应是“不就是做个预约吗”。直到开始拆需求才发现,这个题目同时牵扯三块东西:微信小程序要管用户点选和页面跳转,SSM 要做后端接口和业务规则,MySQL 要把场地、场次、预约记录全部落库。三块之间还夹着并发冲突、场次锁定、管理员审核这些躲不掉的细节。这篇笔记按“先画表结构,再写后端,再写小程序,最后集中排坑”的顺序展开,适合有 Java 基础、正拿这个题目准备毕设答辩,或者想用一个完整案例把 SSM 和小程序串起来的开发者参考。
2. 整体架构与数据库设计:先画表结构,再写接口
动手写代码前,先把表结构定下来。SSM 项目改接口比改数据库省事得多,数据库设计一旦返工,Mapper、Service、页面全都得跟着动。开题报告里的技术路线图,通常也是按这套架构画的:用户在小程序端发起请求,后端 SSM 接收并处理,数据最终落到 MySQL。
2.1 技术栈职责边界:小程序、SSM、MySQL 各管什么
小程序是纯粹的“壳”,只负责页面渲染和用户交互,它不能直连数据库。所有数据都要通过 wx.request 发 HTTP 请求到后端接口,再把返回的 JSON 渲染到页面上。这意味着后端接口的数量和语义,直接决定小程序端的开发量。接口设计得乱,小程序页面写起来就很痛苦。
SSM 是三个框架的组合:Spring 统一管理对象和事务,SpringMVC 负责把 URL 映射到 Controller 方法,MyBatis 负责把 Java 方法调用翻译成 SQL。三者串起来以后,业务上要做的事就变成了“接收参数—校验—写库—返回结果”。MySQL 是最底层的数据存储,场地信息、场次安排、预约记录、用户身份都存放在这里。
那这个题目为什么不用 SpringBoot?常见原因是高校课程和毕设模板对 SSM 更熟悉,答辩时老师问“Spring 跟 SpringMVC 各负责什么”,能指着项目一层层讲清楚,这本身就是加分项。如果只是自己私下练手,换 SpringBoot 没问题;如果是交毕设,按学校的既定技术栈走更稳,不要为了追新给自己埋雷。
2.2 四张核心表:场地、场次、预约、用户怎么设计
这类系统最少需要四张表:用户表存微信用户身份,场地表存场地基础信息,场次表存“某天某个时间段”的预约单元,预约表记录谁在哪个场次约了什么场地。
| 表名 | 关键字段 | 说明 |
|---|---|---|
| user | id, openid, nickname, role | role 用 0 表示普通用户,1 表示管理员 |
| court | id, name, location, image_url, description, status | status 用 1 启用、0 停用 |
| slot | id, court_id, date, start_time, end_time, status | status 用 0 可约、1 已锁定 |
| booking | id, booking_no, user_id, slot_id, court_id, status, create_time | status 用 0 待审核、1 已确认、2 已取消、3 已完成 |
为什么要把场次单独拆一张表,而不是在预约表里直接存开始时间和结束时间?因为一个场地一天会分成多个固定时间段,把时间段独立成表之后,场地列表接口可以直接查“某天还有哪些场次可约”,预约表只需要记录 slot_id 就行,查询路径会短很多。booking 表里冗余了一个 court_id,目的是让“我的预约”页面少做一次 join,这个字段多占一点空间,但换来的查询效率是值得的。
字段类型上,所有主键都用 BIGINT 自增,不要用 VARCHAR 当主键,自增主键在索引维护和分页查询上都有优势。openid 是微信用户的唯一标识,必须加唯一索引,因为同一用户重复登录时不能产生两条用户记录。
2.3 主键、外键和预约状态:容易被答辩老师追问的细节
物理外键在毕设项目里不建议建。原因很实际:删除场地或用户时,物理外键会强制约束,导致很多操作要按特定顺序执行;而常见做法是用逻辑外键,也就是在子表里保留父表的 id 字段(user_id、court_id、slot_id),然后给这些字段建普通索引。ER 图里仍然能画出表间关系,代码里却不用受数据库级约束牵制。
预约状态这个小字段特别容易被忽视,但它恰恰是答辩时老师最喜欢追问的点。建议用数字状态:0 待审核、1 已确认、2 已取消、3 已完成。取消从来不是真的删除记录,而是把状态改成 2,这样论文里能写“预约状态流转”,统计已取消数量也方便。代码层可以定义一个常量类或枚举,把这些状态值映射成有意义的名称,避免到处写魔法数字。
为什么不直接存“pending”“confirmed”这类字符串?字符串可读性确实好,但存储空间更大,而且写错一个字母就很难查出来。用 tinyint 存数字,配合代码里的常量说明,兼顾可读性和稳定性。数据库排序上数字也比字符串更直接。
2.4 初始化 SQL 与演示数据:第一次启动就能看到完整效果
初始化脚本要一次跑通,演示数据要覆盖两个场地、两个用户、未来几天的场次,否则小程序首页打开就是空白,后面所有调试都会卡在“没数据可看”这一步。下面这份 SQL 是我常用的初始版本:
CREATE DATABASE court_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE court_system; CREATE TABLE `user` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `openid` VARCHAR(64) NOT NULL COMMENT '微信 openid', `nickname` VARCHAR(32) DEFAULT '', `role` TINYINT NOT NULL DEFAULT 0 COMMENT '0普通用户,1管理员', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_openid` (`openid`) ) ENGINE=InnoDB; CREATE TABLE `court` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL, `location` VARCHAR(100) DEFAULT '', `image_url` VARCHAR(200) DEFAULT '', `description` VARCHAR(255) DEFAULT '', `status` TINYINT NOT NULL DEFAULT 1 COMMENT '1启用,0停用', PRIMARY KEY (`id`) ) ENGINE=InnoDB; CREATE TABLE `slot` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `court_id` BIGINT NOT NULL, `date` DATE NOT NULL, `start_time` VARCHAR(5) NOT NULL COMMENT '如 09:00', `end_time` VARCHAR(5) NOT NULL, `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0可约,1已锁定', PRIMARY KEY (`id`), KEY `idx_court_date` (`court_id`, `date`) ) ENGINE=InnoDB; CREATE TABLE `booking` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `booking_no` VARCHAR(32) NOT NULL, `user_id` BIGINT NOT NULL, `slot_id` BIGINT NOT NULL, `court_id` BIGINT NOT NULL, `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0待审核,1已确认,2已取消,3已完成', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_slot_user` (`slot_id`, `user_id`) ) ENGINE=InnoDB; -- 演示数据 INSERT INTO `user` (`openid`, `nickname`, `role`) VALUES ('demo_openid_admin', '管理员', 1), ('demo_openid_user', 'A同学', 0); INSERT INTO `court` (`name`, `location`, `description`) VALUES ('羽毛球馆 1 号场', '综合楼 3 层', '标准羽毛球场地'), ('羽毛球场 2 号场', '综合楼 3 层', '靠近窗边,光线较好'); INSERT INTO `slot` (`court_id`, `date`, `start_time`, `end_time`) VALUES (1, DATE_ADD(CURDATE(), INTERVAL 1 DAY), '09:00', '10:00'), (1, DATE_ADD(CURDATE(), INTERVAL 1 DAY), '10:00', '11:00'), (2, DATE_ADD(CURDATE(), INTERVAL 1 DAY), '09:00', '10:00');这段脚本里有几个点值得说明。字符集用 utf8mb4,不只是为了中文,而是为了兼容四字节字符。日期不写死,而是用 DATE_ADD(CURDATE(), INTERVAL 1 DAY) 生成明天,这样无论哪一天初始化,页面都能看到未来可约的场次,演示时不用手动改数据。booking 表加了一个 UNIQUE KEY uk_slot_user,是一道兜底防线:同一个用户对同一个场次不能重复预约,后面并发处理会再次提到它。
3. 后端 SSM 怎么落地:场地查询与预约提交的关键实现
后端是整套系统的业务核心。这一章按“配置 → 查询 → 提交 → 权限”的顺序写,全程围绕最小可运行的项目来组织代码,不给多余的封装。
3.1 SSM 分层结构和三个关键配置文件
SSM 项目从上到下分三层:Controller 接收请求并返回 JSON,Service 写业务规则,Mapper 负责 SQL。答辩老师问“一个请求进来怎么走的”,回答顺序就是 页面 → Controller → Service → Mapper → 数据库,然后逆向返回。
先看三个最关键的配置。spring-mvc.xml 里要开注解驱动、扫描 Controller、配置静态资源映射,其中静态资源映射是为了让上传的场地图片能通过 URL 访问:
<context:component-scan base-package="com.court.controller"/> <mvc:annotation-driven/> <mvc:resources mapping="/upload/**" location="file:D:/court-upload/"/>mybatis-config.xml 里最实用的是驼峰映射开关,打开以后数据库的 create_time 能自动映射到 Java 属性 createTime,省去一大把 resultMap:
<configuration> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> </configuration>数据库连接配置放在 jdbc.properties,注意 MySQL 8 的参数一个都不能少:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/court_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true jdbc.username=root jdbc.password=123456url 里的 serverTimezone 指定时区,useSSL 关掉避免本地环境握手报错,allowPublicKeyRetrieval 是为了兼容 MySQL 8 的认证方式。第一个出问题的往往是最后这个参数,后面排坑章节会再讲。
3.2 场地列表接口:从 Controller 到 Mapper 的一次完整调用
场地列表是首页最主要的接口,目标是把启用的场地按分页返回给小程序。Controller 只做参数接收和结果包装:
@RestController @RequestMapping("/api/court") public class CourtController { @Autowired private CourtService courtService; @GetMapping("/list") public Result list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) { return Result.ok(courtService.pageQuery(page, size)); } }Service 层调用分页插件,并返回 PageInfo 给 Controller:
@Service public class CourtServiceImpl implements CourtService { @Autowired private CourtMapper courtMapper; @Override public PageInfo<CourtVO> pageQuery(Integer page, Integer size) { PageHelper.startPage(page, size); List<CourtVO> list = courtMapper.selectCourtList(); return new PageInfo<>(list); } }Mapper 接口只有一行方法,真正干活的是对应的 XML:
public interface CourtMapper { List<CourtVO> selectCourtList(); }<select id="selectCourtList" resultType="com.court.vo.CourtVO"> SELECT id, name, location, image_url, description FROM court WHERE status = 1 ORDER BY id DESC </select>这里有一个细节:查询返回的是 CourtVO 而不是 Court 实体。VO 只带页面需要的字段,不会把 status 这类内部字段直接暴露给前端,后期如果要在列表里加“今日剩余场次数”,直接在 VO 里扩字段就行。PageHelper 的 startPage 必须紧跟第一条查询语句,中间不能有其他数据库操作,否则分页会串到别的查询上。
3.3 预约提交与冲突检测:用一条 UPDATE 抢占场次
预约提交是整个项目里最核心的业务。表面上是“插入一条预约记录”,但背后要处理并发问题:两个人同时提交同一个场次,不能两个都成功。常见做法是在 Service 层加 @Transactional 事务,把检查场次、锁定场次、写入预约这三步包在同一个事务里:
@Transactional(rollbackFor = Exception.class) public BookingVO submitBooking(BookingRequest req) { // 1. 校验场次存在且可约 Slot slot = slotMapper.selectById(req.getSlotId()); if (slot == null || slot.getStatus() != 0) { throw new BizException("该场次不可预约"); } // 2. 抢占场次:把 status 置为 1,防止并发下重复预约 int rows = slotMapper.lockSlot(req.getSlotId()); if (rows == 0) { throw new BizException("手慢了,场次已被抢走"); } // 3. 写入预约记录,初始状态为待审核 Booking booking = new Booking(); booking.setUserId(req.getUserId()); booking.setSlotId(req.getSlotId()); booking.setCourtId(slot.getCourtId()); booking.setStatus(0); bookingMapper.insert(booking); return buildVO(booking); }对应的 lockSlot 是整段代码的灵魂:
<update id="lockSlot"> UPDATE slot SET status = 1 WHERE id = #{slotId} AND status = 0 </update>这条 UPDATE 利用数据库行锁把“检查是否可约”和“锁定场次”合并成了一步。两个请求同时进来,数据库层面会串行执行,第一个请求更新成功返回 1,第二个请求再执行时 status 已经不是 0,影响行数为 0,事务回滚,返回“手慢了”。这里不要用先 SELECT 再 INSERT 的方式,因为两条语句之间有时间窗口,并发下必然会出现重复预约。
3.4 管理端接口:用拦截器控制管理员权限
管理端接口涉及审核、取消、统计,这些接口不能只靠前端隐藏按钮来保护。常见做法是写一个拦截器,拦截所有 /api/admin/ 开头的请求,从请求头里取 token,解析出用户 id,再查数据库确认角色是管理员:
public class AdminAuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("token"); Integer userId = TokenUtil.parseUserId(token); if (userId == null) { throw new BizException("登录已过期,请重新登录"); } User user = userMapper.selectById(userId); if (user == null || user.getRole() != 1) { throw new BizException("没有管理员权限"); } return true; } }然后在 spring-mvc.xml 里注册拦截规则:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/api/admin/**"/> <bean class="com.court.interceptor.AdminAuthInterceptor"/> </mvc:interceptor> </mvc:interceptors>普通用户接口不在拦截范围内,因为小程序首页、场地列表、提交预约这些操作,只要登录就能访问。拦截器只保护管理操作,token 在小程序启动时通过 wx.login 换取,后端拿到 code 后向微信接口换 openid,再生成自定义 token 返回给小程序。这个流程写成图放在论文里,能直接当“系统登录时序图”用。
4. 微信小程序端:页面结构、角色切换和预约流程
小程序端的目标是让用户能在手机上完成“看场地—选场次—提交预约—查看状态”的完整闭环,同时让管理员有一个简单的审核入口。
4.1 小程序目录结构与 tabBar:页面怎么划分
小程序页面按功能拆成四个:首页展示场地列表,预约页负责选场次和提交,我的页面展示个人预约列表,管理页做审核和场地维护。前两个页面放 tabBar,后两个用普通页面跳转进入:
{ "pages": ["pages/index/index", "pages/my/my"], "tabBar": { "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/my/my", "text": "我的" } ] } }预约页不放到 tabBar,因为它需要携带 courtId 参数进入,不同场地跳转到同一个预约页再动态加载场次,这是最省代码的做法。管理页同样做成普通页面,从“我的”页面里根据角色判断后显示入口。
4.2 预约提交页:日期选择、场次选择、提交校验
预约页的核心逻辑是:进入页面先加载未来七天的日期列表,默认选第一天;日期变化后重新请求该日期的场次列表;选中场次后点提交,调用后端接口。日期和场次分开加载,避免一次性拉回大量数据:
Page({ data: { courtId: null, dateList: [], slotList: [], selectedDate: '', selectedSlotId: null }, onLoad(options) { this.setData({ courtId: options.courtId }) this.loadDateList() this.loadSlotList() }, onDateChange(e) { this.setData({ selectedDate: e.detail.value, selectedSlotId: null }) this.loadSlotList() }, loadSlotList() { wx.request({ url: `${app.globalData.baseUrl}/api/slot/list`, data: { courtId: this.data.courtId, date: this.data.selectedDate }, success: (res) => { this.setData({ slotList: res.data.data }) } }) }, submit() { if (!this.data.selectedSlotId) { wx.showToast({ title: '请先选择场次', icon: 'none' }) return } wx.request({ url: `${app.globalData.baseUrl}/api/booking/submit`, method: 'POST', header: { token: app.globalData.token }, data: { slotId: this.data.selectedSlotId }, success: (res) => { if (res.data.code === 0) { wx.showToast({ title: '预约成功' }) wx.navigateBack() } else { wx.showToast({ title: res.data.msg, icon: 'none' }) } } }) } })baseUrl 放在 app.js 的 globalData 里,本地联调用 http://localhost:8080,真机调试时改成电脑的局域网 IP,这样环境切换只改一个文件。提交按钮前端只做“是否选中场次”的空值校验,真正的权限、场次状态、并发冲突都交给后端处理,前端校验只是体验层的提示。
4.3 我的预约与取消:状态展示与按钮逻辑
“我的预约”列表按状态展示文案:0 待审核、1 已确认、2 已取消、3 已完成。取消按钮要按状态控制,已经取消或已经完成的预约不能再次操作:
<button wx:if="{{item.status === 0 || item.status === 1}}" bindtap="cancelBooking" ><view wx:if="{{userInfo.role === 1}}"> <button bindtap="goAdmin">管理入口</button> </view>管理页分成两个区块:待审核预约列表和场地管理。审核操作就是调后端审核接口,传 bookingId 和审核结果,后端把状态改成 1 或 2。场地管理复用场地列表接口,加上新增、停用、编辑三个操作。这里的关键是,小程序端的管理入口只是 UI 层面的隐藏,真正防止越权的是后端拦截器,也就是 3.4 节做的那个拦截。
5. 从环境到部署:场地预约小程序避坑指南与最常见的 5 个坑
这一章写实际开发里最容易翻车的 5 个点,每一条都按“现象 → 原因 → 解决”来写,很多坑不是你逻辑写错,而是环境和配置的问题。
5.1 启动秒退:Tomcat 端口被占用
现象:Tomcat 启动后控制台直接报 BindException,或 IDE 提示端口被占用。原因大多是上一次运行没有正常停止,或者是本机其他程序占用了 8080。解决分两种:先查占用进程再决定是杀进程还是换端口。
netstat -ano | findstr 8080 taskkill /PID 12345 /F如果 8080 被系统服务占用不方便杀,也可以直接改 Tomcat 的 server.xml,把 Connector 的 port 改成 8081。注意改完以后,小程序端的 baseUrl 也要同步改成 8081,否则页面全部请求失败。这个坑的频率极高,但定位起来也最快。
5.2 MySQL 8 连接报“Public Key Retrieval is not allowed”
现象:项目启动时数据源初始化报错,控制台出现 Public Key Retrieval is not allowed。原因:MySQL 8 默认使用 caching_sha2_password 认证,JDBC 驱动第一次连接时需要从服务器获取公钥。解决方式是在连接串上补参数:
jdbc.url=jdbc:mysql://localhost:3306/court_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true这里 allowPublicKeyRetrieval=true 是关键。注意这个报错只在部分 MySQL 8 版本中出现,如果本地装的是 MySQL 5.7 或更早版本,一般不会遇到。出现这个错先别急着改代码,核对一下驱动版本和连接参数就够了。
5.3 真机连不上本地后端:小程序 request 一直 fail
现象:微信开发者工具里所有接口正常,点“真机调试”后全部请求失败,报错提示不是 url not in domain list 就是请求超时。原因:开发者工具允许访问 localhost,但手机上的小程序没有这个概念,必须通过局域网 IP 访问电脑上的后端。解决方法是:把 baseUrl 从 http://localhost:8080 改成 http://电脑局域网IP:8080/项目名,并在开发者工具的“详情 → 本地设置”里勾选“不校验合法域名”。开发阶段这个配置是常规操作。真正上线前再按平台的 HTTPS 域名要求处理,那是另一个阶段的事。
5.4 并发抢同一场次:数据库出现重复预约
现象:两个同学同时点同一个场次的“提交预约”,数据库里出现两条相同 slot_id 的预约记录。原因:先 SELECT 判断再 INSERT 的做法存在时间窗口,两个请求可能同时通过检查。解决方式就是 3.3 写的 lockSlot 方案,用一条 UPDATE 抢占场次。如果项目已经写成了先查后插,不用推倒重来,把这两步替换成 UPDATE 抢占,再把预约插入放到事务里就行。booking 表上的唯一索引 uk_slot_user 可以作为兜底防线,即使在极端情况下业务锁失效,数据库这一层也会拦住重复数据。
5.5 场地图片 404:静态资源映射没配
现象:数据库里 image_url 存的是 /upload/xxx.jpg,页面图片却显示不出来,浏览器直接访问也是 404。原因:Tomcat 不会把磁盘上的任意目录当成静态资源,图片文件虽然上传到了本地磁盘,但对外没有对应的 URL 映射。解决方式在 spring-mvc.xml 里加一行资源映射:
<mvc:resources mapping="/upload/**" location="file:D:/court-upload/"/>location 对应你实际保存图片的目录,Windows 下写法是 file:D:/court-upload/,Linux 下是 file:/home/court/upload/,结尾斜杠不能丢。改完配置重启 Tomcat,图片立刻能访问。这个坑几乎每个人都会踩一次,因为本地开发时文件明明存在,容易忽略 URL 映射这一环。
6. 从代码到毕业论文:验证方法、演示顺序和值得深挖的扩展
项目代码写完后,还有开题报告、毕业论文和视频演示要交。这一章把验收阶段的三个关键事项一次说清楚。
6.1 演示路线怎么排:先用户端、再管理端、最后看数据库
视频演示和答辩现场演示,顺序都很重要。我最常推荐的路线是:打开小程序首页展示场地列表 → 选一个未来场次提交预约 → 切到管理员账号审核通过 → 切回用户端看到状态变成已确认 → 最后打开数据库客户端,执行 SELECT * FROM booking,现场展示这条预约记录和状态字段。这一轮走完,前端、后端、数据库三个层面都有画面,老师想看的“数据是怎么流进去的”也有了着落。演示前记得用“未来日期”的场次,提前准备一个已完成的场次放在列表末尾,用来展示不同状态的界面差异。
6.2 并发抢场地的验证方法:两个账号同时提交
并发是这套毕设最容易讲出亮点的地方,验证方法也不复杂:准备两个账号,在两个窗口或两台手机同时点同一个场次的提交按钮。观察返回结果,应该只有一个成功,另一个提示“手慢了”。把这个过程录进视频演示,再配一句解释“这里用 UPDATE 影响行数来保证同一场次只被抢到一次”,直接解决了论文里“系统如何处理并发预约”这一节的素材问题。如果测试时发现两个都成功了,说明用的还是先查后插的老写法,按 5.4 的方法改掉。
6.3 从毕设到可运营系统:还差哪几块拼图
如果论文写完之后还想往“可上线”的方向走一步,需要补的东西集中在三块:把场次规则做成可配置,支持周末、节假日不同时段;把数据库锁换成分布式锁,支撑多实例部署;加一个预约成功后的通知机制。但注意,毕设的核心是“把主流程讲清、把状态流转讲闭合”,扩展方向列在论文末尾的展望里就够了,不要把大量篇幅花在还没实现的分布式方案上。我的习惯是开工前先在一页纸上把三张状态图画出来:预约状态流转、场次状态流转、用户角色关系,项目做完再回头对照,基本不会跑偏。希望帮到你。
本文还有配套的精品资源,点击获取