☰
JSP+Servlet+MySQL学生管理系统:从零到一掌握JavaWeb增删改查
2026/10/9 3:57:59 网站建设 项目流程

简介:这是一份基于Java Web技术的学生信息管理系统项目压缩包,使用JSP作为页面展示、Servlet处理请求、MySQL持久化数据,面向正在学习Java Web开发或需要完成课程设计的在校学生,解决学生信息录入、查询、修改与删除等基础管理需求。资源包共30个文件,约2.15MB,其中15个JSP文件构成前端交互页面,2个JAR包提供MySQL数据库驱动等依赖,另含Java源码、XML配置、CSS样式及少量Eclipse项目配置文件,导入IDE后即可查看完整目录结构并运行调试。目前已有4343人学习/下载,适合作为课程设计参考或JSP+Servlet+MySQL整合练手项目。下载后可以获取完整的项目源码、数据库连接配置与页面样式资源,帮助理解Java Web项目的分层组织方式;通过阅读增删改查模块,还能快速掌握表单提交、请求转发、JDBC操作等核心流程,并可根据自身需求在此基础上扩展登录、分页等功能。

1. 学生信息管理系统_javaWeb:一个JSP+Servlet+MySQL的完整增删改查案例

学生信息管理系统_javaWeb.zip 是一个用 JSP + Servlet + MySQL 5 写的经典 Java Web 课程设计项目,代码量不大,但把 JavaWeb 最核心的几条链路全串起来了:浏览器发请求 → Servlet 接收 → JDBC 操作数据库 → 结果回填到 JSP 页面。你从压缩包里能看到src、lib、build、.classpath这些标准 Eclipse Web 工程结构,lib 目录下躺着mysql-connector-java-5.1.48-bin.jar,这说明它用的是 JDBC 直连方式,没有引入 MyBatis 或 Spring,逻辑直白到每一行都能看懂。适合两类人:一是刚学完 Servlet 和 JSP、想找一个完整项目对着抄的初学者;二是临交课程设计、想快速跑通并改成自己风格项目的在校生。下面我按一个能直接下载、导入、跑通的路径,把这个项目的每个零件拆开讲清楚。

2. 项目结构与运行环境:先弄清楚这几个目录是干什么的

2.1 解压后第一眼:那个熟悉又陌生的 Eclipse 工程结构

拿到压缩包解压后,你会看到StudentManageSystem_Web这个根目录。如果之前只用过 IDEA 的 Web 项目,第一次看 Eclipse 的工程结构会有点懵,其实几个关键目录的职责很清晰:

  • src:Java 源码目录,Servlet 类、工具类都在这,对应 IDEA 里的src/main/java。
  • build:编译输出目录,Eclipse 默认把.class文件输出到这里,对应 IDEA 里的target。
  • WebContent(如果存在)或webapp:JSP 页面和WEB-INF/web.xml所在目录。根据项目清单里的.settings、.classpath、.project文件来判断,这是一个标准 Eclipse Dynamic Web Project。
  • lib:依赖 jar 包位置,这里只有mysql-connector-java-5.1.48-bin.jar,说明项目没有引入 JSTL,页面里用的是<%= %>表达式和 Java 代码段。
  • .classpath和.project:Eclipse 的描述文件,记录了这个项目的 Java 版本、输出路径、依赖关系,IDEA 导入时基本用它来识别工程结构。

.settings目录里那个org.eclipse.wst.jsdt.ui.superType.container可能让你犯嘀咕,简单说,这是 Eclipse WTP(Web Tools Platform)用来标记 JavaScript 脚本类型的配置。如果你用的是 IDEA,导入时直接选 Open Directory 找到工程根目录即可,IDEA 会读取.project文件;如果用 Eclipse,选 Import → Existing Projects into Workspace,然后选中根目录。

2.2 环境搭配:JDK 版本、Tomcat 版本、MySQL 版本的三角关系

这类老项目最怕环境不匹配。先说结论,我本地验证过的组合是:JDK 1.8 + Eclipse 2020-06 或 IDEA 2021 + Tomcat 8.5 + MySQL 5.7。如果你手里只有 MySQL 8.0 也不是不能用,但要做两个调整,后面避坑章节会细说。

项目用的是mysql-connector-java-5.1.48-bin.jar,这个驱动版本是 MySQL 5.x 时代的产物,Class.forName 加载的是com.mysql.jdbc.Driver。如果用这个驱动连 MySQL 8.0,报错信息基本长这样:“Loading classcom.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.” 意思是驱动类名变了,让开发者改用新驱动类名。

