☰
基于SSM和MySQL的公开课记录管理系统设计与实现详解
2026/10/13 7:36:03 网站建设 项目流程

在各类课程设计与毕业设计中,"基于 javaweb 和 mysql 的 ssm 公开课记录管理系统" 是一个非常典型、又很容易写崩的项目。很多同学一听到 SSM 就开始慌,以为是三个框架叠加,实际上拆开之后就是一个 Spring 管对象、SpringMVC 管请求、MyBatis 管数据库访问的常规组合。这个项目真正的难点不在框架本身,而在于怎么把"公开课记录"这个业务逻辑理清楚:谁开课、谁记录、记录什么、怎么查、怎么统计。如果这些业务边界都没有划清,代码写得再花哨,最终运行起来也是一团乱麻。

如果你正要动手做这个项目,或者正在参考类似的课程设计,这篇内容会从项目设计、技术选型、数据库建表、核心模块实现到常见踩坑逐一拆开讲,尽量把每一步背后的"为什么"也说清楚,而不是只丢一段能跑的代码让你照抄。

1. 项目整体设计与功能思路拆解

1.1 这个项目到底算哪一类业务系统

公开课记录管理系统本质上是"信息管理类"Web 应用,跟图书管理、课时管理、会议记录管理属于同一大类。这类系统的核心操作无非就是围绕一张或多张业务表做增删改查,外加一些统计、筛选和权限控制。所以,先别急着写代码,先把业务模型想明白。

"公开课"这个词在这里指的是学校或培训机构开设的对外开放的课程,它本身有一个课程档案,比如课程名称、授课教师、上课时间、上课地点、课程简介、开放名额等。而"记录"就是围绕这门课产生的听课记录或授课记录,比如哪天开的课、谁来讲的、实际来了多少人、现场反馈怎么样、课程是否结束、有没有异常情况。因此系统至少要有两个核心实体:课程信息和课程记录。很多同学做这个项目时,只建了一张表,所有字段堆在一起,结果后面改需求时痛不欲生。

另外还要考虑用户角色。通常这类系统至少要有管理员和普通用户(教师或记录员)两种角色。管理员负责课程分类管理、用户管理、统计报表;普通用户负责录入公开课信息、维护听课记录。也可以在角色上再加一层"访客",只允许查看已开放的课程和记录,但不能修改。角色的区别最终要落到权限控制上,也就是登录之后,不同的人看到的菜单和能做的操作不一样。

1.2 技术选型背后的真实考量

标题里写得清清楚楚:Java + SSM + HTML + JavaScript + JSP + MySQL。这套组合在当前的本科课程设计里非常常见,你可能会问既然都 2025 年了,为什么不直接上 Spring Boot?原因很现实:

  • 教学体系里仍然大量使用 SSM 作为入门框架组合,因为这能让你分别理解"控制反转""依赖注入""面向切面""请求映射""SQL 映射"这些概念,而不是被 Spring Boot 的自动配置一揽子带过。
  • 课程设计的验收老师往往要看"你是否理解框架之间的调用关系",SSM 的手动配置反而更能体现你的掌握程度。
  • 很多学校机房的环境仍然停留在 JDK 8 + Tomcat 8 的级别,SSM + JSP 的项目部署起来兼容性最高,不容易因为环境问题翻车。
  • JSP 作为视图层,在本地开发调试时非常直观,不需要前后端分离,一个 WAR 包丢进 Tomcat 就能跑,省去构建前端工程、配置跨域等额外步骤。

所以如果这不是生产级项目,而是一个课程设计或者个人练手项目,用 SSM 完全合理,甚至比用 Spring Boot 更贴近教学目标。

1.3 功能模块划分与页面规划

