news 2026/10/18 5:31:48

JavaWeb学生成绩管理系统:JSP+Servlet+JDBC源码拆解与部署指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaWeb学生成绩管理系统:JSP+Servlet+JDBC源码拆解与部署指南

简介:基于JavaWeb的学生成绩管理系统,是一套面向高校计算机相关专业毕业设计以及Java初学者的完整项目源码资源。系统以JSP、Servlet、JDBC为后台框架,配合MySQL数据库,采用B/S结构,包含学生、教师、管理员三类角色,模块化实现了学生基本信息管理、教师信息管理、班级信息管理、课程信息管理、成绩信息管理、系统设置和考勤管理七项功能,支持按条件查询、成绩导入与统计汇总,界面简洁、操作流畅。压缩包共3个文件:项目说明txt整理了开发环境配置、部署步骤与功能设计,SQL脚本提供完整数据库表结构与初始数据,ZIP工程为可导入Eclipse的完整源码。资源整体仅6.38MB,经严格调试可直接运行,目前已有7846人学习下载。对于正在备赛或完成毕设的读者,既能快速搭建成绩管理场景,也能通过源码理解角色权限、数据表关联和增删改查的典型实现。

1. 基于JavaWeb的学生成绩管理系统:从毕设源码到可运行项目的完整拆解

学生成绩管理系统大概是JavaWeb方向毕设里最常见的题目之一,但你真正拿到一份能跑起来的源码时,遇到的问题往往不是"看不懂逻辑",而是"配三天环境、改了十几处代码,Tomcat 还是起不来"。这套基于 JSP + Servlet + JDBC + MySQL 的B/S架构系统,覆盖了学生、教师、管理员三种角色和七大功能模块,源码里自带数据库脚本和项目说明,定位就是给正在做毕设的学生和需要项目练手的Java学习者准备的。本文不聊空洞的架构概念,而是直接拆开这份资源,把技术栈选型、源码目录、核心代码、运行步骤、常见坑和二次改造思路一次讲透——你照着操作能跑通,改起来也知道从哪儿下手,而不是把源码当黑匣子。

2. 技术栈与架构设计:JSP+Servlet+JDBC 三层结构怎么串起来

2.1 三权分立的角色设计:为什么这套系统天然适合毕设选题

拿到这套源码,你第一眼看到的不是代码,而是它的角色划分——学生、教师、管理员。这个设计几乎决定了整个系统的页面结构和权限判断逻辑,也是最值得你在答辩时讲清楚的点。

管理员拥有最高权限,管理学生信息、教师信息、班级信息、课程信息,还能配置系统操作员、重置密码、查看考勤统计。教师角色能查询自己所带的课程和学生名单,录入成绩、登记考勤。学生角色的权限最窄,登录后只能看自己的成绩、课表和考勤情况,改不了任何数据。

这种三角色模型的实现方式,在这套源码里用的是最朴素的方案:登录接口里查数据库获得用户类型字段,写进 Session,每个页面在加载时判断 Session 里的角色值,决定渲染哪些菜单、开放哪些操作按钮。后续的二次开发章节我会说这种方式的问题和更工程化的替代方案,但作为教学项目,这个设计能让你把"权限控制"这个面试高频问题讲清楚,从数据库 user 表的 role 字段一路讲到 JSP 页面里的逻辑判断,整条链路完整且不复杂。

2.2 源码目录结构:每个文件夹在项目里干什么

把压缩包解压后,你看到的是标准的 Eclipse Dynamic Web Project 目录结构,我用表格把它映射到实际功能上,方便你拿着源码对照。

路径存放内容对应的功能模块
src/com/system/daoJDBC 数据访问对象所有对 MySQL 的操作,按表划分
src/com/system/servlet控制器层接收页面请求、调用 DAO、转发到 JSP
src/com/system/bean实体类学生、教师、课程、班级等 JavaBean
src/com/system/util工具类数据库连接、字符串处理、分页辅助
WebContent/jsp视图层各角色的 JSP 页面
WebContent/css样式文件页面美化,不过度依赖框架
WebContent/WEB-INF/web.xml部署描述符Servlet 映射、欢迎页配置
db_student_manager_web.sql数据库脚本建库、建表、插入初始数据一次完成