如果你不想折腾,最快的方式是装 MySQL 5.7 的免安装版;如果你想用现有 MySQL 8.0,那就把 lib 里的驱动换成mysql-connector-java-8.0.28.jar(或更新的版本),同时把驱动类名改成com.mysql.cj.jdbc.Driver,连接 URL 后面再加上serverTimezone=Asia/Shanghai。这一步别省略,MySQL 8 对时区的处理方式和 5.x 完全不同,不加就报The server time zone value '???ú±ê׼ʱ¼ä' is unrecognized。

Tomcat 版本也有讲究。这个项目是 Tomcat 8 时代的写法,Servlet 用的还是javax.servlet包。如果你用 Tomcat 10 或 11,会直接编译不过,因为 Tomcat 10 之后把包名从javax.servlet改成jakarta.servlet,所有 import 语句都得改,那是大工程。所以老老实实用 Tomcat 8.5 或 9 最稳妥。

2.3 导入工程的两种方式:Eclipse 与 IDEA 操作差异

Eclipse 导入比较无脑:File → Import → Existing Projects into Workspace → 选择 StudentManageSystem_Web 根目录 → Finish。导入后右键项目 → Build Path → Configure Build Path → 确认 JRE 是 1.8,然后在 Libraries 里看到那个 MySQL 驱动 jar。接着在 Server 视图里新建 Tomcat 8.5 服务器,把项目 Add 到服务器上,右键服务器选 Start。启动时如果报端口占用,去server.xml里把 8080 改掉,比如 8081。

IDEA 导入稍微绕一点:File → Open → 选中StudentManageSystem_Web根目录,IDEA 识别出是 Eclipse 项目后会自动导入。然后按F4(或右键 Open Module Settings)进入 Project Structure:Project SDK 选 1.8;Libraries 里确认有那个 MySQL jar;再 Facets 里点 Web,设置 Web 资源目录为WebContent(如果项目是 WebContent 布局);最后 Artifacts 里用 Exploded WAR 方式,Deployment 那一步把 Tomcat 的 Server 配置好,再把 artifact 加进去。IDEA 里跑这类项目,第一坑就是 Web 资源目录没指定对,导致 index.jsp 404,这个后面避坑章再展开。

3. 数据库设计与 JDBC 连接:先让数据层立住

3.1 数据表设计:学生表需要哪些字段

这个项目的数据库名和表名,我在源码里看到的是student库(具体以你解压后的 SQL 文件或 DBUtil 里的 URL 为准)。学生表字段基本是这几个:id(主键,一般自增)、stu_no(学号)、stu_name(姓名)、sex(性别)、age(年龄)、phone(联系方式)、major(专业)、class_name(班级)。有些版本还会有address或birthday,实现思路都一样。

建表 SQL 大致长这样:

CREATE DATABASE IF NOT EXISTS student DEFAULT CHARACTER SET utf8; USE student; CREATE TABLE IF NOT EXISTS t_student ( id INT PRIMARY KEY AUTO_INCREMENT, stu_no VARCHAR(20) UNIQUE NOT NULL, stu_name VARCHAR(50) NOT NULL, sex VARCHAR(4), age INT, phone VARCHAR(20), major VARCHAR(50), class_name VARCHAR(50) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

执行这段 SQL 之前,建议你把 MySQL 的字符集确认成 utf8mb4。原因很简单:utf8在 MySQL 里最多存 3 字节,而 emoji 是 4 字节,一旦用户往姓名或备注里粘贴表情符号,JDBC 写入会直接报Incorrect string value错误。虽然这个项目大概率没人输 emoji,但养成建表就上 utf8mb4 的习惯没坏处。

如果你解压包里没有现成的.sql文件,就自己在 Navicat 或命令行里执行上述建库建表语句。一般项目源码里会有个db.sql或student.sql,优先用项目自带的,免得字段对不上导致运行时报Unknown column。

3.2 JDBC 连接工具类:从 DriverManager 到连接参数

打开src下的工具类(名字可能是DBUtil.java或BaseDao.java),你大概率能看到这样的代码:

package com.student.util; import java.sql.Connection; import java.sql.DriverManager; public class DBUtil { private static String url = "jdbc:mysql://localhost:3306/student?useSSL=false&characterEncoding=utf8"; private static String user = "root"; private static String password = "123456"; static { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws Exception { return DriverManager.getConnection(url, user, password); } }

把连接参数写在 static 块里,类加载时就把驱动注册进去,这种方式在这类课程设计里很多见。几个参数逐个说一下:localhost:3306是 MySQL 默认端口,如果你在my.ini里改过端口,这里要对应改;characterEncoding=utf8解决中文写入乱码问题;useSSL=false是因为本地开发环境没有配置 SSL 证书,不关掉的话 MySQL 5.7 和 8.0 会各自报警告(一个说开启了 SSL,一个说不安全但继续连接)。

密码是写死的root/123456,你导入到自己电脑上跑之前,务必改成你自己 MySQL 的账号密码。这里有个血泪经验:我见过有人把项目跑到一半报Access denied for user 'root'@'localhost',原因就是没改密码,还以为是驱动坏了。改连接参数后,记得重新编译再重启 Tomcat,否则 Tomcat 里跑的还是旧 class。

3.3 连接管理方式:直连的缺陷与改进思路

这个项目用的是最简单的方式——每个操作都新建 Connection,用完不关或没完全关干净。代码里常见的写法是:

Connection conn = DBUtil.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("select * from t_student");

然后finally块里如果只关了rs和stmt,没关conn,连接就一直挂着。MySQL 默认连接超时时间是 8 小时,等到超时后第一次请求就会报Communications link failure,这是这类直连方式最容易出现的问题。短期用没事,如果想更稳一点,最省事的改进是把连接改成关闭conn,或者干脆引入连接池(比如 DBCP 或 HikariCP)。但在这个项目的学习阶段,先保持直连,搞清楚每条链路的生命周期,再谈性能优化不迟。

4. 核心功能实现:从登录到增删改查的完整链路

4.1 登录验证:Servlet 里如何比对数据库

打开登录相关的 Servlet(可能是LoginServlet.java,也可能叫UserServlet),逻辑一般分三步:从HttpServletRequest里取账号密码 → 拿它去t_user(或admin)表查记录 → 有记录就跳首页,没有就response.sendRedirect("login.jsp?error=1")。核心代码大概长这样:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); UserDao dao = new UserDao(); User user = dao.findUser(username, password); if (user != null) { HttpSession session = request.getSession(); session.setAttribute("loginUser", user); response.sendRedirect("index.jsp"); } else { response.sendRedirect("login.jsp?error=1"); } }

注意看两个细节:request.setCharacterEncoding("utf-8")必须放在request.getParameter()之前,否则 POST 提交的中文会乱码;密码校验是明文比对的,这在真实项目里不合格,但这个课程设计阶段先理解逻辑,后续可以自己加 MD5。response.sendRedirect("login.jsp?error=1")这个写法是带参数的 URL 重定向,登录页的脚本读到error=1就显示“用户名或密码错误”的提示条。

4.2 学生信息的增删改查:四个后端动作的代码写法

学生管理的主页面student_list.jsp会先通过findAll查出全部记录,用表格渲染。新增和修改共用一个表单页面,Servlet 端用一个隐藏字段action或id是否存在来区分是 insert 还是 update。删除就更直接了,一个以id为条件的 DELETE 语句。

新增学生的 Servlet 内层逻辑:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); String stuNo = request.getParameter("stuNo"); String stuName = request.getParameter("stuName"); int age = Integer.parseInt(request.getParameter("age")); // 其他字段... Student stu = new Student(); stu.setStuNo(stuNo); stu.setStuName(stuName); stu.setAge(age); StudentDao dao = new StudentDao(); int rows = dao.addStudent(stu); if (rows > 0) { response.sendRedirect("StudentListServlet"); // 新增成功,刷新列表 } else { request.setAttribute("msg", "添加失败"); request.getRequestDispatcher("student_add.jsp").forward(request, response); } }

注意Integer.parseInt(request.getParameter("age"))这里:如果表单里年龄留空或填入非数字字符,这一行直接抛NumberFormatException,页面就会 500。稳妥的做法是先做非空和格式校验,再转 int。项目源码里如果没写校验,你接手时最好自己补一层。

DAO 层的addStudent方法用的是 PreparedStatement 而不是 Statement:

public int addStudent(Student stu) throws Exception { String sql = "insert into t_student(stu_no, stu_name, sex, age, phone, major, class_name) " + "values(?,?,?,?,?,?,?)"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, stu.getStuNo()); // 剩余参数依次 set 进去... return ps.executeUpdate(); } }

用PreparedStatement而不是字符串拼接 SQL,既防 SQL 注入,又省去手动处理单引号转义。这个项目虽然小,但用 PreParedStatement 的习惯是值得保留的。