在开始建表之前,先把功能模块画清楚。基于公开课记录管理的业务,我建议按下面这几个模块来切:

  • 登录与权限模块:用户名密码登录,Session 中记录当前用户基本信息和角色编码,拦截器统一做登录校验和角色校验。
  • 课程信息管理模块:公开课的档案信息维护,包括新增公开课、编辑公开课、下架公开课、按条件查询公开课。
  • 听课/授课记录模块:记录员在课程实际开展后填写记录,包括到场人数、课程反馈、发生时间等,支持记录的增加、修改、删除和查阅。
  • 分类统计模块:按教师、按月份、按课程类型统计公开课的开课次数和覆盖人数,一般用图表或简单统计表展示。
  • 用户管理模块:管理员维护系统用户,重置密码,启停账号。

对应的 JSP 页面大概有:登录页 login.jsp、首页 index.jsp、课程列表 courseList.jsp、课程编辑 courseForm.jsp、记录列表 recordList.jsp、记录编辑 recordForm.jsp、统计页面 statistic.jsp、用户管理 userManage.jsp。这些页面足够覆盖主要功能点,也不会让工作量膨胀到做不完。

2. 数据库设计:这个系统的地基

2.1 建表思路与字段设计

数据库是整个系统的重中之重,很多代码层面的 bug 其实源头在表结构不合理。以公开课记录管理为例,我建议至少建五张表:用户表、角色表(如果想简化,可以把角色字段直接放进用户表)、课程分类表、公开课信息表、公开课记录表。

用户表和角色表这个不多说,重点看业务表。公开课信息表大概长这样:

course_info id BIGINT 主键自增 course_name VARCHAR 课程名称 course_type INT 关联分类表 teacher_name VARCHAR 授课教师 course_time DATETIME 开课时间 location VARCHAR 上课地点 introduction TEXT 课程简介 max_people INT 开放名额 status INT 状态:1 报名中 2 已结束 0 已下架 creator_id BIGINT 创建人ID create_time DATETIME 创建时间 update_time DATETIME 更新时间

公开课记录表:

course_record id BIGINT 主键自增 course_id BIGINT 关联课程ID record_date DATETIME 记录日期 actual_number INT 实际到场人数 feedback TEXT 课堂反馈 record_user_id BIGINT 记录人 record_time DATETIME 记录时间

两张业务表拆开之后,你会发现查询会变得很舒服:查课程列表用第一条,查记录明细用第二条,记录数变化的时候也不需要回写课程表,统计的时候用 GROUP BY 聚合即可。

2.2 外键与索引设计的取舍

关于外键,我的建议是:表结构逻辑上有关联,但物理上不建 FOREIGN KEY 约束。原因很现实,在做课程设计时删除数据的逻辑经常需要"删课程连带删记录"或"标记删除"等操作,物理外键会让 MySQL 在删除阶段频繁报错,处理起来反而增加复杂度。逻辑外键配合 MyBatis 的关联查询足够用。

索引方面,公开课信息表的 course_time、teacher_name、course_type 这三个字段在查询条件中出现的频次最高,建议加普通索引。公开课记录表的 course_id 建议加索引,因为统计类 SQL 几乎都要靠它做 JOIN 和 GROUP BY。添加索引的操作可以直接写在建表语句的后面,也可以后期用 ALTER TABLE 补上。

2.3 初始化数据与字符集注意点

数据库统一使用 utf8mb4 字符集,排序规则用 utf8mb4_general_ci。一开始就定好,后面就不会出现中文乱码的怪问题。初始化数据至少要有管理员账号和测试用户各一个,密码建议用 MD5 或 SHA-256 加密后存储。课程分类比如"校内公开课""企业公开课""竞赛辅导课"先预置三条。这样项目启动之后登录进去就有内容可看,展示效果比空表好很多。

3. SSM 框架整合与核心配置解析

3.1 Maven 依赖与版本匹配

用 Maven 构建项目,pom.xml 里最核心的依赖就是 spring、springmvc、mybatis、mysql-connector-java、druid 连接池、jstl、servlet-api 和 jackson(后续做 JSON 交互时会用到)。版本之间要注意匹配关系,我实测过一套比较稳的组合:

  • Spring 5.2.15.RELEASE
  • MyBatis 3.5.6
  • mybatis-spring 2.0.6
  • MySQL Connector/J 8.0.26
  • Druid 1.2.8
  • JSTL 1.2
  • Jackson 2.12.5