理解这套目录结构的关键在于认清它的数据流向:JSP 页面负责展示和收集表单,把参数提交给 Servlet,Servlet 是个中转站,不碰 SQL,只负责调用 DAO 层的方法,DAO 类用 JDBC 拼 SQL 操作 MySQL,查完的结果封装成 Bean 对象,再回传给 JSP 渲染。这就是典型的 JSP + Servlet + JavaBean + DAO 分层,也是 JavaWeb 课程里最标准的三层架构教学模板。

2.3 数据库表设计:六张核心表如何通过外键关联

打开 db_student_manager_web.sql 脚本你会发现,整套数据模型并没有搞复杂的存储过程或触发器,而是用最直白的六张表完成了所有业务数据的组织。

student 表存学生基本信息,字段包括学号、姓名、性别、年龄、电话、班级编号、专业;teacher 表存教师信息,除了基础资料外还有课程字段和入校时间;class 表管班级,记录班级名称、人数、班主任教师编号;course 表存课程名称和授课教师编号;score 表是成绩核心表,字段是学生编号、课程编号、成绩、考试时间;attendance 表管考勤,记录学生编号、课程编号、日期、出勤状态。

这六张表的关系可以简单概括为:student 通过 class_id 关联到 class 表,class 通过 teacher_id 关联到 teacher,course 通过 teacher_id 关联到 teacher,score 通过 student_id 和 course_id 分别关联学生与课程,attendance 同理。你如果要在二开时加功能,不建议改这六张表的既有结构,而是新增表去外扩,例如加一张 notice 公告表,就完全不会影响原系统的查询逻辑。

3. 核心模块拆解:成绩录入、班级管理、考勤统计的实现链路

3.1 登录与角色分发:Session 里存什么,页面靠什么拦人

整个系统的入口是登录逻辑,这部分的代码是所有角色模块共用的地基。我以常见的实现方式还原一下核心 Servlet 的写法,你在源码里看到的大体是这个套路。

// LoginServlet.java @WebServlet("/login") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); UserDao dao = new UserDao(); User user = dao.findByUsernameAndPassword(username, password); if (user != null) { HttpSession session = request.getSession(); session.setAttribute("loginUser", user); session.setAttribute("role", user.getRole()); // 根据角色跳转不同的首页 if ("admin".equals(user.getRole())) { response.sendRedirect("admin/index.jsp"); } else if ("teacher".equals(user.getRole())) { response.sendRedirect("teacher/index.jsp"); } else { response.sendRedirect("student/index.jsp"); } } else { request.setAttribute("errorMsg", "用户名或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); } } }

这段代码的逻辑非常典型:doPost 接收登录页表单的两个参数,调用 DAO 层按用户名和密码查数据库,查不到就回登录页并提示错误,查到了就把 user 对象和 role 字符串放进 Session,再做页面跳转。

参数说明上,username 和 password 对应登录页 input 框的 name 属性,前端表单穿什么字段名,Servlet 这边 getParameter 就得写什么字符串,这是新手最容易翻车的地方——前端改了 name 值,后端没同步改,登录永远失败。role 字段的值建议在数据库里定死为 "admin" / "teacher" / "student" 三种字符串,不要用数字,不然每个页面判断时还得先转换,逻辑就乱了。

每个需要权限控制的 JSP 页面头部通常还有一段校验代码,检查 Session 里是否存在 loginUser,不存在就跳回登录页。源码里各角色的 index.jsp 都会带这段守卫逻辑。

3.2 成绩信息管理:成绩录入和查询的完整链路

成绩模块是这套系统的核心业务,体现的是典型的增删改查流程,我拆成录入和查询两条链路来看。

成绩录入的页面是一张表格,每行有一个学生姓名、一个课程下拉框和一个成绩输入框,提交后走 ScoreServlet 的 doPost 方法:

// ScoreServlet.java - 成绩录入 @WebServlet("/score/add") public class ScoreAddServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String studentId = request.getParameter("studentId"); String courseId = request.getParameter("courseId"); String scoreValue = request.getParameter("score"); String examTime = request.getParameter("examTime"); // 把字符串参数封装成实体对象 Score score = new Score(); score.setStudentId(Integer.parseInt(studentId)); score.setCourseId(Integer.parseInt(courseId)); score.setScore(Double.parseDouble(scoreValue)); score.setExamTime(java.sql.Date.valueOf(examTime)); ScoreDao dao = new ScoreDao(); boolean success = dao.addScore(score); if (success) { response.sendRedirect("score/list?courseId=" + courseId); } else { request.setAttribute("errorMsg", "添加成绩失败,请检查学生和课程是否存在"); request.getRequestDispatcher("score/add.jsp").forward(request, response); } } }

这个 Servlet 做的事就是参数接收、类型转换、封装对象、调用 DAO、根据结果决定跳转方向。注意 examTime 字段用了 java.sql.Date.valueOf 来把表单里 yyyy-MM-dd 格式的字符串转成日期类型,这个转换方法在格式不匹配时会直接抛异常,所以前端表单里一定要写清楚日期格式要求,或者在 Servlet 里先做字符串格式校验再转换,这是血泪经验。

ScoreDao 里的 addScore 方法实现更直观,就是一条 INSERT 语句:

// ScoreDao.java 片段 public boolean addScore(Score score) { String sql = "INSERT INTO score (student_id, course_id, score, exam_time) VALUES (?, ?, ?, ?)"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, score.getStudentId()); ps.setInt(2, score.getCourseId()); ps.setDouble(3, score.getScore()); ps.setDate(4, score.getExamTime()); return ps.executeUpdate() > 0; } catch (SQLException e) { e.printStackTrace(); return false; } }

这里用了 PreparedStatement 而不是 Statement,重要原因有两个:一是用占位符方式避免 SQL 注入,用户传什么参数都只是参数,不会被拼进 SQL 语句执行;二是 setInt、setDouble、setDate 这些方法自带类型检查,写错类型时在编译或运行早期就会暴露。JDBC 的 finally 块关闭连接这段逻辑,源码里用的是 try-with-resources 写法,所有打开了 Connection、PreparedStatement 的资源在 try 结束后自动关闭,不写 finally 也不会内存泄漏,这个习惯值得保留。

成绩查询链路的实现相对简单,ScoreDao 里写一个按 student_id 或 course_id 查询的方法,把 ResultSet 逐行封装成 Score 对象,放进 List,Servlet 再用 request.setAttribute 把 List 传给 JSP 页面,JSP 用 JSTL 的 c:forEach 标签循环渲染成表格。

3.3 班级与课程的关系处理:外键关联和级联数据展示

班级信息管理模块的难点不在增删改查本身,而在页面要展示的信息来自多张表聚合——一个班级页面不仅要显示班级名称和人数,还要列出该班级的学生名单、班主任信息、关联课程。这就涉及多表联查。

看这段典型的查询班级学生列表的 DAO 写法:

// ClassDao.java 片段 public List<Student> findStudentsByClassId(int classId) { String sql = "SELECT s.id, s.student_no, s.name, s.gender, s.phone, c.class_name " + "FROM student s " + "LEFT JOIN class c ON s.class_id = c.id " + "WHERE s.class_id = ?"; List<Student> students = new ArrayList<>(); try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, classId); ResultSet rs = ps.executeQuery(); while (rs.next()) { Student stu = new Student(); stu.setId(rs.getInt("id")); stu.setStudentNo(rs.getString("student_no")); stu.setName(rs.getString("name")); // 班级名称塞进 Student 对象的扩展字段里 stu.setClassName(rs.getString("class_name")); students.add(stu); } } catch (SQLException e) { e.printStackTrace(); } return students; }

注意这段代码里的一个设计巧思:Student 实体类里除了自己表的字段,还加了一个 className 字段,专门用来接收联查出来的班级名称。这样页面拿到 Student 对象后,不需要再逐条去查一次班级表,一次 SQL 就把关联数据全部封装好。这就是 N+1 查询问题的规避思路,虽然 JDBC 时代没有 ORM 框架帮你处理这类问题,但手写 SQL 时你自己控制 join 的粒度和时机,反而更容易讲清楚数据是怎么从数据库流动到页面的。