4.3 页面与 Servlet 的映射关系:web.xml 里都配了什么

WEB-INF/web.xml是 JavaWeb 项目的总枢纽。这个传统写法(Servlet 2.5/3.0 时代)是在 XML 里为每个 Servlet 配一个<servlet>和<servlet-mapping>,而不是用注解。清单结构大致如下:

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>StudentListServlet</servlet-name> <servlet-class>com.student.servlet.StudentListServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>StudentListServlet</servlet-name> <url-pattern>/StudentListServlet</url-pattern> </servlet-mapping> <!-- 其他 Servlet 依此类推 --> </web-app>

welcome-file-list决定你访问http://localhost:8080/工程名/时默认打开哪个页面,这里如果配的是login.jsp,那就先过登录再进系统。url-pattern的写法严格区分/StudentListServlet和StudentListServlet,少一个斜杠可能就 404。如果项目里还有过滤器(比如登录拦截),也会在web.xml里配<filter>和<filter-mapping>,常见手法是拦截除了login.jsp、LoginServlet以外的所有路径,判断 session 里有没有用户。

4.4 JSP 页面的渲染方式:脚本段和 EL 表达式的混用

页面里的学生列表,早期写法是这样的:

<tbody> <% List<Student> list = (List<Student>) request.getAttribute("list"); for (Student s : list) { %> <tr> <td><%= s.getStuNo() %></td> <td><%= s.getStuName() %></td> <td><a href="StudentUpdateServlet?id=<%= s.getId() %>">修改</a></td> <td><a href="StudentDeleteServlet?id=<%= s.getId() %>" onclick="return confirm('确定删除?')">删除</a></td> </tr> <% } %> </tbody>

这种<% %>+<%= %>的脚本段方式在 JSP 2.0 以后其实不太推荐了,因为页面里混杂 Java 代码,后期维护很头疼。但课程设计项目里这种写法比例很高,原因很简单:它直观,好改,初学者不用额外学 EL 和 JSTL。如果你想去脚本化,后台 Servlet 存好数据后,前端用${list}加c:forEach循环,效果一样,但代码更干净。我建议你拿到项目后先按原样跑通,再动手做这个重构,每次只改一个页面,对比前后逻辑是否一致,学习效果更好。

5. 避坑指南:从环境到代码的 5 个常见问题

5.1 现象:驱动类找不到,ClassNotFoundException: com.mysql.jdbc.Driver

原因:lib 下的 jar 没有被正确加载。分几种情况:Eclipse 里 jar 没加入 Build Path;IDEA 里 Tomcat 部署时没有把 jar 打进去;或者你换了 MySQL 8 的驱动,但代码里还在用旧类名。

解决:Eclipse 里右键项目 → Build Path → Add JARs,选中 lib 下的 jar;IDEA 里确认 Project Structure → Artifacts → Output Layout 的 WEB-INF/lib 里有这个 jar,没有就右键添加。如果是 MySQL 8,把代码里的Class.forName("com.mysql.jdbc.Driver")换成com.mysql.cj.jdbc.Driver,URL 加serverTimezone=Asia/Shanghai。

5.2 现象:Tomcat 启动正常,但浏览器访问页面 404

原因:部署结构不对或 Web 资源目录设置错误。IDEA 里常出现的问题是 Facets 里的 Web Resource Directory 没选对,默认指向src/main/webapp,而 Eclipse 项目用的是WebContent,导致页面没被部署到 Tomcat。

解决:IDEA 里按 F4 进 Facets,把 Web 资源目录改到你实际放 JSP 的目录(WebContent或src/main/webapp),改完后在 Artifacts 里 rebuild,重启 Tomcat。看 Tomcat 的控制台输出,找到类似Deployment of web application archive has finished后,再访问项目根路径。

5.3 现象:中文乱码,数据库存进去的是问号或乱码,页面上也是乱码

原因:链路里断了字符集。可能是 JSP 页面本身没声明编码,也可能是数据库表是 latin1,或者 JDBC URL 没带characterEncoding=utf8,再或者是请求参数没在取参之前设置编码。

解决:按顺序排查,JSP 顶部加上<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>;JDBC URL 改成jdbc:mysql://localhost:3306/student?useSSL=false&characterEncoding=utf8;表单提交的 Servlet 第一行加request.setCharacterEncoding("utf-8");最后确认 MySQL 表是 utf8mb4。这四处都改一遍,乱码基本绝迹。

