ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SSM+MySQL线上会议管理系统毕业设计:时间冲突检测与权限控制实战

SSM+MySQL线上会议管理系统毕业设计:时间冲突检测与权限控制实战 简介这份毕业设计资源包围绕中小型公司线上会议预约场景展开采用Java MVC模式与MySQL关系型数据库构建了前端加后端的会议管理系统适合计算机相关专业学生作为毕业设计参考也适合需要SSM实战练手的开发者。系统涵盖部门管理、会议室管理、公告管理与预约管理等核心模块并配有注册登录、后台管理等辅助功能论文部分包含系统实现与测试章节涉及开发环境、首页、预约、用户、公告及登录注册等测试用例。资源包共2000个文件约150.8MB以js脚本、json配置、jsp页面、css样式、java源码、html页面和xml配置为主另含sql建库脚本与docx论文文档结构完整便于按模块查阅。目前已有108人学习下载读者可获取源码、数据库脚本、论文与演示视频快速理解SSM项目分层与预约业务实现思路。1. 线上会议管理系统从 SSM 到 MySQL 的毕业设计落地路径线上会议管理系统这个题目在计算机毕业设计里属于典型的“业务不复杂、但技术栈必须完整”的类型。它要解决的核心问题很具体用户注册登录后能创建会议、邀请参会人、管理会议状态管理员能审核用户和会议。听起来像是一个 CRUD 项目但真正动手做的时候你会发现权限模型、时间冲突检测、状态流转这三块才是拉开差距的地方。SSM 框架配合 MySQL 是这类系统最常见的组合Spring 负责业务对象管理和事务SpringMVC 处理请求路由和参数绑定MyBatis 做数据持久化。适合谁做适合已经学过 JavaWeb、能写基本 Servlet 和 JSP、但对框架整合还没有完整跑通过一遍的本科生。这篇文章不讲空泛的架构图而是把从建库到接口联调的完整路径拆开让你能照着复现一个能跑、能演示、能写进论文的系统。2. SSM 整合与 MySQL 建库先把地基打对2.1 为什么选 SSM 而不是 SpringBoot很多同学一上来就想用 SpringBoot觉得省事。但毕业设计答辩时老师往往会问“Spring 的 IOC 和 AOP 在这个项目里怎么体现的”。如果你用 SpringBoot自动配置把很多东西藏起来了你反而说不清楚。SSM 虽然配置多但每一步都是显式的你亲手写过applicationContext.xml里的数据源、事务管理器、MyBatis 的SqlSessionFactory答辩时就能指着配置文件讲清楚依赖注入和事务边界的实际位置。另一个现实原因是SSM 的教程和现成代码模板在各类资源站上最多遇到问题容易搜到答案。MySQL 版本选择上5.7 和 8.0 都可以但 8.0 的驱动类名和连接 URL 参数有变化很多老教程用的是 5.7 的写法直接抄会报Communications link failure。我一般建议用 MySQL 5.7.44 或者 8.0.33这两个版本在 Windows 和 Linux 上的安装包都容易找社区问答也最丰富。2.2 数据库表设计五张核心表就够线上会议管理系统的表不用多但字段要想清楚。下面是我实际用过的建表语句直接可以在 MySQL 里执行-- 用户表区分普通用户和管理员 CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 登录名, password varchar(64) NOT NULL COMMENT MD5加密存储, real_name varchar(50) DEFAULT NULL, role tinyint(1) NOT NULL DEFAULT 0 COMMENT 0-普通用户 1-管理员, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 1-正常 0-禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 会议表核心业务表 CREATE TABLE meeting ( id int(11) NOT NULL AUTO_INCREMENT, title varchar(100) NOT NULL, room_id int(11) NOT NULL COMMENT 关联会议室, organizer_id int(11) NOT NULL COMMENT 发起人, start_time datetime NOT NULL, end_time datetime NOT NULL, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0-待审核 1-已通过 2-已拒绝 3-已结束, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_room_time (room_id,start_time,end_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 会议室表 CREATE TABLE room ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(50) NOT NULL, capacity int(11) NOT NULL DEFAULT 10, location varchar(100) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 参会人关联表 CREATE TABLE meeting_attendee ( id int(11) NOT NULL AUTO_INCREMENT, meeting_id int(11) NOT NULL, user_id int(11) NOT NULL, join_status tinyint(1) DEFAULT 0 COMMENT 0-未确认 1-已确认, PRIMARY KEY (id), UNIQUE KEY uk_meeting_user (meeting_id,user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 操作日志表答辩加分项 CREATE TABLE operation_log ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) DEFAULT NULL, action varchar(200) DEFAULT NULL, ip varchar(50) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;meeting表上的idx_room_time联合索引是关键。后面做时间冲突检测时查询条件是room_id ? AND start_time ? AND end_time ?没有这个索引数据量一上来就会全表扫描。meeting_attendee表的唯一键防止同一个人被重复邀请。operation_log表不是必须的但加上之后答辩时演示“管理员查看操作记录”会显得系统更完整。2.3 SSM 配置文件的最小可用集合SSM 整合需要四个配置文件web.xml、spring-mvc.xml、applicationContext.xml、mybatis-config.xml外加一个jdbc.properties。这里不贴全部内容只说三个最容易配错的地方。第一web.xml里ContextLoaderListener和DispatcherServlet的contextConfigLocation要分开。前者加载applicationContext.xmlService 和 DAO 层后者加载spring-mvc.xmlController 层。如果都塞进一个文件事务注解会失效因为 Spring 容器和 SpringMVC 容器各扫各的包事务代理对象在 Controller 里拿不到。第二applicationContext.xml里扫描 Service 包时要排除 Controller 注解context:component-scan base-packagecom.example.service context:exclude-filter typeannotation expressionorg.springframework.stereotype.Controller/ /context:component-scan第三MyBatis 的mapperLocations路径要用classpath*:开头否则打包成 war 之后 XML 映射文件可能找不到。提示MySQL 8.0 的驱动类是com.mysql.cj.jdbc.DriverURL 要加serverTimezoneAsia/Shanghai否则插入 datetime 字段会报时区错误。3. 会议创建与时间冲突检测业务逻辑的核心3.1 时间冲突检测的 SQL 写法这是整个系统里唯一需要动脑子写 SQL 的地方。判断一个会议室在某个时间段是否已被占用逻辑是存在一条记录它的开始时间早于新会议的结束时间且结束时间晚于新会议的开始时间。用 SQL 表达SELECT COUNT(*) FROM meeting WHERE room_id #{roomId} AND status IN (0, 1) AND start_time #{endTime} AND end_time #{startTime}注意status IN (0, 1)只检查待审核和已通过的会议已拒绝和已结束的不算占用。这个条件如果漏了已结束的会议会一直阻塞新会议创建用户会以为系统坏了。对应的 MyBatis Mapper 接口和 XML// MeetingMapper.java int countConflict(Param(roomId) Integer roomId, Param(startTime) Date startTime, Param(endTime) Date endTime);!-- MeetingMapper.xml -- select idcountConflict resultTypeint SELECT COUNT(*) FROM meeting WHERE room_id #{roomId} AND status IN (0, 1) AND start_time lt; #{endTime} AND end_time gt; #{startTime} /selectService 层调用时如果返回值大于 0就抛出自定义异常TimeConflictExceptionController 捕获后返回“该时间段会议室已被占用”的提示。3.2 会议状态流转与权限控制会议状态有四个待审核、已通过、已拒绝、已结束。状态流转规则是普通用户创建后为待审核管理员审核通过变为已通过拒绝变为已拒绝已通过的会议在结束时间过后由定时任务或手动操作变为已结束。这里有一个容易翻车的地方普通用户不能直接修改status字段。如果 Controller 接收前端传来的完整 Meeting 对象直接 update恶意用户可以把 status 改成 1 绕过审核。正确做法是在 Service 层做字段级控制public void updateMeeting(Meeting meeting, Integer currentUserId, boolean isAdmin) { Meeting existing meetingMapper.selectById(meeting.getId()); if (!isAdmin !existing.getOrganizerId().equals(currentUserId)) { throw new PermissionDeniedException(无权修改此会议); } if (!isAdmin) { // 普通用户只能改标题、时间、参会人不能改状态 existing.setTitle(meeting.getTitle()); existing.setStartTime(meeting.getStartTime()); existing.setEndTime(meeting.getEndTime()); meetingMapper.updateById(existing); } else { meetingMapper.updateById(meeting); } }这段代码的逻辑是先查原记录判断当前用户是否有权限普通用户只允许更新部分字段管理员才能全量更新。参数currentUserId从 Session 中获取不要从前端传否则可以伪造。3.3 参会人邀请的批量插入邀请参会人时前端传过来一个userId列表后端需要批量插入meeting_attendee表。用 MyBatis 的foreach标签insert idbatchInsertAttendees INSERT INTO meeting_attendee (meeting_id, user_id, join_status) VALUES foreach collectionlist itemitem separator, (#{item.meetingId}, #{item.userId}, 0) /foreach /insert参数说明collectionlist对应 Mapper 接口中ListMeetingAttendee类型的参数。如果接口方法有多个参数需要用Param指定名称collection也要改成对应的名称。批量插入时如果列表中有一条重复的(meeting_id, user_id)整个插入会失败并回滚。所以 Service 层要先查一遍已存在的参会人过滤掉重复的再插入。4. 避坑与排查那些答辩前夜才发现的错误4.1 中文乱码从数据库到前端全链路现象会议标题在数据库里看是正常的但页面上显示问号。原因MySQL 连接 URL 没有指定字符集或者 Tomcat 的server.xml里 Connector 没有加URIEncodingUTF-8。解决JDBC URL 加上useUnicodetruecharacterEncodingutf8Tomcat Connector 加上URIEncodingUTF-8数据库和表的字符集统一用utf8mb4。三个地方缺一不可。4.2 事务不生效导致数据不一致现象创建会议时会议记录插入成功但参会人插入失败数据库里留下了一条没有参会人的会议。原因Service 类的方法上没有加Transactional或者加了但方法不是 public或者异常被 catch 了没有重新抛出。解决在 Service 类的创建方法上加Transactional(rollbackFor Exception.class)确保任何异常都触发回滚。注意rollbackFor要显式写Exception.class因为 Spring 默认只对RuntimeException回滚。4.3 MyBatis 的#{}和${}用混现象按标题模糊查询时输入%导致查出全部记录。原因XML 里用了${}拼接而不是#{}预编译。解决模糊查询用CONCAT(%, #{keyword}, %)不要用%${keyword}%。${}只用在动态表名或排序字段这种无法预编译的场景并且要在 Java 层做白名单校验。4.4 时间字段前后端格式不一致现象前端传2024-01-01 10:00:00后端接收时报Cannot deserialize value of type java.util.Date。原因SpringMVC 默认不支持这种格式的字符串转 Date。解决在 Controller 的日期参数上加DateTimeFormat(pattern yyyy-MM-dd HH:mm:ss)或者在spring-mvc.xml里注册全局的FormattingConversionServiceFactoryBean。如果用的是RequestBody接收 JSON则需要在实体类的日期字段上加JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8)。4.5 部署到 Tomcat 后 404现象本地 Eclipse 里跑得好好的导出 war 包放到 Tomcat 的webapps目录下启动访问就是 404。原因web.xml里DispatcherServlet的url-pattern配的是/但 SpringMVC 的视图解析器前缀写的是/WEB-INF/jsp/而 JSP 文件没有一起打包进去。解决检查 war 包里的目录结构确保 JSP 文件在WEB-INF/jsp/下。另一个常见原因是applicationContext.xml里的包扫描路径写的是com.example但实际代码包名是cn.example导致 Bean 没有创建。5. 从能跑到能演示三个提升完成度的技巧5.1 用拦截器做登录校验和操作日志登录校验不要在每个 Controller 方法里写if (session.getAttribute(user) null)。写一个HandlerInterceptor在preHandle里统一判断然后在spring-mvc.xml里配置拦截路径和排除路径。操作日志也可以在拦截器里做postHandle中拿到请求的 URL 和当前用户异步插入operation_log表。这样答辩时演示“管理员查看操作日志”就有真实数据而不是手动往数据库里塞几条。public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String uri request.getRequestURI(); // 登录页和静态资源放行 if (uri.contains(/login) || uri.contains(/static/)) { return true; } Object user request.getSession().getAttribute(currentUser); if (user null) { response.sendRedirect(request.getContextPath() /login); return false; } return true; } }参数说明preHandle返回false时请求会被中断后续的 Controller 不会执行。response.sendRedirect的路径要加上request.getContextPath()否则部署到非根路径下会跳转错误。5.2 会议列表分页用 PageHelper不要自己写LIMIT和COUNT两条 SQL容易算错总页数。引入 PageHelper 插件在 MyBatis 配置里加一行plugins plugin interceptorcom.github.pagehelper.PageInterceptor property namehelperDialect valuemysql/ /plugin /plugins然后在 Service 里调用PageHelper.startPage(pageNum, pageSize)紧接着执行查询返回的List会被自动包装成PageInfo对象里面包含总记录数、总页数、当前页数据。注意startPage之后必须紧跟查询语句中间不能插入其他数据库操作否则分页参数会作用到错误的查询上。5.3 演示视频的录制节奏如果毕设要求提交演示视频不要从头到尾录一遍操作。按这个顺序录先展示登录和角色区分普通用户和管理员看到不同菜单再展示创建会议和时间冲突提示然后展示管理员审核和参会人确认最后展示操作日志和数据库表数据。每个环节控制在 30 秒以内总时长 3 到 5 分钟。录制前把数据库里的测试数据准备好避免现场创建时因为时间冲突反复失败。我自己的习惯是提前跑一遍完整流程把每一步的点击位置记在纸上录的时候照着点一次过。希望帮到你。本文还有配套的精品资源点击获取
返回列表