如果你们学校环境里装的是 JDK 8,这套版本组合完全能跑。注意 mysql-connector-java 8.x 的驱动类名是 com.mysql.cj.jdbc.Driver,不是旧的 com.mysql.jdbc.Driver,这一处经常有人写错,导致启动时连接数据库直接失败。

3.2 Spring 与 SpringMVC 的配置分工

SSM 整合最典型的做法是配置三个 XML:applicationContext.xml、spring-mvc.xml、mybatis-config.xml(也可以把 MyBatis 配置合并到 Spring 配置里)。分工如下:

  • applicationContext.xml 负责数据源、SqlSessionFactory、事务管理、Service 层注解扫描。
  • spring-mvc.xml 负责 Controller 层扫描、视图解析器、静态资源放行、JSON 消息转换器。
  • mybatis-config.xml 负责别名定义、驼峰命名映射等全局配置。

有一个高频坑记录一下:千万别在 Spring 的容器里扫描 Controller,也别在 SpringMVC 的容器里扫 Service,否则轻则多实例化一遍,重则事务失效。用 context:component-scan 的 use-default-filters 配合 exclusion 可以精准控制扫描范围。

3.3 MyBatis 的 Mapper 编写与 XML 映射

MyBatis 使用 Mapper 接口加 XML 文件的方式,SQL 与 Java 代码完全解耦。基础的单表增删改查可以直接用注解,但涉及到多表关联查询、动态 SQL 过滤时,还是要用 XML。课程列表的查询经常会有多个查询条件叠加的情况,例如按课程名称模糊查询、按分类筛选、按时间范围筛选,这时候在 Mapper XML 中用 where 标签配合 if 标签拼 SQL,灵活度和可读性都高很多。统计模块的 SQL 用 GROUP BY 加 COUNT、DATE_FORMAT 处理月份聚合,这些在 XML 里写起来也直观。

一个细节建议:为所有列表查询接口都加上分页。最简单的方式是用 PageHelper 插件,在 pom 里引入 pagehelper-spring-boot-starter 或者 pagehelper 对应 SSM 的版本,然后只需要在 Service 层调用 PageHelper.startPage(pageNum, pageSize),紧随其后的查询就会自动分页。这个插件用起来非常简单,能省掉大量手写 LIMIT 和 count 查询的工作。

4. 核心模块的实操过程:从零到跑通

4.1 登录模块与拦截器权限控制

