简介:基于JavaWeb的学生学籍管理系统资料包,面向计算机相关专业正在做毕业设计的学生以及需要项目实战练习的Java学习者。资源将项目源码、数据库脚本与项目说明整合在一处,可直接部署运行,也可作为毕设选题的完整参考。压缩包共包含3个文件,以项目源码zip、数据库脚本sql和说明文档txt为主,整体仅9.21MB。系统采用JSP/Servlet/JDBC技术栈,配合MySQL数据库,基于B/S结构实现,内置学生、教师、管理员三种角色,覆盖考试管理、学生信息管理、教师信息管理、基本信息管理、后台通知及学生成绩查询统计等典型模块。已有3242人学习下载,对于需要快速搭建JavaWeb项目框架、梳理学籍管理业务流程的读者,这套源码加数据库脚本能提供从环境配置到功能实现的直观参照,并可在此基础上进行二次开发,贴合毕设答辩与实际应用要求。
1. 一个 JavaWeb 学生学籍管理系统:先看它能替你挡住哪些操心事
下学期选课结束,辅导员要逐班核对在校生信息,学籍变动还要走纸质流程。手里这套基于 JavaWeb 的学生学籍管理系统,就是把这个场景搬到了浏览器里:管理员登录后可以维护学生基本信息、按院系/班级/关键词检索、处理休学退学等状态变更。它适合两类人——一类是正在做毕设、想少熬夜的在校生,另一类是想快速搭一个内部 demo 的中小规模开发者。资源里除了完整源码,还有直接可导入 MySQL 的建库建表脚本。下面我按自己拆项目的习惯,从选型、工程结构、核心代码、数据库脚本到部署排错讲一遍,你照着跑完就能上手改。
2. 技术栈与工程结构:为什么是 JSP+Servlet,以及 IDEA 里怎么把它跑起来
很多同学看到“JavaWeb”第一反应是“太旧了吧,现在不都 Spring Boot 吗”。这个判断要分场景。毕设题目如果是“基于 JavaWeb 的学生学籍管理系统”,评审提问范围基本锁定在 JSP、Servlet、JDBC、MySQL 这一套上。Spring Boot 能做,但黑匣子太多,问到 Servlet 生命周期、Session 失效机制时,答案都被框架挡住了。反过来,JSP+Servlet+JDBC 每一层代码都写在明面上,好答。不少读者本来就是搜“javaweb 项目完整案例 mysql”来的,Spring Boot 反而不匹配题目。选型逻辑就一句话:题目写什么用什么;题目没写死,再考虑要不要升级到框架。
2.1 选型逻辑:这套经典组合在毕设里是加分项而不是减分项
一个典型请求是这样流动的:浏览器访问 /student/list,web.xml 或注解里的 URL 映射把请求交到 StudentServlet 的 doGet;Servlet 调用 StudentDao 去查 MySQL,拿到 List 后放进 request 作用域,再转发(forward)到 studentList.jsp;JSP 用 JSTL 和 EL 把数据渲染成表格。整个过程没有 Spring 那种自动装配,每一步都是显式编码,非常好讲清楚。如果你的毕设题目明确写了 Spring Boot,那资源里的 DAO 层可以平移到 MyBatis,Servlet 换成 Controller,JSP 也不是必须的——但那是另一套题目,不是这一套。
数据层我统一用一个 DBUtil 工具类,所有 DAO 都从这里拿连接。代码如下:
// util/DBUtil.java package com.demo.student.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { // MySQL 8.x 连接串,注意带 utf8 编码和时区参数 private static final String URL = "jdbc:mysql://localhost:3306/student_manage?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"; private static final String USER = "root"; private static final String PASSWORD = "123456"; static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }这个类的所有参数都值得留意:characterEncoding=utf8 解决中文乱码,serverTimezone=Asia/Shanghai 解决 MySQL 8.x 的时区报错,allowPublicKeyRetrieval=true 是应对 caching_sha2_password 认证。改成你自己的库名和密码后,原则上就不用再动其他代码。密码直接写在常量里,毕设场景没问题;如果是真实项目,我会改成读取配置文件或环境变量。
提示:Tomcat 10 以上把 javax.servlet 改名成了 jakarta.servlet,源码里所有 import javax 的地方会编译不过,所以先认准 Tomcat 9.x 再动手。
2.2 工程目录:每层放哪里,一眼看清
拿到源码包先别急着点 Run,先花五分钟把目录结构过一遍。常见做法是一个 Maven 工程或原生 Web 工程,按 controller(Servlet)、service、dao、bean、util 分包。src 下大致是:bean 放 Student、ClassInfo、User 这些实体;dao 放增删改查的 SQL 访问类;servlet 放登录、学生管理、班级管理、统计等控制类;util 放 DBUtil、MD5Util 这类工具。webapp 目录下 jsp 按功能分子目录,比如 admin/login.jsp、admin/studentList.jsp。
| 目录 | 职责 | 典型文件 |
|---|---|---|
| src/.../bean | 实体类,对应表字段 | Student.java、User.java |
| src/.../dao | 数据库访问,拼 SQL | StudentDao.java、UserDao.java |
| src/.../servlet | 请求控制和转发 | LoginServlet.java、StudentServlet.java |
| src/.../util | 工具类 | DBUtil.java、MD5Util.java |
| webapp/jsp | 页面展示 | login.jsp、studentList.jsp |
| webapp/WEB-INF | 配置文件 | web.xml |
我建议你拿到源码后先做一件事:把这些包名的前缀统一改成你自己的,比如 cn.edu.yourname.student。这样到了答辩现场,导师问到“这个包是干什么的”,你能从自己改过的代码里讲出来,而不像背别人的项目。如果源码是 Maven 工程,先确认 pom.xml 里的依赖拉下来了再部署,避免一启动就缺 jar 包。
2.3 IDEA 跑通一个 JavaWeb 项目:关键配置清单
这一步是最多人卡住的地方,配置项其实就五个。表格里是我反复试出来的组合:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| Project SDK | JDK 1.8 或 11 | 和 Tomcat 9 匹配最稳 |
| Tomcat 版本 | 9.x | 用 javax.servlet,10 以上是 jakarta 命名空间 |
| Artifact 类型 | war exploded | 支持改完 JSP 直接刷新,不用反复重启 |
| Application context | /student | 决定访问路径,统一用 http://localhost:8080/student/... |
| 数据库连接参数 | 见 DBUtil | 密码改成你自己的 |
配置顺序一般是:打开项目后进 File > Project Structure,确认 Project SDK 和 Language level;然后 Run > Edit Configurations,新增 Tomcat Server > Local,Deployment 里把 war exploded 加进去,并填上 Application context 为 /student。启动后再开浏览器访问。这里 90% 的翻车都在 Tomcat 版本和 Artifact 没选对,这两点先定死,后面就顺了。如果你用的是 Maven 工程,启动前在右侧 Maven 面板执行一次 clean package,把依赖完整拉下来,再继续部署。
3. 核心功能落地:从登录鉴权到学籍增删改查的分层写法
上一层把骨架搭好了,这一层我直接带你过三个最核心的功能,代码照着抄就能跑。之所以从这三个写起,是因为任何学籍系统最后演示时都绕不开这几条路径:登录、维护学生信息、按条件把数据捞出来。我在代码里简化了业务校验,但保留了完整的分层调用,方便你看懂数据怎么“从数据库流到 JSP”。
3.1 登录与 Session 拦截
登录是所有页面的入口。流程是:login.jsp 提交用户名和密码,LoginServlet 接收后调 UserDao 查库,比对通过就写入 session,然后重定向到 index.jsp;失败就回到登录页并带回提示。核心代码如下:
// servlet/LoginServlet.java package com.demo.student.servlet; import com.demo.student.bean.User; import com.demo.student.dao.UserDao; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; @WebServlet("/login") public class LoginServlet extends HttpServlet { private UserDao userDao = new UserDao(); protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException { req.setCharacterEncoding("utf-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); User user = userDao.findByUsernameAndPassword(username, password); if (user != null) { HttpSession session = req.getSession(); session.setAttribute("loginUser", user); session.setMaxInactiveInterval(30 * 60); // 半小时后过期 resp.sendRedirect(req.getContextPath() + "/index.jsp"); } else { req.setAttribute("msg", "用户名或密码错误"); req.getRequestDispatcher("/login.jsp").forward(req, resp); } } }这里有两个细节容易被忽略:第一,req.setCharacterEncoding("utf-8") 必须放在读取参数之前,否则 POST 中文就会乱码;第二,resp.sendRedirect 要带 req.getContextPath(),否则你部署成 /student 时重定向会丢掉上下文路径,跳到 404。至于密码,资源包里如果是明文存储,我会建议在 UserDao 里加一层 MD5 校验,用 util/MD5Util 对前端传值做摘要,再和库里的密文比较,这样答辩时能多讲一个安全点。
拦截器不是每个毕设都做,但我会建议加一个最轻量的 Filter,把所有 /admin/ 开头的请求都拦下来检查 session,否则评委可能问“我不登录直接访问学生列表怎么办”。Filter 实现 doFilter 时判断 session.getAttribute("loginUser") 是否为空,为空就跳回 login.jsp,否则放行。代码很短:
// filter/AuthFilter.java public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; if (request.getSession().getAttribute("loginUser") == null) { response.sendRedirect(request.getContextPath() + "/login.jsp"); } else { chain.doFilter(req, resp); } }这段过滤器是你在答辩时讲权限控制的最好素材:一句话说清“未登录用户访问 /admin/ 下的任何资源都会被重定向”,比写一百行权限框架实在。
3.2 学生信息增删改查:DAO 层的标准五连
学生管理是最核心的表格。实体 Student 对应数据库 tb_student 字段,DAO 里就是 insert、delete、update、selectById、selectList 五个方法。我把最常出错的 insert 和 update 抽出来看:
// dao/StudentDao.java 节选 public boolean insert(Student s) { String sql = "insert into tb_student" + "(student_no, name, gender, birth_date, class_id, phone, status)" + "values(?,?,?,?,?,?,?)"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, s.getStudentNo()); ps.setString(2, s.getName()); ps.setString(3, s.getGender()); ps.setDate(4, s.getBirthDate()); ps.setInt(5, s.getClassId()); ps.setString(6, s.getPhone()); ps.setString(7, s.getStatus()); return ps.executeUpdate() > 0; } catch (SQLException e) { e.printStackTrace(); return false; } }所有字段都用占位符 ?,不要用字符串拼接 SQL,这是我能给的最强建议:它既防 SQL 注入,又避免学号里带单引号时把 SQL 语法炸掉。birth_date 是 java.sql.Date,如果你实体里用的是 java.util.Date,要记得在 DAO 层转一下,这是最常见的类型不匹配报错来源。
删除我建议做逻辑删除而非物理删除:给 tb_student 加一个 is_deleted 字段,删除操作 update is_deleted=1,列表查询自动过滤。理由是在校生档案有连续性,误删之后没有后悔药。真要做物理删除,也一定加个二次确认弹窗。
3.3 分页与组合条件检索
学籍管理系统的数据量不大,但演示时最好看的分页一定要有。分页 SQL 我用的是 LIMIT ? OFFSET ?,配合一个统计总数的方法。组合条件就是动态拼 where,条件越多越要小心参数顺序,先拼 SQL 再依次传参数:
// dao/StudentDao.java 分页查询 public List<Student> search(String keyword, Integer classId, int page, int size) { StringBuilder sql = new StringBuilder("select * from tb_student where is_deleted=0"); List<Object> params = new ArrayList<>(); if (keyword != null && !keyword.trim().isEmpty()) { sql.append(" and (name like ? or student_no like ?)"); params.add("%" + keyword + "%"); params.add("%" + keyword + "%"); } if (classId != null && classId > 0) { sql.append(" and class_id = ?"); params.add(classId); } sql.append(" order by student_no limit ? offset ?"); params.add(size); params.add((page - 1) * size); // 执行 SQL 并封装返回 }这段代码的关键在参数顺序:like 的两个值要在 classId 之前先加入,最后两页是 size 和 offset。经常有同学在这个顺序上翻车,报“Parameter index out of range”,其实就是参数和占位符没对齐。页面上我一般配一个下拉框选班级,一个文本框做模糊搜索,条件任意组合都走这个方法,前端只需改传参不变接口。
统计功能是学籍管理系统容易被问到的加分项:查每个班的人数、每个专业的总数、男女比例,一条 group by 就够。导出 Excel 可以用 Apache POI,把列表数据写入 XSSFWorkbook,再通过 resp 的 OutputStream 写回浏览器。注意设置响应头 Content-Disposition,文件名带 .xlsx,否则浏览器会当成普通文本下载。POI 部分源码包里一般会带工具类,没有的话自己写一个也不复杂,核心就十几行。
4. 数据库脚本:建表、初始化数据与 MySQL 8 连接参数
拿到资源包里的 .sql 脚本,第一件事是在本地 MySQL 里新建一个空库,然后把脚本导进去。不要直接在当前已有的业务库里执行,因为脚本里的 create table 可能会和现有表名撞车。下面按我的拆包习惯,把脚本拆成三层看:建库建表、初始化数据、约束与索引。看懂这三层,后面改字段、加表都顺手。
4.1 核心表结构:学生表、班级表、用户表的关系
学籍管理系统最简单的表规模是四张:sys_user 存登录账号,tb_major 存专业,tb_class 存班级,tb_student 存学生。有的版本还会加 tb_course 和 tb_score 做成绩模块。建表脚本如下:
create database if not exists student_manage default character set utf8mb4; use student_manage; create table sys_user ( id int primary key auto_increment, username varchar(50) not null unique, password varchar(100) not null, real_name varchar(50), role varchar(20) default 'ADMIN' ) engine=InnoDB default charset=utf8mb4; create table tb_major ( id int primary key auto_increment, major_name varchar(100) not null, department varchar(100) ) engine=InnoDB default charset=utf8mb4; create table tb_class ( id int primary key auto_increment, class_name varchar(100) not null, major_id int, grade varchar(10), foreign key (major_id) references tb_major(id) ) engine=InnoDB default charset=utf8mb4; create table tb_student ( id int primary key auto_increment, student_no varchar(20) not null unique, name varchar(50) not null, gender char(2), birth_date date, class_id int, phone varchar(20), email varchar(100), address varchar(200), status varchar(20) default '在校', is_deleted tinyint default 0, foreign key (class_id) references tb_class(id) ) engine=InnoDB default charset=utf8mb4;字段类型有三个地方注意:学号 student_no 用 varchar 20,不要用 int,因为学号是 0 开头的字符串;性别 gender 用 char(2) 就行;status 我建议用 varchar 存中文状态,比如“在校”“休学”“退学”“毕业”,比存 0/1 数字在页面上更容易直接展示。is_deleted 是逻辑删除标记,列表查询都要带 where is_deleted=0。
4.2 初始化数据:管理员账号和演示数据
脚本里一般自带一条管理员账号,常见的是 admin/admin123 或 admin/123456。如果你希望演示时有层次感,可以再多初始化一个操作员账号。插入语句如下:
insert into sys_user (username, password, real_name, role) values ('admin', 'e10adc3949ba59abbe56e057f20f883e', '系统管理员', 'ADMIN'); insert into tb_major (major_name, department) values ('计算机科学与技术', '信息工程学院'), ('软件工程', '信息工程学院'), ('会计学', '经济管理学院'); insert into tb_class (class_name, major_id, grade) values ('计科2301', 1, '2023'), ('软件2301', 2, '2023'), ('会计2301', 3, '2023'); insert into tb_student (student_no, name, gender, birth_date, class_id, phone, status) values ('2023001001', '张伟', '男', '2004-03-12', 1, '13800000001', '在校'), ('2023001002', '李娜', '女', '2004-07-25', 1, '13800000002', '在校');上面密码 e10adc... 是 123456 的 MD5 值。如果脚本里存的是明文,建议你把这句改成 MD5 版本,登录逻辑里也相应加一层校验。演示数据不用太多,每个班放三五个就够,重点是把不同状态(在校、休学、毕业)都覆盖到,因为评委最喜欢问“休学学生怎么查、还显示在哪里”。
4.3 外键、索引与级联策略
这张表设计里有几个关键选择值得在答辩时讲。第一,班级和专业之间用外键关联,删除专业时如果班级仍在引用,数据库会拒绝执行,这比应用层判断更可靠。第二,tb_student.class_id 外键的级联策略我建议设为 SET NULL 而不是 CASCADE,因为误删一个班级,不应该连学生档案一起消失。MySQL 默认是 RESTRICT,也可以直接用默认,防止误删。第三,索引建在哪,直接看查询条件:student_no 已有唯一索引,like 查询的 name 可以加普通索引;class_id 作为外键会自动建索引,不用重复建。
alter table tb_student add index idx_student_name (name); alter table tb_class add index idx_class_grade (grade);组合查询时,索引和 like 的配合是“最左前缀”规则。%keyword% 这种写法用不上索引,但如果改成 keyword%(前缀匹配),就能命中普通索引。实际学籍系统里按学号精确查是主要场景,所以不必太纠结百分号放左还是放右。
4.4 从脚本到本地库:导入的三种方式和连接参数
导入数据库脚本最省事的是用 Navicat / DataGrip 直接运行 .sql 文件;也可以命令行导入,先建库再执行:
mysql -u root -p student_manage < student_manage.sqlIDEA 里也可以在 Database 面板右键运行 SQL 文件。无论哪种方式,导入后先跑一句 show tables; 确认四张表都在,再跑 select count(*) from sys_user; 确认账号存在。
很多同学卡在“脚本导入成功但程序连不上”,多半是 MySQL 8 认证方式和 SSL 的问题。连接串里这几个参数按下面的值填,基本不会再报错:
| 参数 | 值 | 作用 |
|---|---|---|
| useUnicode | true | 配合 characterEncoding 传输中文 |
| characterEncoding | utf8 | 与数据库字符集保持一致 |
| useSSL | false | 本地开发不需要加密连接 |
| allowPublicKeyRetrieval | true | 解决 caching_sha2_password 的公钥获取报错 |
| serverTimezone | Asia/Shanghai | 解决时区差 8 小时 |
5. 避坑手册:部署运行学籍管理系统时的五个高频翻车点
下面这些坑,是我把同一套 JavaWeb 项目在不同机器、不同 MySQL 版本、不同 Tomcat 版本下复现时踩出来的。按出现频率从高到低排,每个都按“现象→原因→解决”来写,你可以直接对照处理。
5.1 坑一:IDEA 启动 Tomcat 后访问页面 404
现象:启动日志正常,但浏览器访问 http://localhost:8080 能出 Tomcat 首页,访问你的项目路径就是 404。
原因:Tomcat 默认根路径不是你的项目,访问时必须带上下文路径。还有可能是 Artifact 没部署到 Deployment。
解决:确认 Run Configuration 里 Deployment 下有你的项目,Application context 填 /student,然后访问 http://localhost:8080/student/login.jsp 或 http://localhost:8080/student/ 下的具体页面。改完 context 要重启 Tomcat,热部署对 context 修改不生效。
5.2 坑二:登录永远提示用户名或密码错误
现象:账号在数据库里存在,但无论怎么输入都提示错误,甚至直接在数据库里改密码也无效。
原因:最常见是密码存储方式和你代码的校验方式不一致。比如库里的值是明文,代码却用 MD5 摘要比对;或者反过来。
解决:打开 sys_user 表看 password 字段的值。如果是 32 位十六进制密文,登录代码就要做 MD5;如果是一串明文,代码直接等值比对即可。把表和代码统一成同一种策略,这个坑就消失了。排查时先在数据库工具里用这条账号手动执行一次查询,确认 SQL 能查出记录,再怀疑代码。
5.3 坑三:JSP 页面中文全部变成问号
现象:登录页和列表页标题栏正常,但输入中文并保存后,数据库里显示 ??,列表里也全都乱码。
原因:编码链路有三个环节,任意一处断了都会乱码:页面编码、请求传输编码、数据库连接编码。
解决:JSP 顶部写 pageEncoding="utf-8";Servlet 读取参数前执行 req.setCharacterEncoding("utf-8");JDBC URL 带 characterEncoding=utf8。这三处有一处遗漏就乱码。我一般再配一个 CharacterEncodingFilter 做统一处理,一劳永逸。另外检查 MySQL 库表是否建成了 utf8mb4,老库可能是 latin1,那也要改。
5.4 坑四:MySQL 8 连接报 Public Key Retrieval is not allowed
现象:换了一台电脑或从 MySQL 5.7 换到 8.0 后,启动时直接报 SQLNonTransientConnectionException,提示 Public Key Retrieval is not allowed。
原因:MySQL 8 默认使用 caching_sha2_password 认证,本地开发没有配置 SSL 时,RSA 公钥交换会被安全策略拦截。
解决:JDBC URL 加 allowPublicKeyRetrieval=true 和 useSSL=false。如果还报错,可以把账号改成 mysql_native_password 认证,但能用参数解决就不动账号。遇到这个报错,先看 URL 再查账号,别一上来就重装驱动。
5.5 坑五:修改学生信息后页面还是旧数据
现象:执行 update 后,用数据库工具查表数据已变,但页面刷新还是老样子。
原因:两类,一类是 JSP 页面或浏览器缓存,另一类是 DAO 层事务没有提交。
解决:先用数据库工具确认数据是否真的更新。如果数据没变,检查 JDBC 是否 setAutoCommit(true),或者手动调 conn.commit()。如果数据已变,页面加 Ctrl+F5 强制刷新,JSP 响应的 HTTP 头也可以加 no-cache。这个问题 80% 是事务没提交,优先查那里。
如果你按上面的顺序走完还没解决,把 IDEA 日志里的异常栈原样贴到搜索引擎里,比盲改配置快得多。JavaWeb 的报错信息都带行号,定位起来其实不难。
6. 部署验收与答辩演示:一份我能直接执行的检查清单
拿到这套资源后,我建议你按下面顺序做一遍验收,而不是直接打开浏览器乱点。先启动 MySQL,导入 student_manage.sql;修改 DBUtil 里的账号密码;IDEA 配好 Tomcat 9 和 Artifact 后启动;用 admin/123456 登录;新增一个学生、编辑、再删除;用学号模糊搜索;打开统计页看分组人数;退出登录后直接访问 /admin/studentList 验证拦截。这一轮走完,系统才算真正在你手里跑通。
| 检查项 | 预期结果 | 对应模块 |
|---|---|---|
| 数据库脚本导入 | student_manage 库出现四张表 | student_manage.sql |
| 登录与拦截 | admin 登录成功,未登录跳回 login.jsp | LoginServlet + AuthFilter |
| 学生增删改查 | 新增后列表可见,编辑后字段更新,删除后列表消失 | StudentDao |
| 分页与搜索 | 每页 5 条,按班级筛选加姓名模糊搜索正常 | StudentDao.search |
| 导出 Excel | 下载文件能打开,列字段与列表一致 | POI 导出代码 |
答辩演示的顺序也很有讲究。我的习惯是“先让评委看到界面,再讲实现,最后抛边界”。开始先登录,顺手在地址栏演示“未登录访问被拦截”的效果,这能立刻把权限话题引出来。接着展示学生列表分页、按班级下拉筛选、按姓名/学号模糊搜索,这三个操作覆盖了数据库索引、动态 SQL、分页三个知识点。然后新增一个学生信息,切到数据库工具里查这条记录,评委看到数据和界面同步,会相信这不是写死的。最后如果有统计图或导出 Excel 功能,放到收尾,因为它能引出 group by 和 POI 文件流这类加分点。
这里有两个我踩过的坑想分享。一次演示现场,我习惯性点了 Tomcat 的 Restart,结果 context 路径没对上,第一分钟全在修 404,气氛很尴尬。从那以后,我每次演示前都强制走一遍“先停服务、再点 Rerun、浏览器先访问一次登录页”的流程,确认登录页能出再开始讲。另外一个习惯是演示前先在数据表里执行 select count(*) from tb_student; 确认演示数据还在,缺了就先补一条,避免现场“新增学生”点下去没有响应。愿你拿着这套代码能少熬两个通宵,希望帮到你。
本文还有配套的精品资源,点击获取