班级管理模块还有一个常规操作是级联展示——点击某个班级名称,下方区域动态显示这个班的学生表和课程表。源码里的实现方式是 JSP 页面用 AJAX 请求一个返回 JSON 数据的 Servlet,Servlet 把查询结果用 JSON 工具序列化后写回响应。如果你的项目源码里没找到这部分代码,那是因为常见做法是直接在 JSP 里做表单联动搜索,而不是做前端异步渲染,这取决于原作者的实现风格。

3.4 考勤管理:出勤状态统计的简单可靠实现

考勤模块的亮点不在功能复杂度,而在统计思路。考勤表记录的是粒度数据——某个学生在某节课上是出勤、迟到、缺勤还是请假。统计逻辑就是把每次考勤记录按照状态字段做分组计数。

这里的核心 SQL 长这样:

SELECT student_id, SUM(CASE WHEN status = '出勤' THEN 1 ELSE 0 END) AS attend_count, SUM(CASE WHEN status = '迟到' THEN 1 ELSE 0 END) AS late_count, SUM(CASE WHEN status = '缺勤' THEN 1 ELSE 0 END) AS absent_count FROM attendance WHERE course_id = ? GROUP BY student_id

这个统计 SQL 用的正是条件聚合:CASE WHEN 把符合条件的记录记为 1、不符合的记为 0,再通过 SUM 累加,一次查询就把每个学生在某门课上的各种出勤状态次数全算出来。这种写法比在 Java 里循环统计要高效得多,而且 SQL 逻辑一目了然,答辩时拿这个 SQL 当例子讲解,比贴一大段 Java 代码更有说服力。

考勤信息导入功能在这个模块里通常指的是教师按课程批量登记考勤,表单里每行一个学生,旁边是状态下拉框,提交后多层循环逐条 INSERT。这种做法性能上有优化空间,但作为小型教务系统的并发量来说完全够用,项目里别去过度设计批量提交、事务回滚这些机制,除非你后续要承接真实业务,我在最后一章会单独说这个改造点。

4. 本地运行全流程:Eclipse + MySQL + Tomcat 把源码跑起来

4.1 环境版本怎么选才不踩坑

先说环境搭配,这是整个跑通流程里最容易出问题的环节,而且问题通常出在版本不匹配上。根据这套项目的技术栈和大多数毕设源码的实际配置,我推荐的环境组合是 JDK 1.8、Tomcat 8.5、MySQL 5.7、Eclipse IDE for Enterprise Java Developers。