登录功能看起来简单,但它是整个系统的门面,也是拦截器链路的起点。操作步骤建议按下面的流程走:

  1. 登录页提交用户名和密码,Controller 层接收参数。
  2. Service 层调用 Mapper 根据用户名查询用户信息,比对密码(数据库中存的是加密后的密文,比对时对入参做同样的加密算法处理)。
  3. 登录成功后,把 userInfo 对象和 role 编码放入 HttpSession。
  4. 在 spring-mvc.xml 中注册拦截器,配置拦截路径为 /admin/、/course/、/record/** 等需要登录的路径,放行路径包括 /login、/logout、/static/** 等。
  5. 拦截器的 preHandle 方法中检查 Session 是否存在,不存在则重定向到登录页,存在但角色不匹配则返回无权限页面。

需要注意:JSP 页面本身也可以直接用 EL 表达式读取 Session 里的用户信息来渲染导航菜单,例如判断 role 是不是管理员来显示"用户管理"入口。

4.2 公开课管理模块的完整实现

公开课管理模块是这个系统的核心,我个人建议用列表页 + 表单页的经典模式来做,不要一上来就上 Bootstrap 的模态框 Ajax 弹窗编辑,因为模态框会牵涉到大量的 JS 传值、异步刷新和表单校验,调试工作量翻倍。课程设计的验收看的重点是功能是否完整,操作是否顺畅,模态框并不是加分必需项。

列表页的实现思路:

  • 页面加载时发起查询请求,Controller 层接收 pageNum、pageSize、课程名称、分类、状态等参数。
  • Service 层调用 PageHelper.startPage 后查询列表。
  • Controller 返回 ModelAndView,携带 pageInfo 和查询条件,转发到 courseList.jsp。
  • JSP 页面使用 JSTL 的 c:forEach 渲染表格,使用 c:if 控制状态显示文案。
  • 分页栏用 PageInfo 的 getPageNum、getPages、getTotal 等属性动态渲染。

表单页实现思路:

  • 新增和编辑共用一个 courseForm.jsp,通过隐藏的 id 字段区分是新增还是更新。
  • 提交后 Controller 判断 id 是否为 null,分别调用 insert 和 update。
  • 课程状态字段用下拉框,值由表单直接提交,默认值为 1。

如果想加一点高级感,可以在列表页加一个"查看记录"按钮,跳转到该课程下所有公开课记录的列表,这就是主表和明细表的标准联动,Son 页面相对简单,主要包含到场人数、反馈内容和记录时间。

4.3 Ajax 与 JSON 的辅助应用

虽然整个项目用 JSP 渲染为主,但还是建议在某些场景用 Ajax + JSON 配合,比如无障碍的"快速上线/下架课程"操作,在列表页点击按钮直接向后台发请求,返回 JSON 数据,再用 JS 更新按钮状态。这种情况下需要处理 Controller 返回 JSON 的配置。在 SpringMVC 里,只要方法标注了 @ResponseBody 并且返回对象类型,框架会自动用 Jackson 把对象转成 JSON 输出。记得在 spring-mvc.xml 中加入注解驱动的配置,并确认 Jackjson 依赖已经引入。

一个比较实用的 Ajax 场景是统计页面的异步数据加载:页面加载时从后台查询统计结果,返回 JSON,前端用 DOM 操作渲染成简单的表格或者条形图,不需要引入重量级的图表库,用 CSS 撑宽度就能做出"条形图"的效果,即每行课程类型名称后面加一个灰色底、用宽度百分比表示占比的 div。这种实现既不增加技术负担,又能让页面显得有内容。

4.4 统计报表模块的设计与实现

统计报表是最容易被忽略但最能出彩的模块。设计两个统计维度就足够:

  • 按月份统计开课数量和记录数量:SQL 中使用 DATE_FORMAT(course_time, '%Y-%m') 作为分组字段,COUNT 统计数量。
  • 按课程类型统计总开课数和平均到场人数:一张课表关联分类表,再用记录表算实际人数均值。

统计结果的后端返回一个 List<Map<String, Object>>,然后在 JSP 中遍历输出。如果希望更美观,可以在 JSP 里用行内样式绘制简单的进度条,占满统计行的剩余宽度即可。

这类统计 SQL 要注意数据类型和空值问题。比如 AVG(actual_number) 如果记录表里没有匹配行会返回 NULL,页面上会显示空白,建议在 SQL 中用 IFNULL(AVG(actual_number), 0) 包裹。

5. 常见问题与排查实录

5.1 问题速查表

现象常见原因排查方式
页面提示 404Controller 映射路径写错或视图名解析失败先看控制台日志是否进入方法,再看视图解析器前缀后缀拼出的物理路径是否存在
启动时提示找不到驱动mysql-connector-java 版本 8 时误写旧驱动类改成 com.mysql.cj.jdbc.Driver,确认依赖已引入
数据库中文乱码数据库字符集、连接参数、页面编码三层不一致JDBC URL 加 characterEncoding=utf8,数据库建库用 utf8mb4,JSP 顶部声明 UTF-8
登录后页面不跳转Session 存储或重定向路径写错检查拦截器 preHandle 的 return 逻辑,放行配置是否覆盖了目标路径
分页不生效PageHelper 放在查询语句之后返回值类型不对控制 PageHelper.startPage 后紧跟第一条 Mapper 查询,且返回类型必须是 List
修改数据时提示 SQL 更新 0 行批量更新 SQL 没有匹配到条件打印参数,检查 id 是否传递,字段名是否与数据库列名一致
Jackson 转换时报错实体类没有无参构造器或 getter检查实体类结构,确保属性和方法命名规范
上传到服务器后页面样式丢失静态资源被拦截spring-mvc.xml 中配置 mvc:resources 放行 /static/**

5.2 值得记下来的三个坑

第一个坑是 MyBatis 的驼峰映射。数据库列名下划线风格比如 course_name,如果不开启 mapUnderscoreToCamelCase,实体类的 courseName 属性就永远映射不上去,查出来的对象全部是 null,但 SQL 在数据库工具里明明能查到数据。很多同学查到怀疑人生。解决方案是在 mybatis-config.xml 里加上这个配置项。

第二个坑是 Session 的过期时间。Tomcat 默认 Session 过期时间是 30 分钟,做演示的时候经常有人讲着讲着页面就跳回登录页,很尴尬。建议在 web.xml 里将 session-timeout 设置为 60,或者在拦截器遇到 Session 过期时提示"登录超时",而不是直接白屏。

第三个坑是 JSP 页面中动态脚本与页面报错的关系。如果 JSP 里直接嵌入了大量的 Java 脚本片段,而且业务代码里抛了异常,错误信息会直接打印在页面上,不但丑,而且会把 SQL、路径等信息暴露出去。建议所有业务代码都在 Controller/Service 层捕获,通过 Model 添加 errorMsg 属性,在 JSP 里用 div 呈现。这样演示的时候即使出了错,也不会把底层的堆栈信息展示给验收老师。

5.3 演示前必须做的自测清单

每次在提交之前,我都建议按下面的清单过一遍,一方面是为了功能完整度,另一方面是避免演示时当场翻车:

  • 登录页面是否能正常跳转,错误密码提示是否友好。
  • 新增公开课后返回列表页,数据是否出现,刷新后是否还在。
  • 列表页的分页是否正常,最后一页是否有空数据导致显示错位。
  • 编辑一条课程,修改分类和状态,再查询条件是否还能正确过滤。
  • 删除课程时,关联的记录数据如何处理:直接禁止删除、级联删除、还是仅标记下架。无论选哪种,逻辑都要一致。
  • 录一条记录后,统计页面的数据是否刷新。
  • 退出登录后能否直接访问受保护路径,应该被拦截跳回登录页。

我之前在帮别人调试时最常看到的问题就是:课程删了,但记录表里还有数据,统计页面 JOIN 之后出现空课程名称;或者在页面上点击下架,实际上并没有修改到数据库状态,刷新之后还是原来的状态。这些都是逻辑链路不完整导致的,演示时一旦被问到就很难解释清楚。

6. 项目后续的优化与扩展方向

课程设计交掉之后不代表项目价值就到头了。如果这块代码你决定花时间打磨成求职简历上的项目经验,可以考虑在以下几方面做增量优化:

  • 引入 Spring Security 或 Shiro 替代手写拦截器,让权限控制更规范、更安全。
  • 所有删除操作改成逻辑删除,表中增加 is_deleted 字段,避免误删数据。
  • 把 JSP 逐渐替换成 FreeMarker 或 Thymeleaf,再进一步做前后端分离。
  • 统计模块引入 ECharts 图表库,把条形图换成更直观的柱状图、折线图。
  • 增加导出功能,将课程列表和记录导出为 Excel,使用 Apache POI 或 EasyExcel。
  • 增加留言或附件上传功能,让公开课的课堂资料可以作为附件挂载在课程详情页。
  • 优化密码加密方式,从 MD5 升级为 BCrypt。

每一步优化都可以作为面试时的项目亮点来聊,比如"我在项目中通过 PageHelper 解决了分页性能问题","在权限模块中我把默认的 Session 校验升级成了 Spring Security 的过滤器链",这些都是实打实的个人增量。相比在简历里空谈"精通 SSM",不如拿出一个完整可运行、逻辑有深度的项目来讲,说服力强得多。

最后再分享一个小实践:每一次修改完代码之后,用浏览器的无痕模式重新走一遍登录和新增加载流程,也就是清掉旧的 Session 再测试,很多"在我电脑上明明没问题"的尴尬场景都是因为残留 Session 导致的。养成这个习惯后,你对项目运行状态的判断会比之前准确很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询