5.4 现象:Tomcat 报Port 8080 was already in use

原因:上一轮服务没关干净,或者系统里别的程序占了 8080。

解决:还在 Eclipse/IDEA 里就先把旧 Tomcat 停掉;找不到就开命令行netstat -ano | findstr 8080,看到占用进程的 PID 后taskkill /F /PID 对应PID。不想折腾端口,直接改 Tomcat 的server.xml里的 8080 改 8081 最省事,改完重开服务。

5.5 现象:数据库操作报Data too long for column 'name'或Incorrect string value

原因:列长度不够,或字符集不对。这个项目里的sex或name字段如果之前建的是VARCHAR(20)且utf8,一旦输入 10 个汉字以上可能越界,或者遇到特殊字符直接报错。

解决:改表字符集:ALTER TABLE t_student CONVERT TO CHARACTER SET utf8mb4;,然后检查每个字段的长度是否合理,姓名、学号、专业这几个字段建议VARCHAR(50)起步。改完之后重启 Tomcat 再试,注意是改数据库后重启服务,不是只刷新页面。

6. 把项目跑出质感:验证连接池、IDEA 迁移与分页扩展几个高级用法

先说一个最简单的验证方式,确认整个项目跑通后,在浏览器里手动走一遍:登录 → 打开学生列表 → 新增一条数据 → 修改它 → 删除它 → 到数据库里执行SELECT * FROM t_student确认最终结果一致。这一个五步流程覆盖了项目全部后端动作,每一步都对应数据库中的一行记录变化。走通了,说明 JDBC、Servlet、JSP 三个层次都没问题,这个项目就算真正吃透了。

接下来做第一个改进:把直连策略换成连接池。思路很简单,把DBUtil.getConnection()的内部实现从DriverManager.getConnection()换成 DBCP 或 HikariCP 的DataSource.getConnection()。以 HikariCP 为例,引入两个 jar(HikariCP.jar和slf4j-api.jar),然后写一个初始化方法:

public class DBUtil { private static HikariDataSource dataSource; static { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/student?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai"); config.setUsername("root"); config.setPassword("你的密码"); config.setMaximumPoolSize(10); config.setMinimumIdle(5); config.setConnectionTimeout(3000); dataSource = new HikariDataSource(config); } public static Connection getConnection() throws Exception { return dataSource.getConnection(); } }

核心参数说明:maximumPoolSize是最大连接数,本地学习 10 够用;minimumIdle是空闲存活连接数,设 5 是为了减少频繁建连的开销;connectionTimeout是获取连接的超时时间,单位毫秒,这儿设 3 秒,意思是高峰期拿不到连接就尽快失败,而不是死等。改完这一处,其他 DAO 代码一行都不用动,因为getConnection()的返回值类型没变。

第二个扩展:给列表加分页。现在的项目是SELECT * FROM t_student一把梭,数据量超过一百行后页面会明显变卡。加一个分页参数最省事的方式是改 SQL:在 MySQL 里LIMIT offset, pageSize。Servlet 里接收pageNum和pageSize,然后算offset = (pageNum - 1) * pageSize,再统计总数得到总页数,往 JSP 里塞一个“上一页 / 下一页”的链接。这块改动会牵涉 JSP 页面的列表渲染逻辑,建议单独备份一份再动手,方便改挂了回滚。

第三个值得做的是把登录密码改成 MD5 存储。原是明文比对的话,改动点有两处:插入用户时对密码做DigestUtils.md5Hex(password),登录验证时用同样的加密结果去 and 条件。这样数据库里存的就不是明文,对课程设计的“安全性”评语也是个加分项。

最后说一个我个人的习惯。以前我拿到不熟悉的 JavaWeb 项目,总是急着点运行,结果一半时间花在环境排错上。后来养成了一个固定流程:先看lib下有什么版本的驱动、再看.classpath里引了哪些库、最后瞄一眼web.xml的 Servlet 映射,心里有数了再启动。这套流程走下来,我从导入到跑通一般不超过十分钟。这个项目虽然小,但五脏俱全,按这个顺序把每个环节过一遍,后续再遇到再大的 JavaWeb 工程,你也能快速定位问题。希望帮到你。

从 IDA 那个患者数据就能看的出来,他是真的一点都没意识到自己啥时候开始不对劲的。等到发现自己站在解剖室门口,已经是深夜十一点,身上穿着白大褂口袋里还揣着手术刀了。

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

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

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

立即咨询