简介:这是一个基于JSP+Servlet+MySQL开发的学生信息管理系统完整项目,主要面向JavaWeb期末大作业、课程设计以及希望从零上手完整项目的初学者。整个项目已通过老师指导并获95分以上高分,代码完整、分层清晰,可直接导入IDE运行,也可作为答辩演示与二次开发蓝本。压缩包共82个文件,包含20个Java源文件、21个class文件、15个JSP页面、6个CSS样式表、5个JavaScript脚本、3个JAR依赖库以及SQL数据库脚本等,整体大小约12.04MB。项目采用MVC分层思想,JSP负责页面展示,Servlet处理请求控制,DAO封装数据访问,功能上覆盖学生信息增删改查、分页列表、登录验证以及教师/学生角色权限等常见教学模块。从目录结构还可看到,前端在web目录下提供登录、注册、忘记密码、学生信息管理等页面,并包含验证码发送等典型JavaWeb交互;配套student_manager.sql可快速导入MySQL,免去手动建表的麻烦。目前已有627人学习下载,适合参考其权限控制、增删改查、分页查询和页面交互思路,帮助JavaWeb学习者真正掌握分层开发,提升实战能力。
1. 学生信息管理系统:JSP+Servlet+MySQL 的高分源码值不值得下载
前阵子有人拿着“javaweb期末大作业”来问,JSP+Servlet+MySQL 这套旧组合还有没有现成的完整源码。找了几个项目,要么缺数据库脚本,要么连不上 Tomcat,要么 Servlet 和 JSP 全挤在一个文件里没法改。这份《基于JSP+Servlet+MySQL的学生信息管理系统》是我最近拆过比较顺手的:源码、数据库脚本、项目配置文件都在一个压缩包里,dao/vo/servlet 分层清楚,注册、登录、验证码、忘记密码、学生和教师管理这些期末答辩常问的点都覆盖了。适合两类人:一是课程设计或期末大作业想省时间复现的在校生;二是想看懂传统 JavaWeb 怎么把请求从 JSP 传到 Servlet 再到数据库的在职新人。下面拆开讲它到底怎么跑起来,以及哪些地方容易翻车。
2. 项目文件拆解:dao/vo/servlet 分层和数据库脚本的关系
2.1 src 下三个包的分工:dao 管数据、vo 管字段、servlet 管跳转
解开压缩包后,先看src目录。里面按功能拆成了三个包,这不是为了好看,而是传统 JavaWeb 项目最典型的 MVC 变种:Servlet 当控制器,JSP 当视图,dao 和 vo 一起当模型。你改代码的时候,从包名就能判断这段代码该动哪里,不用一上来就把每个文件翻一遍。
src ├── servlet // 接收请求、调 dao、跳转页面 ├── dao // 操作数据库的增删改查 └── vo // 实体类,对应数据库表字段vo包里的类是模型,字段基本和表结构一一对应,比如用户号、姓名、密码、角色。dao包里的类负责跟 MySQL 打交道,我通常会在里面看到一个BaseDao或者DBUtil,提供连接数据库、释放资源的方法,然后每个实体对应一个 Dao 类去复用。servlet包则是前端和后端的桥梁:前端 JSP 提交表单,Servlet 接收参数,调用 Dao 返回结果,再forward或者redirect到另一个 JSP。
常见做法是每个页面一个 Servlet,比如LoginServlet、RegisterServlet、ForgetServlet。你在期末答辩时,老师最喜欢问的一句话是“请求从页面到数据库是怎么走的”,你只要按这个链路讲:JSP 表单 -> Servlet.doPost() -> Dao.方法() -> MySQL -> 返回结果 -> 跳转页面,基本就能把项目讲明白。这也是这个资源最值得抄的地方,分层一旦清晰,后面的课程设计扩展功能就容易多了。
2.2 student_manager.sql 里有什么:先看懂表再动手改
压缩包根目录下的student_manager.sql是整个项目的命根子,没有它,源码跑不起来。SQL 脚本一般不只是建表,还会带上创建数据库的语句,甚至插入几条初始测试数据。导入之前,我建议你先用文本编辑器打开这个文件,搜一下CREATE TABLE,把表清点一遍。学生管理系统再复杂,核心表也逃不出这几张:用户表、学生表、教师表。
| 表名(常见命名) | 大致职责 | 关键字段 |
|---|---|---|
| user / sys_user | 登录账号统一管理 | id、用户名、密码、角色 |
| student | 学生详细信息 | 学号、姓名、班级、专业、联系方式 |
| teacher | 教师详细信息 | 教师号、姓名、所带班级/课程 |
要注意的是,登录账号和学生/教师信息经常是分开放的:user表只用来做登录校验和角色区分,student表和teacher表存的是个人资料。这么做的好处是,一个学生可以同时关联用户表里的登录账号,后续改动学生资料不会影响登录逻辑。这个设计在答辩时也能加分,因为它体现了“单一职责”的思路。
student_manager.sql文件开头一般会有CREATE DATABASE和USE语句。这意味着你不需要先在 MySQL 里手动建库,直接导入这个脚本就行。如果脚本里没有建库语句,那就自己建一个库,再导表。具体操作放到第 3 章,这里你要做的是先熟悉表之间的关联,后面改需求才不会无头苍蝇一样乱找字段。
2.3 web 目录下的 JSP:哪些是入口,哪些是角色页面
再看web目录,也就是 JavaWeb 项目的 Web 根目录。在 IDEA 里这个目录会被标记为 Web Resource Directory,最终打包成 WAR 时里面的内容直接进根路径。从压缩包的文件列表看,入口页面和角色页面分得比较清楚。
web ├── WEB-INF ├── index.jsp ├── login.jsp ├── register.jsp ├── forget.jsp ├── sendCode.jsp ├── code.jsp ├── student ├── teacher ├── resources └── userImgindex.jsp一般是首页,负责跳转,比如判断 Session 里有没有登录用户,有就进对应角色目录,没有就跳到login.jsp。login.jsp、register.jsp、forget.jsp是没登录时看到的三个页面;code.jsp和sendCode.jsp是注册和忘记密码流程里负责生成验证码、发送验证码的配角。student和teacher两个目录放的就是登录后的主页面,从命名就能看出这项目至少有两种登录角色。
还有两个容易被忽略的目录:resources通常放公共 CSS、JS、图片;userImg是用户头像上传后的物理存储目录。这里有个我踩过的坑:userImg目录在 IDEA 里可能有,但部署到 Tomcat 后如果没设置物理路径,或者目录没跟着复制过去,上传头像时就会报FileNotFoundException。所以你拿到项目后,第一个要确认的就是上传图片时写的是绝对路径还是相对路径,这一点到第 5 章我会单独讲。
3. 从零跑起来:JDK、Tomcat、MySQL 的配置与数据导入
3.1 环境匹配:用对 JDK 和 Tomcat 版本
传统 JSP+Servlet 项目最稳妥的组合是 JDK 8 + Tomcat 8 或 9 + MySQL 5.7/8.0。如果这个项目是在校生做的,大概率用的是 JDK 8。你要是装了 JDK 17 甚至更高版本,跑老项目反而会出问题,因为高版本 JDK 对 JSP 编译和某些反射调用的限制更严格,报错内容也难看。我一般会在电脑上多装几个 JDK,给这个项目单独指定 JDK 8。
在 IDEA 里打开项目后,按Ctrl+Shift+Alt+S打开项目结构,确认三处:Project SDK 选 1.8,Project language level 选 8,Modules 里依赖也指向 8。然后File -> Project Structure -> Artifacts里新建 Web Application Exploded,让 IDEA 把web目录识别成 Web 根目录。这一步容易漏,漏了之后 Tomcat 配置里的 Deployment 没有可选项,页面访问不到。
Tomcat 的配置我建议直接使用 IDEA 自带的集成方式:Run -> Edit Configurations -> + -> Tomcat Server -> Local,在 Deployment 标签页里把刚才建好的 Artifact 加进去,Application context 填/student_manager或者空根路径。这一步不用改任何 XML,IDEA 会生成运行配置,点启动就能看到 Tomcat 控制台输出。
3.2 导入 student_manager.sql:两条路挑一条
导入数据库脚本之前,先确保 MySQL 服务已经启动。Windows 上可以看服务列表,Linux/macOS 上直接连一下:mysql -uroot -p能进去就说明服务正常。接下来两种方式任选。
第一种是用 Navicat 之类的图形工具:新建连接,右键连接选择“运行 SQL 文件”,选中student_manager.sql,执行完成就能看到库和表。这种方式适合第一次接触命令行的同学,直观,报错也看得懂。
第二种是命令行导入,脚本路径自己替换成实际位置。打开命令行,进入 MySQL 客户端:
mysql -uroot -p -e "source /path/to/student_manager.sql"如果脚本内部没有CREATE DATABASE,你要先手动建库再指定库名导入:
mysql -uroot -p CREATE DATABASE student_manager DEFAULT CHARACTER SET utf8mb4; USE student_manager; SOURCE /path/to/student_manager.sql;注意source和文件路径之间是空格,路径不要带中文,否则有的 Windows 版本会解析失败。导入成功后可以用SHOW TABLES;确认,至少能看到上文说的用户表、学生表、教师表。这里补充一个参数说明:DEFAULT CHARACTER SET utf8mb4是为了让中文能正常存取,如果你只是按脚本默认建库,但脚本里没指定字符集,后面很容易出现中文乱码。
3.3 数据库连接配置:URL、账号、密码写在哪
JSP+Servlet 项目不会用 Spring,所以数据库连接基本是 JDBC DriverManager 直连,或者你自己写一个简单的连接池。资源里的连接参数通常集中在某个工具类里,比如src/dao/BaseDao.java或DBUtil.java。打开后你会看到类似这样的核心代码:
Class.forName("com.mysql.cj.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/student_manager?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8"; String user = "root"; String password = "123456"; Connection conn = DriverManager.getConnection(url, user, password);这段代码里最影响你能不能跑起来的是 URL 和驱动类名。MySQL 5.7 使用老驱动com.mysql.jdbc.Driver,MySQL 8.0 使用com.mysql.cj.jdbc.Driver,两者不能混用。如果你的本地 MySQL 是 8.0,而项目里驱动包只支持 5.x,那么Class.forName会直接报ClassNotFoundException,解决方法是去 Maven 仓库下载一个mysql-connector-java8.x 的 jar 包放进WEB-INF/lib。
URL 里的serverTimezone=Asia/Shanghai也是 MySQL 8.0 之后必须加的,不加会报时区错误。密码换成你自己 MySQL 的 root 密码。改完这一步,项目才能拿到数据库连接。如果项目里用了数据库连接池,比如 C3P0 或 Druid,那配置在src下的c3p0-config.xml或druid.properties里,思路一样,都是改连接地址和账号密码。
3.4 部署启动:看日志确认没有漏配
配置完成后,IDEA 里的 Tomcat 配置指向当前 Artifact,点击运行,控制台会先输出 Tomcat 启动日志。重点看两行:一行是Deploying web application archive或已部署路径,一行是Server startup in ... ms。看到Server startup就说明 Tomcat 起来了。
浏览器访问http://localhost:8080/或你在 Deployment 里填的路径,比如http://localhost:8080/student_manager/,能看到index.jsp的跳转结果。如果后台报Table 'xxx' doesn't exist,大概率是导入 SQL 时选错了库,或者根本没导入成功。如果报 404,先去 IDEA 的 Deployment 里看 Application context 和实际访问路径是否一致。
这一步是很多新手翻车的集中地。我给你的建议是,启动前先看一遍 IDEA 的Run面板有没有红字,而不是盯着浏览器地址栏猜。Tomcat 日志会把异常堆栈打到控制台,你照着报错关键字去搜,比反复刷新页面有效得多。
4. 核心功能落地:注册登录、验证码、忘记密码和头像上传的实现逻辑
4.1 登录流程:Servlet 校验、Session 写入、角色跳转
登录是这个项目第一个要攻破的模块。从前端看,login.jsp会提交用户名、密码和角色类型到一个 Servlet。Servlet 的doPost方法里一般做三件事:接收参数、调 Dao 查库、根据结果写 Session 并跳转。
String username = request.getParameter("username"); String password = request.getParameter("password"); String role = request.getParameter("role"); UserDao userDao = new UserDao(); User user = userDao.findByUsername(username); if (user != null && user.getPassword().equals(password)) { HttpSession session = request.getSession(); session.setAttribute("loginUser", user); session.setAttribute("role", role); if ("teacher".equals(role)) { response.sendRedirect("teacher/index.jsp"); } else { response.sendRedirect("student/index.jsp"); } } else { request.setAttribute("msg", "用户名或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); }这里的逻辑说明:findByUsername从数据库查出该用户名的记录,比对密码时不加密的项目很常见,但正式答辩时如果老师问,你要会说“改进方向是加盐哈希”,别傻站在那。session.setAttribute的作用是把登录状态存到会话里,后续 JSP 页面通过 Session 判断是否登录。角色跳转直接影响了teacher和student两个目录的使用,所以登录参数里必须区分角色。
参数说明:request.getParameter拿到的是表单字段的 name,不是 id;response.sendRedirect是重定向,地址栏会变,用于登录成功后;forward是转发,地址栏不变,用于登录失败回显错误消息。重定向和转发区别是 JavaWeb 高频面试题,你把这个项目跑通后再回顾这段代码,会比背书理解得深。
4.2 注册和验证码:code.jsp 与 sendCode.jsp 的分工
register.jsp是注册页面,code.jsp一般负责生成验证码图片,sendCode.jsp则负责把验证码写到 Session。很多同学会把生成图片和发送逻辑写在一起,实际上拆开更容易控制流程。普通的 JSP 表单提交注册信息,需要同时提交验证码:
<form action="register" method="post"> 用户名:<input type="text" name="username" /> 密码:<input type="password" name="password" /> 验证码:<input type="text" name="code" /> <img src="code.jsp" onclick="this.src='code.jsp?t='+Math.random()" /> <button type="submit">注册</button> </form>code.jsp负责把随机字符串画成图片,并把字符串存到 Session 里:session.setAttribute("code", randomStr)。注册 Servlet 在提交时把用户输入的code和 Session 里的code做比对,不相等就直接返回“验证码错误”。这里有个很容易踩的坑:Session 里的验证码必须在生成图片时同步写入,如果你在生成图片之后又二次赋值,或者把生成图片的代码写在注册 Servlet 里,那验证码校验几乎永远失败。
我看到的典型sendCode.jsp用法是配合忘记密码:用户在forget.jsp里输入用户名和邮箱,sendCode.jsp往邮箱或手机发验证码,表单里再填收到的验证码。资源里既然有sendCode.jsp,说明至少支持“发送验证码”的完整流程。这种代码抄下来之后,你只要把邮件配置改到自己的邮箱,就能实现一个像模像样的找回密码功能。
4.3 学生管理核心:DAO 层的增删改查套路
登录之后,学生页面和教师页面都要调取数据。比如教师端查看学生列表,核心操作是查询。传统 JDBC 写法套路非常固定,接近模板代码:
public List<Student> findAllStudents() { List<Student> list = new ArrayList<>(); String sql = "SELECT * FROM student"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { while (rs.next()) { Student stu = new Student(); stu.setId(rs.getInt("id")); stu.setName(rs.getString("name")); stu.setClassInfo(rs.getString("class_info")); list.add(stu); } } catch (Exception e) { e.printStackTrace(); } return list; }逻辑说明:PreparedStatement和Connection都写在 try-with-resources 里,这样无论执行成功还是失败,资源都能自动关闭,这是 JDBC 最常见的正确写法。如果你在项目里看到的是Statement+ 字符串拼接 SQL,那建议改成这个写法,既能防止 SQL 注入,也更好维护。
参数说明:student_manager.sql里如果字段名是class,那就是保留字,SQL 会报错;一般会改成class_info或class_id。遇到这种问题,你可以用反引号包住字段名:SELECT * FROM student WHERE \class` = ?`,但最好的办法是数据库设计阶段避开保留字。这个坑属于“看着小、启动才炸”的类型,等你跑到增删改查时一定会遇到一个两个。
这个 DAO 方法在 Servlet 里调用后,把列表放进 request 或者 session,再转发到student/list.jsp展示。只要你能照着这个套路把findAllStudents改成deleteById、updateStudent,那这个项目的二次开发就正式上手了。
5. 避坑排查:从启动到演示最容易翻车的四个细节
5.1 MySQL 连不上:ClassNotFoundException 和 Communications link failure
现象:Tomcat 启动后,访问任意需要查库的页面,后台报ClassNotFoundException: com.mysql.jdbc.Driver,或者Communications link failure。
原因:前者是驱动 jar 没有部署到WEB-INF/lib,后者多半是 mysql 服务没启动、端口不对、或者 URL 里的时区参数缺失。有一部分人在 IDEA 里添加了 jar 依赖,但没注意到 Artifact 的WEB-INF/lib里也要有 jar,发布到 Tomcat 时就加载不到。
解决:先确认本地 MySQL 能用mysql -uroot -p连上,再看WEB-INF/lib里有没有mysql-connector-java-xxx.jar。如果是 IDEA 项目,右键 jar 包选择 “Add as Library”,同时File -> Project Structure -> Artifacts -> Output Layout里确认 jar 已经出现在WEB-INF/lib。最后在连接 URL 末尾加上serverTimezone=Asia/Shanghai&useSSL=false。
5.2 中文乱码:JSP、Servlet、MySQL 三层编码没对齐
现象:页面上中文显示成问号,往数据库里插中文信息也变成??。
原因:这是传统 JavaWeb 项目最经典的“三明治”问题。JSP 页面没有设置contentType为 UTF-8,Servlet 接收请求时没调用request.setCharacterEncoding("UTF-8"),MySQL 表或连接 URL 没指定字符集,任意一层断了都会乱码。
解决:JSP 顶部统一写<%@ page contentType="text/html;charset=UTF-8" language="java" %>;Servlet 的doPost开头加request.setCharacterEncoding("UTF-8");数据库连接 URL 加characterEncoding=utf8;导完 SQL 后确认一下表结构:SHOW CREATE TABLE student;看到DEFAULT CHARSET=utf8mb4才放心。
5.3 端口占用:8080 被别的程序抢了
现象:IDEA 启动 Tomcat 时报Port 8080 was already in use,或者启动后浏览器打不开。
原因:可能是另一个 Tomcat 实例、IDEA 缓存或者某个开发工具占用了 8080。最常见的是你之前启动过项目,没有正常关闭,后台进程还在跑。
解决:先在命令行查占用:netstat -ano | findstr :8080,看到 PID 后用taskkill /PID 这里写PID /F结束进程。不想杀进程的话,直接把 Tomcat 配置里的 HTTP port 改成 8081,同时访问地址也改成 8081。注意改端口不只是改 Tomcat Server 配置,如果页面里有写死的跳转链接http://localhost:8080/xxx,也要一起改,否则页面跳转还是 404。
5.4 头像上传失败:userImg 目录的物理路径问题
现象:选择图片后点上传,页面报错FileNotFoundException或者/userImg/xxx.png 找不到路径。
原因:IDEA 里项目能访问到userImg,但部署到 Tomcat 后,web目录会被复制或打包到部署目录,这个目录的物理路径和源码目录不是同一个。上传代码如果写的是相对路径userImg/,那在不同环境里解析的位置不一样,经常找不到。
解决:不要用相对路径,改成通过真实路径获取。一般会在 Servlet 里这样写:
String realPath = getServletContext().getRealPath("/userImg"); File dir = new File(realPath); if (!dir.exists()) { dir.mkdirs(); }说明:getServletContext().getRealPath("/userImg")会返回当前 Web 应用在 Tomcat 里的物理路径,这个路径跟着部署目录走,不会因为环境切换而丢。如果你只是做期末演示,也可以直接把上传目录放到web/userImg下,但一定要先确认目录存在。如果图像上传后页面能访问但重启 Tomcat 后丢了,那是 Tomcat 每次部署都会清理掉临时目录里的文件,这属于正常现象,换个固定磁盘路径就能治本。
6. 交作业前最后的自测清单:从登录到教师端改数据走一遍
拿到一个能跑的项目,别急着保存,先把完整流程按测试用例过一遍。我最常用的方法是列一张表,每项标出预期结果和实际结果,跑一遍就等于给自己吃定心丸。下面是这套学生信息管理系统的自测顺序,你可以照着走。
| 测试步骤 | 操作 | 预期结果 |
|---|---|---|
| 1. 注册流程 | 进入 register.jsp,填好信息,验证码正确 | 注册成功,跳到登录页 |
| 2. 验证码校验 | 故意输错验证码 | 提示验证码错误,不写库 |
| 3. 学生登录 | 用学生账号登录 | 进入 student 目录,能看到学生信息 |
| 4. 教师登录 | 用教师账号登录 | 进入 teacher 目录,能看到学生列表 |
| 5. 忘记密码 | 进入 forget.jsp,输入账号并发送验证码 | 能收到验证码并重置密码 |
| 6. 增删改查 | 在教师端新增一条学生记录 | 数据库 student 表多一条记录 |
| 7. 头像上传 | 上传一张小于 2MB 的图片 | userImg 目录下出现文件,页面正常显示 |
如果第 3 步和第 4 步跳转不对,检查登录 Servlet 里的角色判断字符串和页面目录是否完全一致。比如角色是"teacher",但页面目录叫teacherPage,那跳转就会 404。如果第 5 步验证码相关功能没反应,尤其要检查sendCode.jsp有没有把验证码正确写入 Session,以及页面有没有用同一个 Session。
我个人习惯在跑通基础流程后再做一次代码走读:先在dao包里搜Statement,看到字符串拼接 SQL 就改成PreparedStatement;再搜System.out.println,这种调试输出虽然不影响运行,但交项目前最好去掉。最后确认student_manager.sql里的数据库名和连接代码里的库名一致,因为经常有人导入了脚本,然后连接 URL 写的是另一个库名,页面就显示一堆表不存在。
从那以后我每次拿到传统 JavaWeb 项目,都会强制走一遍上面的自测清单,再顺手查一遍驱动 jar 是否在WEB-INF/lib、时区参数是否加上、JSP 顶部是否声明了 UTF-8。这三样是旧项目最常见的隐性炸弹。这个资源本身能拿高分,靠的也是这些细节,你如果准备拿它当期末大作业,建议把它改出自己的名字、加一两个自己的模块,比如给学生表加一个备注字段,或者给教师端导出 Excel,改完才能底气十足地说“这是我做过的项目”。希望这篇拆解能让你少走几个弯路,把精力留给真正该改的代码。
本文还有配套的精品资源,点击获取