资讯动态

JSP+SSM毕设实战:第二课堂成绩单系统开发与避坑指南

发布时间:2026/10/22 10:45:58 来源:尧图企业网站定制
简介这是一份基于JSP与SSM框架的大学生第二课堂成绩单系统毕业设计资源包面向需要完成类似选题、学习SSM整合开发或备战毕业答辩的计算机专业学生。后台区分普通管理员与超级管理员覆盖密码修改、录入单审核、思想道德与技术修养信息维护、新闻数据发布、用户管理等功能模块适合课程设计、毕业设计或框架入门练习。资源包共887个文件、42.25MB以JSP页面、Java源码、JAR依赖库和GIF/PNG界面截图为主另含SQL数据库脚本、Word论文文档、MP4安装演示及项目配置文件便于在Eclipse、STS等IDE中搭配JDK1.8与MySQL运行。目前已有82人学习/下载可对照源码与文档梳理从数据库建表、后台权限分级到前台交互的完整实现思路。包内含源码、数据库脚本、论文、环境工具包及相同框架项目的安装教程按说明操作即可快速部署并可在源码基础上扩展更多第二课堂成绩单管理功能。1. 毕业设计选题怎么选才不踩坑第二课堂成绩单系统到底值不值得做每年到毕设季总有一批同学在选题上反复横跳想做个新颖的又怕实现不了想做个稳妥的又怕太简单被评委挑毛病。大学生第二课堂成绩单系统恰好卡在一个微妙的平衡点上——它的业务逻辑不复杂但涉及学生申报、教师审核、学分汇总、打印导出功能链条完整能覆盖 JSP SSM 开发模式里最常考的那几块内容。更重要的是这套系统背后对应的是高校真实存在的第二课堂管理需求不是那种纯虚构的图书管理系统评委一听就知道你在做什么、为什么要做。这类系统的典型用户是某高校的在校学生、辅导员和院系管理员。学生通过 Web 页面申报自己参加过的社团活动、志愿服务、学科竞赛辅导员逐条审核系统按活动类别自动折算学时或积分最终生成一份带编号的成绩单支持打印和导出。如果你正在为毕设选题发愁手头又有一份带源码、文档和教程的 JSPSSM 项目作参考那这个方向可以认真考虑。它的技术栈足够“经典”能让你把 Spring、SpringMVC、MyBatis 这三件套的关联讲清楚同时业务上又留了扩展空间不管是做数据可视化还是加移动端适配后续都有文章可做。2. 拆解 JSPSSM 技术栈为什么这套组合仍是毕设里的稳妥答案2.1 SSM 三件套在系统里的分工SSM 是 Spring SpringMVC MyBatis 的组合很多刚接触 Java Web 的同学容易把三者混为一谈实际它们在系统里各管一摊。Spring 是容器负责管理对象的创建和依赖注入比如 Service 层的实例由 Spring 统一维护你不必在 Controller 里手动 new 一个 ServiceSpringMVC 是 Web 层框架负责接收浏览器请求、调用业务方法、把结果渲染到 JSP 页面MyBatis 是持久层框架负责把 Java 方法和 SQL 语句做映射简化 JDBC 那堆重复的取连接、建语句、关资源的样板代码。在第二课堂成绩单系统里它们的调用链大致是这样浏览器发起请求SpringMVC 的 DispatcherServlet 根据 URL 找到对应的 Controller 方法Controller 调用 Service 接口处理业务逻辑比如判断申报学时是否超限、状态是否能审核Service 内部再通过 MyBatis 的 Mapper 接口操作数据库。三层各司其职改页面不用动 SQL改业务逻辑不用碰 JSP这也是评委最喜欢追问的分层解耦问题。理解这个分层还有一个实际好处排查问题的时候能快速定位。如果页面报 500日志里既有 SQL 异常又有 NullPointerException你至少能判断是 Mapper 层写错了还是 Service 层没拿到注入的对象不至于从页面一路瞎猜到数据库。2.2 项目目录结构与关键配置拿到一套 JSPSSM 的源码第一步不是急着点运行而是先看目录结构。规范的 Maven Web 项目长这样src/main/java cn.edu.demo.controller StudentController.java AdminController.java TeacherController.java cn.edu.demo.service ApplyService.java AuditService.java cn.edu.demo.dao ApplyMapper.java StudentMapper.java cn.edu.demo.entity Student.java ApplyRecord.java SecondClassScore.java src/main/resources jdbc.properties mybatis-config.xml spring-mvc.xml spring-mybatis.xml src/main/webapp WEB-INF jsp student admin teacher web.xml pom.xml拿到代码后先对着这种标准结构核对一遍。如果源码的包名混乱、JSP 散落在根目录没有收进 WEB-INF说明这份代码的作者本身工程素养一般你后续维护成本会偏高。我一般会先看三样东西pom.xml 里的依赖版本、jdbc.properties 的数据库连接配置、web.xml 里配置的 Spring 容器加载路径。这三处能跑通项目基本就活了大半。2.3 数据库设计第二课堂成绩单核心表怎么建模成绩单系统的数据库设计是答辩时的重点表建得好不好直接决定你能不能让评委点头。最核心的表有四张学生表、活动类别表、申报记录表、成绩单汇总表。学生表存学号、姓名、班级、专业活动类别表用来定义“志愿服务类”“学术竞赛类”“文体活动类”这些字典数据方便以后加类别不用改代码申报记录表是业务核心每次申报一条记录包含学生 ID、活动 ID、申报学时、状态、审核意见成绩单汇总表则按学期或学年汇总每个学生的总学时和各类别明细。建表时有个容易被忽略的点学时字段要保留一位小数比如“1.5 学时”很常见用 INT 会丢精度。状态字段则建议用 TINYINT 存数字0 表示待审核、1 表示通过、2 表示驳回而不是直接存中文字符串这样查询效率高代码里也便于用常量判断。下面这是申报记录表的参考 DDLCREATE TABLE apply_record ( id INT NOT NULL AUTO_INCREMENT COMMENT 主键, student_id VARCHAR(20) NOT NULL COMMENT 学号, activity_id INT NOT NULL COMMENT 活动ID, apply_hours DECIMAL(4,1) DEFAULT 0.0 COMMENT 申报学时保留一位小数, status TINYINT DEFAULT 0 COMMENT 状态0待审核 1通过 2驳回, audit_opinion VARCHAR(255) DEFAULT NULL COMMENT 审核意见, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 申报时间, audit_time DATETIME DEFAULT NULL COMMENT 审核时间, PRIMARY KEY (id), KEY idx_student (student_id), KEY idx_activity (activity_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT第二课堂申报记录表;注意这里给 student_id 和 activity_id 都建了索引。第二课堂系统的数据量不会特别大但按学生查申报记录、按活动查参加人数是最常见的查询路径这两个索引能让组合查询快一个量级。charset 用 utf8mb4 而不是 utf8因为 utf8 在 MySQL 里存不了 emoji 和部分生僻字万一学生在活动名称里填了个特殊符号用 utf8 就直接报“Incorrect string value”错误。3. 把源码跑起来从导入到看到登录页的完整步骤3.1 环境准备JDK、Tomcat、MySQL 的版本搭配JSPSSM 的老项目对环境版本很敏感尤其是 JDK 和 Tomcat 的搭配。常见做法是用 JDK 1.8 Tomcat 8.5 MySQL 5.7这套组合最稳网上能查到的资料也最多。如果你电脑上装的是 JDK 11 甚至更高不是不能跑但会遇到 JSP 编译相关的兼容问题比如 Tomcat 9 对 JSTL 的支持方式和老版本有差异改起来费劲。安装顺序建议是先装 JDK 并配好 JAVA_HOME再装 MySQL 并初始化密码最后解压 Tomcat。Tomcat 不需要安装解压后配置一下端口就行。装 MySQL 时有个血泪经验5.7 版本安装时如果选了“强密码”选项默认密码策略要求大小写字母加特殊字符后边连接配置里很容易因为特殊字符没转义而出问题建议安装时直接选“弱密码”或者用 root/123456 这种简单的开发密码毕设环境没必要搞那么复杂。3.2 修改配置文件数据源和路径是两大命门项目导入 IDEA 后别急着启动先打开 jdbc.properties 把数据库连接改成你自己的。这段配置是项目能连上数据库的前提也是最容易翻车的地方jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/second_class?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456这里最容易忽略的是 URL 后面那一长串参数。useSSLfalse 是必须的MySQL 5.7 默认会尝试建立 SSL 连接不加这个参数会报一堆 SSL 警告serverTimezoneAsia/Shanghai 是处理时区问题的不加这个参数 MyBatis 在操作 DATETIME 类型时可能差 8 个小时。如果你是 MySQL 8.x 的驱动driver 要改成 com.mysql.cj.jdbc.Driver老驱动类名在新版本里已经移除。改完配置还要检查 web.xml 里有没有配置项目欢迎页——也就是默认跳到哪个 JSP。常见做法是把登录页 index.jsp 放在 webapp 根目录或者在 web.xml 里加一个 welcome-file 配置。如果启动后访问项目根路径报 404优先检查这里而不是先去查代码逻辑。3.3 启动项目从 Tomcat 报错到看到登录页配置改完后在 IDEA 里配置 TomcatRun - Edit Configurations新增一个 Tomcat Server - Local在 Deployment 选项卡里把项目以 war exploded 方式部署Application context 填/second_class或保持根路径。启动后看控制台日志出现 “Server startup in xxx ms” 就说明 Web 容器起来了再访问http://localhost:8080/second_class/。这一步最常见的现象是启动报错但错误信息看不懂。教你一个快速定位的思路先看是不是端口被占用——Tomcat 默认 8080如果你之前装过其他服务占了端口就会报Port 8080 required by Tomcat v8.5 Server is already in use在 server.xml 里把端口改成 8081 就行。再看有没有ClassNotFoundException这类错误多半是 Maven 依赖没有全部导入在 IDEA 里右键项目 Maven - Reimport 重新拉一遍依赖基本能解决。如果日志里出现了数据库相关的异常回到上一节检查连接配置别急着往下走。4. 核心模块怎么实现成绩单的申报、审核与打印全流程4.1 学生申报模块表单提交与学时校验学生登录后的核心操作就是发起申报。前端是一个包含活动名称、活动类别、申报学时、活动描述的表单提交后由 SpringMVC 接收参数并封装成对象。这里有个细节Controller 方法的参数对象必须和实体类字段名对应上JSP 表单里的 name 属性、实体类的属性名、数据库表的列名这三处不一致就会出现前端显示“提交成功”但数据库里没数据的诡异现象。活动类别建议用下拉框而非文本框。下拉框的数据来自 activity_category 表在前端用 JSTL 的 forEach 标签渲染。这样做的原因是后续统计成绩单时要按类别分组汇总如果学生手填类别可能出现“志愿服务”和“志愿服务类”两种写法汇总时直接分成两行。申报提交后Service 层要做两件事一是判断该学生是否重复申报同一个活动二是判断学时分值是否在合理范围内。后者的判题思路很直接——活动类型不同单次学时上限不同比如学术竞赛类单次最高 8 学时文体活动类最高 4 学时。在 Service 里写一个薄薄的校验方法既能体现业务思考也能防止学生乱填数据答辩时这条逻辑值得单独讲一讲。4.2 教师审核模块列表与批量操作审核模块是后台管理的重点。教师登录后看到的是一个待审核列表每条记录显示学生学号、姓名、活动名称、申报学时和申报时间。这里有两个实现上的关键点分页查询和状态流转。分页用 MyBatis 的 PageHelper 插件最省事。Controller 接收当前页码 pageNum 和每页大小 pageSizeService 层调用 PageHelper.startPage(pageNum, pageSize) 后紧跟一条查询语句PageHelper 会自动拦截 SQL 并生成带 LIMIT 的查询同时返回一个 PageInfo 对象里面封装了总记录数、总页数、当前页数据列表。前端分页条直接用 PageInfo 里的字段渲染就行不用自己拼 SQL。审核状态流转的代码逻辑类似这样public void audit(Integer id, Integer status, String opinion) { ApplyRecord record applyMapper.selectById(id); if (record null) { throw new RuntimeException(申报记录不存在); } if (record.getStatus() ! 0) { throw new RuntimeException(该记录已审核请勿重复操作); } record.setStatus(status); record.setAuditOpinion(opinion); record.setAuditTime(new Date()); applyMapper.updateStatus(record); if (status 1) { scoreService.addScore(record); } }这段代码里两个 if 判断是核心。第一个是防空指针如果记录不存在直接抛异常第二个是状态幂等校验防止教师在前端重复点击“通过”按钮导致同一条记录被加两次分。最后那行 addScore 的逻辑值得品味——只有审核通过才累加到成绩单汇总表里驳回的申报根本不会影响学生的总学时这就保证了成绩单数据的准确性。4.3 成绩单汇总与打印MyBatis 动态 SQL 的用武之地成绩单模块需要支持按学号、按学期、按活动类别三个维度查询还会涉及多表关联。这里把 MyBatis 的动态 SQL 特性发挥到极致。比如一个组合查询学生只选了学期没选类别或者两个条件都选了写 SQL 时要用 if 标签动态拼接 WHERE 条件select idselectScoreSummary resultTypemap SELECT s.student_name AS studentName, c.category_name AS categoryName, SUM(a.apply_hours) AS totalHours FROM apply_record a JOIN student s ON a.student_id s.student_id JOIN activity_category c ON a.activity_id c.id WHERE a.status 1 if testsemester ! null and semester ! AND a.semester #{semester} /if if testcategoryId ! null AND a.activity_id IN (SELECT id FROM activity WHERE category_id #{categoryId}) /if GROUP BY s.student_name, c.category_name ORDER BY totalHours DESC /select这段 SQL 里 resultType 用了 map方便前端展示那些没有对应实体类的虚拟字段。如果你是第一次接触 MyBatis需要注意 if 标签里 test 参数的写法字符串用单引号包着判断数值类型直接写属性名。另外 GROUP BY 后面不能把 student_id、category_id 写进 SELECT 列表之外MySQL 默认开了 ONLY_FULL_GROUP_BY 模式写错会直接报错这个坑不少人都踩过。打印功能有两种常见实现一种是用浏览器自带的 window.print() 打印当前页面简单但样式难以控制更专业一点的是用 POI 导出 Excel在 Java 里生成 .xlsx 文件响应给前端下载。毕设做到 POI 导出这步就已经超出平均水平了评委看到的不只是一个能用 print 弹出的网页而是一个能真正导出文件的系统。5. 毕设调试中的避坑指南从白屏到数据错乱的排查记录5.1 JSP 页面路径 404斜杠背后的路径玄学现象启动成功首页也进了但点击某个菜单跳转到/student/apply.jsp时直接 404。原因JSP 存放在WEB-INF/jsp/student/apply.jsp下而 WEB-INF 目录下的资源不能通过浏览器地址栏直接访问。很多老项目的 JSP 没有收进 WEB-INF而是直接放在 webapp 根目录这时访问路径要写成/apply.jsp而不是/WEB-INF/jsp/apply.jsp。解决有两种方案。一是把 JSP 放在 webapp 根目录下的对应文件夹里简单粗暴但会暴露页面文件路径安全性差些二是用 SpringMVC 的 ViewResolver 配置内部视图解析器Controller return 的时候直接返回逻辑视图名student/apply由解析器自动拼接前缀和后缀定位到真实 JSP 文件。我用后者配置在 spring-mvc.xml 里两个属性一个 prefix 一个 suffix写清楚就行。5.2 数据库中文乱码一个字符集引发的连锁翻车现象学生信息录入中文后页面上显示正常但数据库里存成了????。原因请求从浏览器经过 Tomcat 再到 MySQL链路里任何一环字符集不对中文就会变形。最常见的是 MySQL 连接 URL 里 characterEncoding 参数没写Tomcat 默认的 POST 请求编码又不是 UTF-8两处叠加必然乱码。解决先改数据库连接 URL 加上 characterEncodingutf8再在 web.xml 里配置一个 CharacterEncodingFilter强制所有请求用 UTF-8 编码。这个 Filter 要在 SpringMVC 的 DispatcherServlet 之前注册否则 SpringMVC 已经读取了请求参数你再改编码就晚了。还有个易漏的点——如果建表时表本身是 latin1 字符集连接参数改对也没用需要把表和字段的字符集一起 alter 成 utf8mb4。5.3 MyBatis 结果映射失败字段驼峰与下划线之争现象列表页能显示数据条数但每一行的姓名、学号字段全部为空。原因数据库表的字段是student_name、student_id这种下划线风格但实体类的属性是studentName、studentId这种驼峰风格。MyBatis 默认不会自动把下划线转成驼峰结果集映射时找不到属性名就默默返回 null。解决在 mybatis-config.xml 里开启驼峰映射一行配置解决问题configuration settings setting namemapUnderscoreToCamelCase valuetrue/ /settings /configuration如果不开这个配置你就得在 resultMap 里手动把每个下划线字段和驼峰属性对应一遍纯属浪费时间。这个坑在 Student、ApplyRecord、Category 三个实体类上会各踩一次开一个开关全搞定。排查时注意区分如果所有字段都为空几乎可以断定是映射问题如果某个字段为空、其他字段正常再去查那条数据本身是不是没填值。5.4 端口被占用与项目热部署失效现象Tomcat 启动到一半报端口被占用或者修改 JSP 后刷新页面没变化。原因前者好理解本机有其他进程占了 8080。后者往往是因为 IDEA 配置 Tomcat 时选了“Deploy on Server Shutdown”而不是“Update Resources”导致每次修改都要重启 Tomcat 才能生效。解决端口占用时打开终端执行netstat -ano | findstr 8080找到占用进程的 PID再到任务管理器结束进程。热部署失效则在 Tomcat 配置的 On Frame Deactivation 选项里选 Update classes and resources这样改 JSP 和静态资源不需要重启调试效率提升一个档次。这个配置在 IDEA 的 Run Configuration 里不在项目代码里很多同学找不到是因为没展开 Tomcat Server 的高级选项。5.5 学时汇总数据翻倍一次典型的联表查询脏数据现象某个学生的成绩单总学时比实际申报记录加起来的还多而且数据越查越不对劲刷新一次变一个样。原因写汇总 SQL 时 JOIN 了多张表其中 one-to-many 的关系没有去重比如学生表 join 申报表 join 活动表如果活动表里遇到一对多的情况同一份申报记录就会被拆成多行参与 SUM结果自然翻倍。解决排查时先把 SQL 拆开跑。先用SELECT * FROM apply_record WHERE student_id2021001看原始记录有多少行再单独跑汇总 SQL 看结果。如果发现结果行数异常问题一定出在 JOIN 上。我的习惯是汇总前先用子查询把明细层聚合好再来做外表关联永远不要在 JOIN 之后直接 SUM除非你完全确认每个 JOIN 都是一对一关系。这条经验是从某次翻车里得来的当时查了整整一个下午最后发现是活动表和活动类别表之间有一条冗余数据。6. 答辩演示的实战技巧让评委觉得系统有价值的三个关键动作6.1 准备一个 5 分钟的演示脚本毕设答辩时间通常有限系统展示环节只有几分钟不可能把每个页面都点一遍。我的习惯是准备一个“主线演示路径”从登录页进入学生角色演示一次完整的申报流程提交一条新的活动记录切换到教师角色审核刚才那条申报再回到学生角色查看成绩单确认学时已经累加上去。这条路径完整覆盖了“提交 - 审核 - 汇总”的核心闭环比漫无目的地乱点更有说服力。演示前一定要做一次“数据预置”提前在数据库里插入几条待审核的记录、一条已经审核通过的成绩单数据保证演示时页面不会出现空白列表。这一点看着不起眼但在台上关键时刻救过命。我见过有同学现场申报完教师端刷新半天没数据最后发现是没提交成功场面非常尴尬。避免的唯一办法就是提前彩排两遍把每一步点击后的页面结果记在心里。6.2 让评委眼前一亮的两个进阶功能点基础功能做完之后如果你还有余力推荐加两个低成本高回报的功能。第一个是 ECharts 可视化图表。在成绩单汇总页加一个柱状图按活动类别展示学时分布再放一个饼图显示各年级参与人数占比。ECharts 是纯前端的 JS 库引入一个 script 标签再写几十行 JS 就能跑起来数据从后端接口拿 JSON 就行。评委看到图表后几乎必然会问数据从哪来、怎么聚合的这时你就可以把自己写的统计 SQL 讲一遍既展示了前端能力又展示了 SQL 功底。第二个是无刷新提交。学生申报表单提交后不跳转页面而是用 AJAX 把表单数据 POST 到后端返回 JSON 结果后只在当前页面弹一个提示。这个功能虽然没有图表那么显眼但能避免学生在申报后重新填一遍表单的糟糕体验也说明你理解了前后端交互的异步模型。6.3 收尾好系统的标准不只是“能跑”做了这么多套 JSPSSM 项目后我自己的体会是毕设系统能不能拿高分标准从来不是“功能多齐全”而是“边界有没有考虑”。你处理了重复申报没有处理了审核幂等没有数据库用了事务没有这些边界情况才是系统真正拉开差距的地方。如果你在演示时主动提一句“我在申报模块做了重复校验防止同一活动被多次申报”评委的注意力会立刻从页面样式转移到业务设计上这比任何花哨的动效都管用。这个方向真正值得投入的地方也在于此——技术栈虽然是老的但你在实现过程中建立的分层意识、边界意识和排错能力换到任何新技术上都能复用。希望这篇笔记能帮你在毕设路上少走几步弯路把更多精力花在真正有长期收益的代码和设计上。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