
简介OA会议系统源代码是一套面向开发者的办公自动化项目素材覆盖用户管理、会议创建审批、会议室预订与使用跟踪等核心业务适合需要学习Java Web分层开发、权限控制及LayUI前端集成的进阶学员开展课程设计、项目实训或二次开发。资源压缩包共203个文件大小约169.86MB以Java源码、class编译文件、JSP页面为主辅以JS、CSS、JAR依赖与各类配置文件较完整地呈现了后端业务逻辑、前端页面交互及项目构建方式目前已有190人浏览学习。通过研读代码可以理解DAO/Action分层、基于RBAC的权限管理思想以及会议从创建、审批到通知的全流程数据设计。同时可借助LayUI组件快速搭建系统管理界面并参考其目录结构学习企业级项目的组织方式与工程配置要点。资源还包含少量mp4演示或字体文件整体适合用于课程设计、源码研读或中小型企业内部系统原型开发。 做企业级OA系统绕不开的三大基础模块就是用户、会议、会议室。很多刚接手这套源代码的同学第一反应是“不就是增删改查吗”真正动手之后才发现用户模块要考虑权限边界和数据安全会议模块要理清状态流转和审批链路会议室模块还得处理资源冲突和并发预订哪一块都不省心。这篇博文就围绕一套完整的OA会议系统源代码做拆解讲清楚三大模块的数据模型、核心逻辑、实操要点和踩坑记录适合正在做办公系统开发、准备二次集成、或者面试前想系统梳理这类业务的人参考。1. 项目背景与整体设计思路1.1 为什么会议模块是OA系统的最佳切入点OA系统里会议属于高频、流程相对标准化的业务。它同时涉及企业最基础的三类数据用户谁开会、会议开什么会、会议室在哪开。把会议子系统做扎实就相当于把企业“人、事、物”的数据关系完整梳理了一遍。做源代码落地时我给自己定了三条硬性标准数据库表关系必须清晰状态流转必须可追踪接口权限必须可控。这三点不是口号而是后续所有开发工作的骨架。很多内部系统做到后期变得难以维护根源往往就是前期表设计混乱、状态字段随意扩展、权限校验靠“判断用户名是不是admin”等业务量上来再回头重构成本已经非常高。所以这篇博文也建议你先从数据模型和状态机入手不要急着写Controller。1.2 三大模块怎么拆分数据表怎么设计用户、会议、会议室三者关系可以概括为用户是主体会议是业务载体会议室是被调度的资源。对应到数据库核心表至少六张sys_user用户表主键、工号、姓名、手机号、邮箱、部门ID、状态。sys_dept部门表主键、父部门ID、部门名称、负责人。sys_role角色表与 sys_user_role用户角色关联表用于权限控制。meeting_room会议室表主键、名称、位置、容纳人数、设备配置、状态。meeting_booking会议预订表主键、会议主题、会议室ID、发起人ID、开始时间、结束时间、状态。meeting_participant会议参与人表主键、会议预订ID、用户ID、参会类型、确认状态。表名和字段名建议用统一前缀和命名规范业务表用meeting_开头基础表用sys_开头。团队协作时只看表名就能判断归属模块能省掉大量沟通成本。主键用BIGINT自增或雪花ID都可以时间字段统一用datetime状态字段用TINYINT预留扩展。有一点容易被忽略会议参与人表一定要保留独立的确认状态字段不能简单用“存在即参会”替代否则后续做“必选/可选/已确认/已拒绝”这类需求时只能被迫改表结构。2. 用户管理模块从增删改查到底层权限2.1 用户CRUD的核心细节与密码安全用户管理虽然只有“增删改查”四个字但写起来比想象中繁琐。新增用户时除了常规的姓名、工号、手机号、邮箱、所属部门还要处理密码初始化和唯一性校验。密码绝对不能明文入库推荐用BCrypt这类加盐哈希算法。它单向不可逆即使数据库泄露攻击者也没法直接拿到明文密码这也是源代码审计的重点检查项。删除用户这一块强烈建议做逻辑删除而非物理删除。因为历史会议记录里大量外键指向用户ID物理删除会导致会议参与人表出现悬空引用查历史会议时轻则显示异常重则直接报错。我的做法是在用户表加status字段0表示停用1表示正常。查询可用用户时统一过滤status1而历史记录里的关联查询不做过滤保证老数据完整可见。批量导入导出也是需求方经常点名的功能。导入时逐行校验工号格式、手机号格式、部门是否存在有一行失败就要回滚整个批次并返回具体行号错误原因。导出时注意不要导出密码哈希也不要把停用用户和正常用户混在一起不标注这些细节虽然小却是体验差异的关键。2.2 角色权限与组织架构怎么配合权限模型推荐用RBAC用户关联角色角色关联权限点。针对会议模块常见权限点是新增会议、审批会议、管理会议室、查看全部会议。用权限点控制接口和按钮比按角色写死要灵活得多。举个例子A部门主管和B部门主管都是“主管”角色但A部门主管不应该看到B部门的所有会议所以除了功能权限还要有数据权限的概念。组织架构上用parent_id做树形结构。查询“某个部门下所有用户”时不能只查当前部门还需要递归子部门或者用带有path字段的闭包表。实现上我建议直接维护一个dept_path字段例如“/1/12/123”查询时用LIKE prefix%匹配虽然牺牲了一点规范化但换来的是查询性能和数据一致性。这里有一个经验不要在代码里写死“管理员”三个字应该给管理员角色分配“全部权限”的角色数据然后通过角色标识判断。否则换一个人做管理员还得改动代码逻辑非常僵化。3. 会议管理模块核心流程与状态流转3.1 会议全生命周期怎么设计一个会议从创建到结束至少要经过草稿、待审批、已批准、已拒绝、已取消、已结束这些状态。状态机设计的好处是动作与状态一一对应不会出现“会议已经被拒绝还能通过修改重新生效”这类逻辑漏洞。状态流转是这样的用户新建会议后进入草稿提交审批后变成待审批审批人通过后变成已批准审批人拒绝后变成已拒绝。会议开始后自动标记为进行中结束后变成已结束。发起人可以在会议未开始时取消会议取消后资源随即释放会议室被腾空。这里还需要考虑超时作废如果待审批状态超过设定时限比如24小时没有被处理系统应该自动提醒审批人而不是让会议一直悬在那里。有一个容易忽略的设计是“修改会议”。已经审批通过的会议不允许直接编辑需要先撤销申请或者走重新申请流程生成新的版本。这样做的目的是保证与会人员看到的信息和审批人当时确认的信息一致避免“改了个时间参会人不知道”的尴尬。3.2 参会人设计与通知机制参会人用独立的meeting_participant表一个会议对应多条参与人记录这是典型的“一对多”关系。添加参会人时要做去重校验同一场会议不能重复添加同一人同时要过滤掉停用账号。查询“某用户今天有哪些会议”时直接通过参与人表关联会议预订表按时间排序返回即可。通知机制建议做成异步任务而不是在请求链路里同步发送。创建会议、会议变更、会议提醒三个节点各触发一次通知消息内容包含时间、地点、参会人变更等关键信息。通知渠道先预留站内信、邮件两种接口用策略模式封装后续要接企业微信或钉钉机器人只需要新增一个策略实现类不用改动原有调用逻辑。我实际开发中就是靠这个设计把通知模块的改造成本降到了最低。4. 会议室管理模块资源冲突才是真正的难点4.1 会议室资源建模会议室不是简单“名字位置容纳人数”的字段集合还要考虑设备能力比如投影仪、白板、视频会议终端。查询可用会议室时这些能力条件都要参与过滤。我的做法是把设备能力拆成独立字段每项用0/1表示是否支持而不是用逗号分隔字符串。因为用逗号拼接的“投影,白板”查询“支持投影的会议室”时SQL会写得很痛苦还要考虑匹配顺序问题。会议室有启用/停用状态停用中的会议室不能被新会议预订。这里有个容易踩的坑如果已经审批通过的会议发生在被停用会议室上怎么处理我的方案是停用前先做关联检查把未来N天已批准的会议列表拉出来由管理员逐个处理同时在审批会议时也校验会议室状态如果房间被停用会议自动进入“待重选”状态从源头上杜绝“会议照开、房间已锁”的乌龙。4.2 时间冲突检测算法与并发控制这是会议室模块最核心的算法。判断两个会议是否时间重叠标准条件是这样的新会议开始时间小于已有会议结束时间并且新会议结束时间大于已有会议开始时间。写成SQL就是SELECT COUNT(*) FROM meeting_booking WHERE room_id ? AND status IN (APPROVED, PENDING) AND start_time ? -- 传入新会议的结束时间 AND end_time ? -- 传入新会议的开始时间如果返回值大于0说明时间段被占用。这里要注意边界条件用小于、大于不能用小于等于、大于等于。否则一个会议14:00结束另一个会议14:00开始两个相邻会议会被误判为冲突。半开区间[开始, 结束)才是会议室预订的正确用法。并发场景下上面这条SQL存在竞态。两个请求同时查到“当前空闲”就会重复预订。解决办法是在事务里给会议室记录加上行锁BEGIN; SELECT * FROM meeting_room WHERE room_id ? FOR UPDATE; -- 再执行冲突检测 -- 没有冲突则插入会议记录 COMMIT;因为所有预订操作都先经过同一把“会议室锁”请求被强制串行化重复预订的问题就解决了。这里的关键是加锁和检测必须放在同一个事务里不能先查再开事务否则并发问题照样存在。5. 典型问题与排查实录5.1 高频问题速查表症状可能原因处理建议明明显示会议室空闲提交却提示冲突前端展示时段与后端提交时段不一致多为时区或日期格式化问题前后端统一用毫秒时间戳传参后端统一转服务器时区相邻两个会议被判定为冲突时间重叠判断用了或改成半开区间用和判断普通用户能看到全部会议列表接口缺少数据权限过滤查询条件增加“发起人当前用户 OR 参会人包含当前用户 OR 拥有管理权限”分支会议取消后会议室仍显示被占用只改了状态没有释放资源或前端列表没有过滤已取消状态确认状态变更逻辑前端按状态过滤查询修改会议后参会人没收到通知通知在事务提交前发出事务回滚后通知已外发用事务提交后的异步事件触发通知批量导入用户时报错却不知道哪行缺少逐行校验和错误定位导入时记录行号错误信息失败时整体回滚并展示明细5.2 印象比较深的几个坑第一个坑是逻辑删除引发的空指针。用户表做了逻辑删除之后历史会议记录里关联的创建人ID还指向这个用户但查询用户详情时查不到数据详情页直接报空指针。后来我统一封装了用户信息查询服务查不到数据时返回一个“已注销用户”的兜底对象页面显示“该用户已注销”而不是直接抛异常。第二个坑是会议室设备能力的存储方式。一开始图省事用逗号分隔字符串“投影,白板”后来做“支持投影的会议室”筛选时SQL写得非常痛苦。改成独立字段加布尔值之后查询逻辑瞬间清爽。第三个坑和源代码安全审计有关。接口层虽然做了权限校验但内部服务之间相互调用时偶尔存在绕过权限检查直连Service的情况。后来在代码评审阶段重点排查所有对外暴露的Controller入口统一加注解式鉴权同时对敏感操作增加了操作日志记录。注意涉及会议室预订这类写操作除了接口权限参数校验一定要做扎实。开始时间必须小于结束时间、预订时长不能超过合理上限、不能预订过去的时间。这些校验要放在冲突检测之前避免无效请求打到数据库。结尾一点个人体会这套系统我从前端页面到后端接口完整过了一遍最大的感受是OA系统的代码难度不在于某个算法有多高深而在于业务分支非常多状态与状态之间、模块与模块之间的耦合关系很容易被忽略。特别是会议室预订的并发控制如果只停留在“会写增删改查”的层面根本意识不到这里还藏着竞态问题。建议你拿到源代码后先画一遍数据模型和状态流转图再逐行看核心业务的Service层最后再动手改需求。这个过程走完你对“企业级开发”和“写Demo”之间的差距会有非常直观的认识。本文还有配套的精品资源点击获取