
简介基于微信小程序的软件学院会议室管理系统毕业设计资源包面向计算机相关专业毕业生及小程序/Java开发者针对会议室预订冲突、资源利用率低等实际场景提供一套可运行、可扩展的完整项目方案既可作为毕设参考也适合前后端结合的实践练习。压缩包共320个文件大小约61.59MB其中jar/class/java构成后端服务核心js/wxml/wxss/json承载小程序页面与配置sql为MySQL数据库初始化脚本mp4为操作演示视频另有png/jpg等界面素材目录类型划分清晰便于按需检索与定位。已有187人学习/下载。系统实际覆盖会议室预约、审批管理、用户管理、公告信息等业务模块前端页面与后端接口均已打通配合演示视频可快速完成环境搭建理解小程序与Java后端的通信方式以及数据库表结构设计对毕业设计答辩、代码二次开发和项目上线都有较高参考价值。1. 为什么“小程序 Java MySQL”是会议室管理系统毕业设计的稳妥选择毕业设计如果选的是微信小程序Java 的软件学院会议室管理系统它要解决的问题其实很朴素老师或学生打开小程序能看到会议室空闲还是被占提交一个时间段预约管理员在后台审批最后能统计每间会议室到底被用了多少。它不复杂却是一个完整的业务闭环小程序做展示层、Java 做业务层、MySQL 做存储层正好覆盖毕业设计要求的“有前端、有后端、有数据库、能演示”。这个题目难就难在“小程序和 Java 两边都有真实代码而数据库不是摆设”。会议室管理的核心不是界面多好看而是预约冲突怎么查、状态怎么流转、数据怎么不丢。把这个想清楚就算只看演示视频也能抓到项目骨架想不清楚源码跑起来也是表面通。下文按“拆系统 → 跑起来 → 踩坑 → 加分”的顺序写适合拿到源码包想快速复现、以及准备自己动手改一版的人。2. 拆解系统架构、数据库三张表和源码包的模块对应关系2.1 一次预约请求的完整链路从 wx.request 到 MySQL这个系统的常见做法是前后端分离微信小程序只负责页面和交互Java 后端以 Spring Boot 提供 HTTP 接口MySQL 负责最终存储。小程序端没有直连数据库的能力也不能直接执行 SQL所有数据都要先变成 JSON通过 wx.request 发给后端接口再由后端去操作数据库。一次“提交预约”的完整链路大致是小程序页面上选好会议室和时间段点击提交wx.request 发送 POST 请求到后端的 ReserveControllerController 接收 JSON 参数转成 DTO 对象不写任何业务逻辑直接丢给 ReserveServiceService 先做时间冲突检查再调用 Mapper 层往 t_reserve 表插入一条记录数据库执行成功后结果再逐层返回给小程序。后端入口代码大致长这样RestController RequestMapping(/api/reserve) public class ReserveController { Autowired private ReserveService reserveService; PostMapping(/add) public ResultBoolean add(RequestBody ReserveDTO dto) { return Result.success(reserveService.addReserve(dto)); } }逻辑说明RestController声明这是一个返回 JSON 的接口类RequestMapping(/api/reserve)定下接口根路径PostMapping(/add)接收 POST 请求RequestBody把小程序传来的 JSON 自动绑定到 ReserveDTO。Controller 层的职责只是“收参、调用、返回”业务判断放在 Service 层。Service 层更关键它负责预约冲突校验Override Transactional(rollbackFor Exception.class) public boolean addReserve(ReserveDTO dto) { int count reserveMapper.countConflict( dto.getRoomId(), dto.getReserveDate(), dto.getStartTime(), dto.getEndTime()); if (count 0) { throw new BizException(该时间段已被预约); } return reserveMapper.insert(dto) 0; }逻辑说明Transactional表示这个方法如果中途抛出异常数据库操作会整体回滚避免“查重通过了但插入失败”这类半截数据。countConflict是核心查询它按会议室、日期、开始时间和结束时间查重叠记录只要查到一条就拒绝预约。这个设计能挡住大部分重复预约也是答辩时最值得讲的一个点。2.2 数据库设计用户、会议室、预约三张核心表的字段与索引这类管理系统一般就三张核心表用户表、会议室表、预约记录表。用户表存 openid 和角色会议室表存房间基本信息预约表存“谁在什么时间用了哪个房间”。预约表是业务核心常见结构如下CREATE TABLE t_reserve ( id int NOT NULL AUTO_INCREMENT, user_id int NOT NULL COMMENT 预约人id, room_id int NOT NULL COMMENT 会议室id, reserve_date date NOT NULL COMMENT 预约日期, start_time time NOT NULL COMMENT 开始时间, end_time time NOT NULL COMMENT 结束时间, status tinyint NOT NULL DEFAULT 0 COMMENT 0待审批 1已通过 2已驳回 3已结束, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 提交时间, PRIMARY KEY (id), KEY idx_room_date (room_id, reserve_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT会议室预约记录表;参数说明reserve_date用 date 类型start_time和end_time用 time 类型不要混成 datetime否则同一天的预约判断会很别扭。idx_room_date是个联合索引因为冲突查询的 WHERE 条件永远是“某一天 某个会议室”用这个索引能让筛选直接在索引层完成不扫全表。status用 tinyint 而不是字符串省空间也方便扩展状态。会议室表建议加一个逻辑删除字段比如is_deleted。会议室一旦被删除历史预约记录还需要保留物理删除会把统计数据的根也删掉。用逻辑删除后老预约仍然能关联到房间名称只是新预约查不到这间房而已。这个细节在答辩时提一句“我做了逻辑删除而不是物理删除”比单纯背表结构有说服力得多。用户表最需要关注的是openid。微信小程序没有传统用户名密码用户身份来自微信登录后端通过 wx.login 拿到的 code 换取 openid再在用户表里查或建一条记录。首次登录自动注册后续请求通过 openid 识别用户身份。管理员的角色通常不是靠界面切换而是靠用户表里的role字段控制接口权限。2.3 源码包目录结构先认代码再动手拿到源码包不要急着启动。先看目录一般压缩包里有几个固定部分一个后端工程目录、一个微信小程序前端目录、一个数据库脚本文件还有一个演示视频。后端常见结构是backend ├── src/main/java │ ├── controller │ ├── service │ ├── mapper │ ├── entity │ └── config ├── src/main/resources │ ├── application.yml │ └── mapper └── pom.xmlcontroller 里是各类接口service 是业务逻辑mapper 是 MyBatis 的接口定义resources/mapper 下是 XML 映射文件config 里通常有跨域配置和拦截器配置。小程序端则看 pages 目录一般有 index会议室列表、detail预约页、my我的预约和个人中心这几个页面utils 目录里封装了 wx.request。演示视频是复现项目最好的线索。我一般建议先完整看一遍视频记下“打开小程序后先做了什么、管理员后台长什么样、数据大概怎么变化”再回源码里对着找对应页面和接口。视频里展示的流程就是项目作者验收时最稳妥的路径照它走一遍最容易排除环境问题。3. 把源码包从解压到跑通数据库、后端、小程序端的标准启动顺序3.1 用 IDEA 导入后端工程JDK、Maven 和配置文件检查先把 zip 解压到一个路径不含中文和空格的目录比如D:/work/meeting-room。直接解压到桌面“新建文件夹 (2)”这种路径容易触发编码和路径解析问题。用 IDEA 打开后端目录常见做法是菜单 File → New → Project from Existing Sources然后选中 backend 目录里的pom.xml以 Maven 项目方式导入。导入后第一件事不是点运行而是检查 Project Structure 里的 SDK 版本。这个项目一般基于 Java 8 或 Java 11如果本机装的是 Java 17先统一改成源码要求的版本。接着检查application.yml核心配置如下server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/meeting_room_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true参数说明serverTimezoneAsia/Shanghai解决 MySQL 连接时区偏差jackson.time-zoneGMT8解决返回前端的时间字段多 8 小时或少 8 小时。这两个配置经常只有一处被设置后面会发现时间对不上。map-underscore-to-camel-case开启后数据库的user_id能自动映射到 Java 的userId省掉大量手写映射。确认配置后运行主类里的 main 方法或直接用 Maven 启动cd D:/work/meeting-room/backend mvn spring-boot:run第一次运行会下载很多依赖如果卡特别久检查 Maven 是不是用了国内镜像。启动日志出现Tomcat started on port(s): 8080说明后端已经起来了。3.2 初始化 MySQL 数据库导入 SQL 脚本并验证表结构数据库脚本通常在压缩包的 db 或 sql 目录下文件名类似 init.sql。先用命令行导入mysql -u root -p D:/work/meeting-room/db/init.sql导入完成后用一条查询验证表是否建成功顺便看看初始化数据有哪些mysql -u root -p -e USE meeting_room_db; SHOW TABLES; SELECT id, nickname, role FROM t_user;如果能看到 t_user、t_room、t_reserve 这三张表并且 t_user 里有预置的管理员账号说明脚本执行正常。很多源码包会初始化一条管理员用户和几条会议室数据这是后面走通预约流程的基础。如果 MySQL 版本是 8 以上连接时驱动/URL 可能会报时区或公钥检索错误解决办法是在application.yml的连接串尾部追加url: jdbc:mysql://localhost:3306/meeting_room_db?...useSSLfalseallowPublicKeyRetrievaltrueallowPublicKeyRetrievaltrue是 MySQL 8 配合 caching_sha2_password 插件常见的参数不加会报 Public Key Retrieval is not allowed。3.3 用微信开发者工具打开小程序前端AppID 与本地请求开关微信开发者工具界面里选择“小程序项目”导入前端目录。AppID 可以直接选测试号不必自己注册小程序账号。项目导入后如果提示基础库版本过低把调试基础库调到与源码要求一致的版本即可。本地开发阶段必须把合法域名校验关掉否则请求会被拦截。位置在工具栏的“详情”→“本地设置”里勾选“不校验合法域名、web-view 业务域名、TLS 版本以及 HTTPS 证书”。这一项不勾任何http://localhost:8080的请求都会报错。找到小程序的utils/request.js把请求基础地址改为本机后端地址const BASE_URL http://localhost:8080 function request(path, method GET, data {}) { const token wx.getStorageSync(token) return new Promise((resolve, reject) { wx.request({ url: BASE_URL path, method, data, header: { Content-Type: application/json, ...(token ? { Authorization: token } : {}) }, success(res) { if (res.statusCode 200 res.data.code 200) { resolve(res.data.data) } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }) reject(res.data) } }, fail: reject }) }) } module.exports { request, BASE_URL }逻辑说明BASE_URL是所有接口的前缀后面对接时统一改这一个文件。wx.getStorageSync(token)是 read 本地缓存中的登录凭证有就放进请求头后端拦截器靠它识别当前用户。res.data.code 200表示后端返回的业务成功如果后端统一返回 Result 结构这里就只处理 data 部分。改完先看首页列表能不能加载出会议室。如果列表空白且控制台有报错优先检查后端是否真的启动、BASE_URL 是否写成了https或者是否漏关合法域名校验。3.4 用一条模拟预约走通全流程验证环境正常环境正常与否只看页面能打开不算数要完整走一遍“预约—审批—状态变化”的流程。照着演示视频的操作来一遍用普通用户身份进入首页选择一个会议室选明天某个时间段提交预约。提交后回到“我的预约”页面状态应该是“待审批”。此时去查数据库SELECT r.id, r.room_name, t.reserve_date, t.start_time, t.end_time, t.status FROM t_reserve t JOIN t_room r ON t.room_id r.id ORDER BY t.id DESC LIMIT 5;如果查不到刚提交的记录问题不在前端页面而是在后端请求或数据库连接。如果查到了但状态不对再检查 status 的映射有没有约定错。这条 SQL 也能直接验证预约是否落库比只在页面上看 toast 要可靠。确认落库后用管理员身份去审批这条预约。审批通过再回到用户端刷新“我的预约”状态从“待审批”变成“已通过”。一个完整的闭环走完后系统才算真正跑通后面再改代码也有一个可对比的基准。4. 项目复现与改造中的常见问题5 个高频坑的定位思路4.1 打开列表页空白请求返回 401前端身份凭证没对齐现象后端日志显示请求进入但返回 401页面列表一直是空的。原因多数这类系统在拦截器里校验 token 或 openid。前端没有登录成功就往接口发请求后端不认识这个用户直接拒了。解决用微信开发者工具看 Network 面板确认请求头里是否带上了Authorization或登录后的自定义字段。常见做法是在小程序app.js的onLaunch里先登录、再缓存凭证request.js从缓存读取并写入 header。如果登录逻辑没跑先单独触发登录接口再去请求列表。4.2 后端在跑小程序却报“url not in domain list”本地调试的合法域名开关现象后端已经启动Postman 调接口也正常但小程序点任何按钮都提示request:fail url not in domain list。原因微信开发者工具默认校验域名白名单http://localhost:8080不在合法域名范围里。真机上必须使用备案过的 HTTPS 域名本地开发则要靠开发者工具的开关绕过。解决工具栏详情 → 本地设置 → 勾选“不校验合法域名”。如果演示要放到手机上跑后端需要部署到带 HTTPS 的服务器把线上域名加到小程序后台的 request 合法域名里。毕业答辩如果只是在教室演示开发者工具的模拟器完全够用不需要折腾公网部署。4.3 同一间会议室被重复预约冲突查询漏掉了待审批状态现象时间接近的两条预约记录同时存在会议室使用记录重叠。原因冲突检查的 SQL 只判断了status 1已通过忽略了“待审批”状态的记录。用户先提交了一条待审批再提交一个重叠时间两次都不撞上已通过记录于是被放行。解决冲突查询要把“待审批”和“已通过”都纳入范围用status IN (0, 1)。更重要的是时间重叠的判断条件常见写法是SELECT COUNT(*) FROM t_reserve WHERE room_id #{roomId} AND reserve_date #{date} AND status IN (0, 1) AND start_time #{endTime} AND end_time #{startTime}逻辑说明start_time 新结束时间 AND 新开始时间 end_time这个交集条件是判断重叠的标准写法既能挡掉完全重合也能挡掉部分重叠。边界情况如已有 10:00–12:00新预约 12:00–14:00因为12:00 12:00不成立视为不冲突允许背靠背预约这是符合实际使用习惯的。4.4 预约时间显示相差 8 小时时区配置要从两头统一现象页面上显示某条预约开始时间是凌晨 02:00但数据库里明明是 10:00。原因时区配置不一致。MySQL 连接串里的serverTimezone和 Jackson 的time-zone至少有一处没设或者设置成了不同值导致时间在存取过程中被往返转换。解决把application.yml里的 JDBC URL 改为serverTimezoneAsia/ShanghaiJackson 配置改为time-zone: GMT8。改完重启后先删掉测试数据再重新提交一条预约验证显示。已存在的脏数据不会自动修正直接手动调整或重建记录。4.5 管理后台拉取列表报跨域CORS 配置没放在后端现象Postman 调后端接口正常但浏览器管理后台或某个 Web 端管理页面请求时报No Access-Control-Allow-Origin header is present。原因浏览器同源策略拦截了跨域请求。微信小程序本身不受这条规则限制但管理后台如果是用浏览器打开的就必须由后端允许跨域。解决在后端加一个统一的 CORS 配置Configuration public class WebConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*); } }逻辑说明addMapping(/api/**)只对接口路径开放跨域allowedMethods要包含OPTIONS因为浏览器会在正式请求前发一个预检请求。毕业设计做本地演示allowedOrigins(*)可以接受如果后续要严一点可以改成具体的前端地址。5. 让答辩更稳的进阶收尾冲突约束、定时状态和统计报表5.1 把时间重叠检测收敛成同一个方法前文提到的冲突 SQL不要在每个接口里各写一遍。后端可能同时存在小程序端提交、管理员代订、修改预约时间这三个入口三处各自写冲突查询很容易只改了一处漏了另一处。更稳的做法是在 Service 层抽一个公共方法入参是会议室 id、日期、开始时间、结束时间所有入口统一调用。加这个方法后再遇到重复预约这类 bug只需要改一处 SQL 和一处判断逻辑其余入口全部生效。这也是答辩时能直接讲出来的“复用设计与一致性保障”。5.2 用一个定时任务自动把过期预约置为已结束会议室预约的“已结束”状态在很多源码里是靠手动改库或人工操作的这不合理。给后端加一个定时任务是体面的加分项Component public class ReserveStatusTask { Scheduled(cron 0 5 0 * * ?) public void autoCloseExpired() { reserveMapper.updateStatusByEndTime(LocalTime.now()); } }参数说明0 5 0 * * ?表示每天凌晨 00:05 执行。业务含义是把所有“已通过”且结束时间早于当前时间的预约记录统一更新为“已结束”。启动类上要加EnableScheduling这个注解容易漏漏了定时任务不会执行但也不报错属于典型的“没报错但不生效”问题。5.3 “使用率统计”只要 DATE 过滤和 GROUP BY 就够撑起功能亮点会议室管理系统如果能给出一张“每月各会议室使用时长”的统计展示价值会明显高于单纯的增删改查。实现不复杂一条 SQL 就能汇总SELECT DATE_FORMAT(reserve_date, %Y-%m) AS ym, room_id, COUNT(*) AS reserve_cnt, SUM(TIMESTAMPDIFF(MINUTE, start_time, end_time)) / 60 AS reserve_hours FROM t_reserve WHERE status 1 AND reserve_date #{startDate} GROUP BY ym, room_id逻辑说明DATE_FORMAT(reserve_date, %Y-%m)把日期归一成月份TIMESTAMPDIFF(MINUTE, start_time, end_time)计算每次预约的分钟数再转成小时。拿到这个结果后管理端画柱状图或饼图都很容易。我在做类似项目时最后一步往往不是加功能而是把演示视频重新走一遍确保刚才改过的代码没把老流程搞坏。这个习惯帮我躲过不少答辩前夜的翻车。希望帮到你。本文还有配套的精品资源点击获取