JDK 8 是兼容性最稳的选择,因为源码里极少会用到 JDK 11 之后的新语法特性,而且 Eclipse 2019 到 2021 那几个常用版本对 JDK 8 的支持都非常好。Tomcat 8.5 支持到 Servlet 3.1 规范,对 JSP 2.3 解析没问题,比 Tomcat 9 更省心的是它和 Eclipse 的适配度更高,不用额外处理模块化相关的类加载报错。MySQL 5.7 的驱动连接串写法(jdbc:mysql://localhost:3306/db_name?useSSL=false&characterEncoding=utf8)在 MySQL 8.0 里已经变了,有些旧源码直接用 5.7 的驱动连 8.0 数据库会报 SSL 或编码相关的连接错误,所以我建议你装 5.7,省去这些玄学问题。

把这三个软件的安装包准备好,按默认选项安装就行,唯一要注意的是 MySQL 安装时记住你设置的 root 密码,后面修改数据库连接配置时要用。

4.2 数据库导入:不写一行命令把 SQL 跑起来

解压后的 db_student_manager_web.sql 文件是整个系统的数据地基,里面包含建库语句、建表语句、初始数据插入语句。导入方式有很多种,最稳妥的还是命令行操作。

打开命令行工具,进入 MySQL 的 bin 目录后执行:

mysql -u root -p # 输入密码后进入 MySQL 交互界面 source /你的完整路径/db_student_manager_web.sql

source 命令会把 SQL 文件里的建库语句直接执行,执行完后用 show databases; 检查数据库是否创建成功,再用 use 数据库名; show tables; 确认所有表都建好了。

如果你更习惯用图形化工具,Navicat 或 MySQL Workbench 都可以直接右键运行 SQL 文件。这里有个注意点:SQL 脚本开头如果包含 CREATE DATABASE 语句,你要确认当前连接的账号有建库权限,否则导入会半路失败。另外脚本里有中文数据(比如班级名称、学生姓名),导入前需要确认 SQL 文件本身是 UTF-8 编码,用记事本打开看到的中文是正常的,就没问题;如果是乱码,先用 Notepad++ 转成 UTF-8 编码再导入。

4.3 项目导入与 Tomcat 配置:从 Eclipse 到浏览器显示首页

数据库就绪后,进入 Eclipse 导入项目环节。打开 Eclipse,File -> Import -> General -> Existing Projects into Workspace,选择你解压后的源码根目录,注意不要勾选 Copy projects into workspace(如果你希望保留源码原路径的话,勾选与否都可以,不影响运行)。

导入后要做的关键操作是把项目关联到 Tomcat。在 Eclipse 的下方窗口找到 Servers,右键新建一个 Tomcat 8.5 的服务器实例,然后在项目上右键 Properties -> Targeted Runtimes,勾上你刚才创建的 Tomcat 实例。

很多项目跑不起来就是因为漏了最后这一步,项目没有关联运行环境,Eclipse 只在语法检查层面能过,部署到 Tomcat 时找不到运行环境,启动直接报错。

接下来是修改数据库连接配置。在源码里找到数据库连接工具类(路径一般在 src/com/system/util/DBUtil.java),修改连接字符串、账号、密码三个信息:

// DBUtil.java 片段 private static final String URL = "jdbc:mysql://localhost:3306/db_student_manager_web?useSSL=false&characterEncoding=utf8"; private static final String USER = "root"; private static final String PASSWORD = "你自己的数据库密码";

URL 里的 db_student_manager_web 要和 SQL 脚本里创建的数据库名完全一致,大小写也要对上。useSSL=false 这个参数很关键,MySQL 5.7 默认配置下如果没关闭 SSL,旧驱动连数据库时会一直在握手阶段报错;characterEncoding=utf8 则确保中文字符在查询插入时不会乱码。

启动顺序有讲究:先保证 MySQL 服务已启动,然后把项目右键 Run As -> Run on Server,选择你配置好的 Tomcat。启动日志刷到 Server startup 字样就稳了,浏览器输入 http://localhost:8080/项目名/ 就能看到登录页。登录页的默认账号密码在 SQL 脚本的 user 表里,你可以用 where 条件查出来,也可以在项目说明 txt 里找,一般管理员账号 admin/admin 是标配。

4.4 启动验证:逐个模块确认功能正常

项目跑起来只是第一步,你要快速验证七大模块都正常才算是真正复现成功。我的验证顺序是:先用管理员账号登录,确认能进入管理员首页,菜单能看到学生管理、教师管理、班级管理、课程管理、成绩管理、考勤管理、系统设置七个入口;点进学生管理页面,确认列表有数据展示、查询条件能筛出来结果;再点成绩管理,给某条学生记录录入一个成绩,保存后回到列表确认新增的数据出现在页面里;最后切换到教师账号登录,验证教师视角里能看见自己关联的课程和学生,能操作考勤登记。

这个验证过程走完只需要十几分钟,但能发现大多数隐藏问题。例如页面能打开但查不出数据,十有八九是数据库连接配置里的库名或密码错了;登录成功但跳转后一片空白,通常不是程序逻辑问题,而是 JSP 编译报错,去看 Tomcat 的 catalina.out 日志能找到根因。

5. 避坑记录:跑不起来和跑起来报错最集中发生的地方

5.1 现象:Tomcat 启动立即报 ClassNotFoundException 或 ClassDefNotFoundError

原因:项目里缺 servlet-api.jar 或 jsp-api.jar,常见于项目导入时没有把外部 Jar 包正确加入 Web 应用的 WEB-INF/lib 目录,或者 Tomcat 库没有关联到项目构建路径。

解决:右键项目 -> Properties -> Targeted Runtimes,勾选对应的 Tomcat 版本,让 Eclipse 自动把 Tomcat 的库附加到项目里;同时检查项目 src 下的 Jar 包是否真的在部署清单里,Build Path -> Libraries 里删掉显示红叉的包并重新 Add External JARs。

5.2 现象:页面中文全是问号或者乱码,登录页的提示信息都看不明白

原因:浏览器请求的编码和 JSP 页面的编码不一致,加上 MySQL 连接串里没指定 characterEncoding=utf8,导致请求参数和数据库往返的中文全部失真。老项目中很多 JSP 页面只在 page 指令里写了 contentType,没有加 pageEncoding,或者两个值互相冲突。

解决:把每个 JSP 文件头部的 page 指令统一改成 contentType="text/html; charset=UTF-8" pageEncoding="UTF-8",在 DBUtil 的连接串里加 characterEncoding=utf8,同时在项目中加一个全局过滤器,在 doFilter 里对 request 和 response 都设置 UTF-8 编码,这样所有 Servlet 处理请求参数时就不会再出现因为手写 getBytes 导致的中文乱码问题。

5.3 现象:点击登录按钮后页面没有任何反应,浏览器报 404

原因:Servlet 的 @WebServlet 注解路径和表单提交的 action 路径不一致。很多表单里写的是绝对路径(比如 /login),而部署后项目名带了上下文路径,实际访问地址是 /项目名/login,直接写 /login 就找不到这个 Servlet。

解决:把表单 action 改成相对路径,比如 login.jsp 和 LoginServlet 在同一个项目内,action="login" 就够了;或者所有跳转都通过 JSTL 的 c:url 标签生成带上下文路径的 URL。排查这类问题时看浏览器地址栏跳到了什么地址,对比 web.xml 里的 servlet-mapping 或类上的 @WebServlet 注解路径。

5.4 现象:页面能打开,但列表一直空,数据库明明有数据

原因:逻辑判断类的问题居多,常见是两个:DAO 里查询条件拼了空字符串,SQL 变成了 WHERE student_name = '';或者 ResultSet 取字段名时写错了大小写和别名,取到一个 null 值导致对象封装失败。

解决:在 DAO 的 catch 块里打印 SQL 语句和参数值,把这些日志往控制台一贴,对照数据库执行一遍同样的 SQL,就能快速定位是条件问题还是字段名问题。养成这个习惯比在页面里翻代码效率高得多。

5.5 现象:Tomcat 能启动,但访问项目首页一直卡在 Loading

原因:Tomcat 的发布目录里有残留的旧版本文件,或者项目里的某个 Jar 包和 Tomcat 自带的库冲突,导致 Web 应用部署时某些类加载卡住了。这个问题在反复修改代码重启服务器的过程中特别容易出现。

解决:把 Tomcat 的 work 目录(Tomcat 根目录下)清空,Eclipse 里右键项目 -> Clean,再重启服务器。如果还不行,右键 Tomcat Server -> Clean 一个完整清理过程,把发布目录删掉重新部署。这类"改了没生效""重启还报旧错误"的怪问题,大多能用这一套组合拳解决。

6. 二次开发:把毕设从"能跑"改到"能用"的三个有效改造点

源码能跑通之后,你要考虑的是怎么把它从一个演示项目改造成一个拿得出手的完整作品。我建议按性价比排序做三个改造,每个都不复杂,但加在一起效果非常明显。

第一是给成绩列表加导出 Excel 功能。JavaWeb 项目里最实用的方案是使用 POI 库,在 Maven 里引入 poi 依赖后,写一个导出 Servlet,把查询结果逐行写入 Workbook,设置响应头的 ContentType 为 application/vnd.ms-excel,浏览器收到后就能直接下载。这个功能在教务场景里几乎必做,是你答辩现场最好的加分项。

第二是把系统设置模块的消息通知功能做成公告,实现方式是在数据库加一张 notice 表,管理员可以发布公告,学生登录首页时展示最新三条公告。这个改造不动原有表结构,只做新增,出问题的概率极低,却能直观展示系统的信息流转能力。

第三是改造权限校验的粒度。原系统的 Session 判断分散在每个 JSP 里,你可以抽一个 Filter 把所有需要登录的页面保护起来,在 web.xml 里配置 URL 拦截规则,这样比在页面写校验代码干净得多,也更符合你对"工程化"的表述。

拿导出功能举例,核心代码就十几行:

// ExportScoreServlet.java 片段 @WebServlet("/score/export") public class ExportScoreServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int courseId = Integer.parseInt(request.getParameter("courseId")); List<Score> list = new ScoreDao().findByCourseId(courseId); response.setContentType("application/vnd.ms-excel;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;filename=scores.xls"); // 在输出流里逐行写入表头和成绩数据 PrintWriter out = response.getWriter(); out.println("学号\t姓名\t成绩"); for (Score s : list) { out.println(s.getStudentNo() + "\t" + s.getStudentName() + "\t" + s.getScore()); } out.flush(); out.close(); } }

这段代码的思路是:把查询到的成绩数据按行输出到响应流,浏览器识别到响应头后以文件形式下载,表头用 \t 分隔列,保持和 Excel 默认导出的文本格式一致。改造完成后,成绩列表页加一个按钮指向这个 Servlet,整个功能就能落地。

从那以后我每次拿到类似的学生成绩管理系统源码,都会强制自己先走一遍完整的运行验证流程,把所有数据都添加、修改、查询、删除一遍,再开始动手改代码。这样做的好处是你对系统的数据流有了肌肉记忆,改动时能预判哪里有影响,回归测试的时间反而比瞎改省得多。这套源码作为毕设或者练手项目的底子,确实值得你花点时间跑通它、改透它,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 5:31:15

大模型编程新利器 Kiro 实测:Specs 与 Hooks 如何吊打 Cursor 工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 5:28:56

K8s + AIOps:构建Pod OOM自动定位与自愈体系

前阵子我们这套某在线服务的告警又响了&#xff0c;kubectl top pod看到内存已经摸到容器 limit 边缘&#xff0c;还没等我把第二张监控图点开&#xff0c;Pod 就直接进入了OOMKilled状态。那已经不是第一次了。这种场景做过容器平台运维的朋友应该都不陌生&#xff1a;内存泄漏…

作者头像 李华
网站建设 2026/10/18 5:28:31

Agent工程化实战:从Demo到生产的12大核心技术

2026年再聊Agent&#xff0c;画风跟两年前完全不一样。前两年大家晒的是“我用大模型自动写了个周报”&#xff0c;今年圈子里问得最多的却是“你的Agent怎么做到连续跑一个月不出事”。做demo的时候&#xff0c;一切都很美好&#xff1a;模型偶尔抽风&#xff0c;重跑一次就行…

作者头像 李华
网站建设 2026/10/18 5:28:17

上下文工程实战指南:六大核心技术系统性压制大模型幻觉

一次线上事故让我盯上了上下文工程。当时某个智能客服系统上线没两周&#xff0c;用户问“订单超过七天能不能退”&#xff0c;模型回答“根据规则可以办理”&#xff0c;但实际上运费险条款里明确写着“签收七天后不予受理”。客服主管把对话记录甩过来的时候&#xff0c;我第…

作者头像 李华
网站建设 2026/10/18 5:27:07

OPC-Client-X64.rar 实战:从连接 OPC DA 服务器到订阅采集与避坑指南

简介&#xff1a;这份资源是面向工业自动化领域开发者的OPC DA客户端开发包&#xff0c;基于COM/DCOM技术实现&#xff0c;适用于64位Windows环境下使用Visual Studio 2013构建与PLC等数据源通信的应用程序。包内包含OPC DA客户端动态库及配套工程文件&#xff0c;涉及IOPCItem…

作者头像 李华
网站建设 2026/10/18 5:26:45

STM32学习 SPI通讯协议

SPI&#xff08;Serial Peripheral Interface&#xff09; 是一种由摩托罗拉&#xff08;Motorola&#xff09;公司开发的高速、全双工、同步串行通信协议。它主要用于短距离通信&#xff0c;常见于微控制器与传感器、存储器、显示屏等外设之间的连接。SPI通讯协议1. 核心特点全…

作者头像 李华