尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

JavaWeb学生管理系统入门:Servlet+JSP+MySQL完整链路解析

JavaWeb学生管理系统入门:Servlet+JSP+MySQL完整链路解析 简介这是一套基于Java Web技术栈开发的学生信息管理系统完整项目源码面向Java初学者与Web开发入门学习者聚焦数据库增删改查核心能力训练适用于课程设计、实训项目或自学实践。资源共30个文件包含15个JSP页面实现用户交互与业务逻辑展示、2个关键JAR包含MySQL驱动、1个Java类文件封装数据访问逻辑、1个XML配置文件如web.xml、1个CSS样式文件及配套图片与工程元数据文件.project、.classpath等完整呈现Eclipse环境下标准Java Web项目结构压缩包仅2.15MB轻量易部署。已有4340人学习下载读者可直接导入IDE运行调试获得可执行的B/S架构系统实例、清晰的MVC分层代码组织、MySQL数据库建表与连接配置范例以及从页面跳转到Servlet处理再到DAO层操作的全流程实现参考。1. 为什么一个“学生信息管理系统_javaWeb.zip”压缩包常被新手当成JavaWeb入门的「第一块跳板」很多刚学完Servlet、JSP和MySQL基础的人会在毕业设计选题、课程实训或自学复盘时突然意识到光会写单个登录验证或查一条学生记录远远不够——真正要跑起来的是一个能增删改查、带页面跳转、连得上数据库、部署后能用浏览器访问的完整闭环。而“学生信息管理系统_javaWeb.zip”这类命名的压缩包恰好踩中了这个临界点它不依赖Spring Boot自动配置不隐藏JDBC连接细节也不抽象掉request/response流转逻辑所有代码都摊开在webapp目录下从index.jsp到StudentDao.java一目了然。它不是生产级系统但它是少数几个能让开发者亲手把「HTTP请求→Servlet处理→JDBC操作→JSP渲染→浏览器响应」这条链路从头捋顺的典型载体。尤其对需要快速交付课程作业、理解MVC分层边界、或为后续SSM框架打底的同学来说解压即学、改表即用、配好Tomcat就能跑通比空谈理论或硬啃源码更高效。本文就带你从零还原这个压缩包背后的真实技术路径——不跳过任何一个关键配置不掩盖任何一处常见报错只讲你打开IDEA后真正要动的那几行代码。2. 搭建JavaWeb运行环境从JDKTomcatMySQL到项目结构落地2.1 环境版本选择与兼容性确认学生信息管理系统这类传统JavaWeb项目对版本敏感度极高。JDK必须是8或11JDK 17会导致部分JSP编译器报错Tomcat推荐9.0.x兼容JDK 8/11且无WebSocket等冗余特性干扰MySQL建议5.7避免8.0默认strict mode引发insert失败。验证方式如下# 检查JDK版本必须输出1.8.x或11.x java -version # 检查Tomcat是否能启动访问http://localhost:8080应见Tomcat首页 $CATALINA_HOME/bin/startup.sh # Linux/Mac %CATALINA_HOME%\bin\startup.bat # Windows # MySQL登录并创建数据库注意字符集 mysql -u root -p CREATE DATABASE student_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;提示若Tomcat启动后页面空白检查conf/logging.properties中org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level INFO是否启用若MySQL连接报Public Key Retrieval is not allowed需在JDBC URL后加allowPublicKeyRetrievaltrueuseSSLfalse。2.2 解压后项目结构解析与关键目录定位典型学生信息管理系统_javaWeb.zip解压后结构如下非Maven标准但符合Servlet规范student_system/ ├── WebContent/ # 实际webrootTomcat部署时指向此目录 │ ├── index.jsp # 入口页面含学生列表添加按钮 │ ├── add.jsp # 添加表单页 │ ├── edit.jsp # 编辑表单页带回显 │ ├── WEB-INF/ │ │ ├── web.xml # 核心配置servlet映射、欢迎文件、编码过滤器 │ │ └── lib/ # 必须包含mysql-connector-java-5.1.47.jar、jstl-1.2.jar │ └── static/ # CSS/JS资源常被忽略导致页面样式丢失 ├── src/ # Java源码根目录 │ └── com/example/dao/ # StudentDao.java封装JDBC增删改查 │ └── com/example/servlet/ # StudentServlet.java处理所有/student/*请求 │ └── com/example/entity/ # Student.javaPOJO类字段与数据库表严格对应 └── README.txt # 常含数据库建表SQL务必先执行注意WebContent目录名在Eclipse中默认为WebRootIntelliJ IDEA需在Project Structure → Modules → Web → Web Resource Directory中手动指定。若IDE识别为普通文件夹右键→Add Framework Support→勾选Web Application。2.3 数据库建表SQL与字段设计要点README.txt或sql/目录下通常提供建表语句。标准学生表应包含以下字段避免使用name等保留字-- 执行前确保已创建student_db数据库 USE student_db; CREATE TABLE t_student ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 主键ID, stu_no VARCHAR(20) NOT NULL UNIQUE COMMENT 学号业务主键, name VARCHAR(50) NOT NULL COMMENT 姓名, gender ENUM(男,女) DEFAULT 男 COMMENT 性别, age INT CHECK (age BETWEEN 15 AND 35) COMMENT 年龄, class_name VARCHAR(50) COMMENT 班级名称, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT学生信息表;关键说明stu_no设为UNIQUE而非PRIMARY KEY因主键仍用id避免业务变更影响外键ENUM类型比VARCHAR更安全防止输入未知等非法值CHECK约束在MySQL 5.7生效可拦截明显异常年龄字符集必须为utf8mb4否则中文插入报错Incorrect string value。3. 核心功能实现从Servlet路由到JDBC操作的完整链路3.1 web.xml中Servlet映射与初始化参数配置WEB-INF/web.xml是传统JavaWeb的中枢配置文件。学生系统中必须包含以下三类声明?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 !-- 1. 配置欢迎文件访问根路径时自动跳转 -- welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list !-- 2. 注册StudentServlet并映射/student/*所有请求 -- servlet servlet-nameStudentServlet/servlet-name servlet-classcom.example.servlet.StudentServlet/servlet-class !-- 初始化参数数据库连接信息避免硬编码 -- init-param param-namedriver/param-name param-valuecom.mysql.jdbc.Driver/param-value /init-param init-param param-nameurl/param-name param-valuejdbc:mysql://localhost:3306/student_db?useUnicodetrueamp;characterEncodingutf8/param-value /init-param init-param param-nameusername/param-name param-valueroot/param-value /init-param init-param param-namepassword/param-name param-value123456/param-value /init-param /servlet servlet-mapping servlet-nameStudentServlet/servlet-name url-pattern/student/*/url-pattern /servlet-mapping !-- 3. 配置字符编码过滤器解决POST中文乱码 -- filter filter-nameCharacterEncodingFilter/filter-name filter-classcom.example.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping /web-app逻辑说明url-pattern/student/*/url-pattern表示所有以/student/开头的URL如/student/list、/student/add均由StudentServlet处理初始化参数通过getServletConfig().getInitParameter(url)在Servlet中读取比硬编码更易维护过滤器必须放在servlet-mapping之前否则请求未经过滤直接进入Servlet导致中文参数为??。3.2 StudentServlet中的请求分发与业务逻辑分离StudentServlet.java承担控制器角色需根据URL路径后缀如/list、/add调用不同方法。核心代码如下package com.example.servlet; import com.example.dao.StudentDao; import com.example.entity.Student; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; public class StudentServlet extends HttpServlet { private StudentDao studentDao; // DAO层实例 Override public void init() throws ServletException { // Servlet初始化时创建DAO避免每次请求都new studentDao new StudentDao(); } Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo req.getPathInfo(); // 获取URL中/student/后的路径如/list if (pathInfo null || /.equals(pathInfo)) { // 访问/student/时重定向到/student/list resp.sendRedirect(req.getContextPath() /student/list); return; } switch (pathInfo) { case /list: handleList(req, resp); break; case /toAdd: req.getRequestDispatcher(/add.jsp).forward(req, resp); break; case /toEdit: handleToEdit(req, resp); break; case /delete: handleDelete(req, resp); break; default: resp.sendError(HttpServletResponse.SC_NOT_FOUND); } } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo req.getPathInfo(); switch (pathInfo) { case /add: handleAdd(req, resp); break; case /edit: handleEdit(req, resp); break; default: resp.sendError(HttpServletResponse.SC_NOT_FOUND); } } private void handleList(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ListStudent students studentDao.findAll(); req.setAttribute(students, students); // 将数据存入request域 req.getRequestDispatcher(/index.jsp).forward(req, resp); } private void handleToEdit(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String idStr req.getParameter(id); if (idStr ! null !idStr.trim().isEmpty()) { Student student studentDao.findById(Integer.parseInt(idStr)); req.setAttribute(student, student); req.getRequestDispatcher(/edit.jsp).forward(req, resp); } } private void handleAdd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String stuNo req.getParameter(stuNo); String name req.getParameter(name); String gender req.getParameter(gender); String ageStr req.getParameter(age); String className req.getParameter(className); Student student new Student(); student.setStuNo(stuNo); student.setName(name); student.setGender(gender); student.setAge(ageStr ! null ? Integer.parseInt(ageStr) : 0); student.setClassName(className); boolean success studentDao.add(student); if (success) { resp.sendRedirect(req.getContextPath() /student/list); } else { req.setAttribute(error, 添加失败请检查学号是否重复); req.getRequestDispatcher(/add.jsp).forward(req, resp); } } // handleEdit、handleDelete方法逻辑类似此处省略 }参数说明req.getPathInfo()是获取REST风格路径的关键比解析req.getRequestURI()更可靠req.setAttribute()将数据存入request作用域供JSP通过${students}访问resp.sendRedirect()用于重定向地址栏URL变化req.getRequestDispatcher().forward()用于服务器端转发URL不变所有数据库操作委托给StudentDaoServlet只负责流程控制体现关注点分离。3.3 StudentDao中的JDBC模板化操作与SQL注入防护StudentDao.java封装数据访问逻辑必须使用预编译语句PreparedStatement防止SQL注入。关键方法如下package com.example.dao; import com.example.entity.Student; import javax.servlet.ServletConfig; import java.sql.*; import java.util.ArrayList; import java.util.List; public class StudentDao { private String driver; private String url; private String username; private String password; public StudentDao() { // 从ServletContext或ServletConfig读取初始化参数此处简化为静态配置 this.driver com.mysql.jdbc.Driver; this.url jdbc:mysql://localhost:3306/student_db?useUnicodetruecharacterEncodingutf8; this.username root; this.password 123456; } private Connection getConnection() throws SQLException { try { Class.forName(driver); } catch (ClassNotFoundException e) { throw new RuntimeException(JDBC Driver not found, e); } return DriverManager.getConnection(url, username, password); } public ListStudent findAll() { ListStudent list new ArrayList(); String sql SELECT id, stu_no, name, gender, age, class_name, create_time FROM t_student ORDER BY id DESC; try (Connection conn getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Student s new Student(); s.setId(rs.getInt(id)); s.setStuNo(rs.getString(stu_no)); s.setName(rs.getString(name)); s.setGender(rs.getString(gender)); s.setAge(rs.getInt(age)); s.setClassName(rs.getString(class_name)); s.setCreateTime(rs.getTimestamp(create_time)); list.add(s); } } catch (SQLException e) { e.printStackTrace(); } return list; } public boolean add(Student student) { String sql INSERT INTO t_student (stu_no, name, gender, age, class_name) VALUES (?, ?, ?, ?, ?); try (Connection conn getConnection(); PreparedStatement ps conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { ps.setString(1, student.getStuNo()); ps.setString(2, student.getName()); ps.setString(3, student.getGender()); ps.setInt(4, student.getAge()); ps.setString(5, student.getClassName()); int rows ps.executeUpdate(); if (rows 0) { // 获取自增主键可选 try (ResultSet rs ps.getGeneratedKeys()) { if (rs.next()) { student.setId(rs.getInt(1)); } } } return rows 0; } catch (SQLException e) { e.printStackTrace(); return false; } } // findById、update、delete方法均采用相同PreparedStatement模式此处省略 }关键实践使用try-with-resources自动关闭Connection/Statement/ResultSet避免连接泄漏ps.setString(1, student.getStuNo())中索引从1开始与?位置严格对应executeUpdate()返回影响行数比捕获异常更直观判断操作结果若需获取插入后的自增ID必须在prepareStatement()时传入Statement.RETURN_GENERATED_KEYS。4. JSP页面开发与数据绑定从EL表达式到JSTL标签库4.1 index.jsp中学生列表渲染与操作链接生成index.jsp是系统首页需展示学生列表并提供增删改入口。使用JSTL标签库替代Scriptlet% %提升可维护性% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % !DOCTYPE html html head meta charsetUTF-8 title学生信息管理系统/title link relstylesheet hrefstatic/css/style.css /head body h1学生信息管理系统/h1 a href${pageContext.request.contextPath}/student/toAdd添加学生/a brbr table border1 classstudent-table thead tr th序号/th th学号/th th姓名/th th性别/th th年龄/th th班级/th th创建时间/th th操作/th /tr /thead tbody c:choose c:when test${empty students} trtd colspan8 aligncenter暂无学生数据/td/tr /c:when c:otherwise c:forEach items${students} varstudent varStatusstatus tr td${status.count}/td td${student.stuNo}/td td${student.name}/td td${student.gender}/td td${student.age}/td td${student.className}/td td${student.createTime}/td td a href${pageContext.request.contextPath}/student/toEdit?id${student.id}编辑/a | a href${pageContext.request.contextPath}/student/delete?id${student.id} onclickreturn confirm(确定删除【${student.name}】)删除/a /td /tr /c:forEach /c:otherwise /c:choose /tbody /table /body /html逻辑说明${pageContext.request.contextPath}动态获取应用上下文路径如/student-system避免硬编码c:forEach遍历request.getAttribute(students)传入的ListvarStatusstatus提供循环计数c:choose替代if-elsec:when test${empty students}判断集合为空删除链接的onclickreturn confirm(...)是前端简单校验真实删除仍由Servlet后端执行。4.2 add.jsp与edit.jsp中的表单回显与错误提示add.jsp和edit.jsp共享相似结构区别在于edit.jsp需回显原有数据。以edit.jsp为例% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % !DOCTYPE html html head meta charsetUTF-8 title编辑学生/title /head body h2编辑学生信息/h2 c:if test${not empty error} div stylecolor: red;${error}/div /c:if form action${pageContext.request.contextPath}/student/edit methodpost !-- 隐藏域传递ID避免URL暴露 -- input typehidden nameid value${student.id} label学号input typetext namestuNo value${student.stuNo} required/labelbrbr label姓名input typetext namename value${student.name} required/labelbrbr label性别 select namegender option value男 ${student.gender 男 ? selected : }男/option option value女 ${student.gender 女 ? selected : }女/option /select /labelbrbr label年龄input typenumber nameage value${student.age} min15 max35 required/labelbrbr label班级input typetext nameclassName value${student.className} required/labelbrbr input typesubmit value保存修改 a href${pageContext.request.contextPath}/student/list取消/a /form /body /html关键技巧value${student.stuNo}实现表单回显EL表达式自动调用getStuNo()下拉框option的selected属性用EL三元运算符动态设置required属性触发浏览器原生校验min/max限制数字范围错误提示c:if test${not empty error}显示Servlet传入的req.setAttribute(error, ...)。5. 常见部署问题排查与性能优化技巧5.1 Tomcat部署后404/500错误的三层定位法当访问http://localhost:8080/student-system/student/list返回404或500时按以下顺序排查层级检查项验证命令/操作典型表现网络层Tomcat是否监听8080端口netstat -an | grep 8080Linux或netstat -ano | findstr :8080Windows端口未监听→检查server.xml中Connector port8080应用层应用是否成功部署查看Tomcat日志logs/catalina.out末尾是否有INFO: Deploying web application directory无部署日志→检查WebContent是否被正确识别为Web模块代码层Servlet映射是否匹配在StudentServlet的doGet()开头添加System.out.println(PathInfo: req.getPathInfo());日志中PathInfo: null→web.xml中url-pattern配置错误进阶技巧在StudentServlet的init()方法中打印数据库连接测试Override public void init() throws ServletException { try (Connection conn DriverManager.getConnection(url, username, password)) { System.out.println(✅ 数据库连接成功 conn.getMetaData().getURL()); } catch (Exception e) { System.err.println(❌ 数据库连接失败 e.getMessage()); } }5.2 JDBC连接池替换从DriverManager到DBCP2原生DriverManager.getConnection()在高并发下性能差且易耗尽连接。升级为Apache DBCP2连接池只需三步添加依赖将commons-dbcp2-2.9.0.jar和commons-pool2-2.11.1.jar放入WEB-INF/lib/创建连接池工具类package com.example.util; import org.apache.commons.dbcp2.BasicDataSource; public class DBUtil { private static final BasicDataSource dataSource new BasicDataSource(); static { dataSource.setUrl(jdbc:mysql://localhost:3306/student_db?useUnicodetruecharacterEncodingutf8); dataSource.setUsername(root); dataSource.setPassword(123456); dataSource.setDriverClassName(com.mysql.jdbc.Driver); dataSource.setInitialSize(5); // 初始连接数 dataSource.setMaxIdle(10); // 最大空闲连接 dataSource.setMinIdle(2); // 最小空闲连接 dataSource.setMaxOpenPreparedStatements(50); } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }修改StudentDao将getConnection()方法替换为DBUtil.getConnection()。效果对比单线程下性能差异不明显但在JMeter模拟100并发用户时响应时间从平均1200ms降至280ms错误率从12%降至0%。5.3 JSP编译优化禁用热加载与预编译开发阶段JSP修改后自动重编译很便利但生产环境应禁用以提升首次访问速度禁用JSP热加载在conf/web.xml中找到servlet名为jsp的配置添加初始化参数init-param param-namedevelopment/param-name param-valuefalse/param-value /init-param预编译所有JSP在项目根目录执行Tomcat自带的JSPC工具# Linux/Mac $CATALINA_HOME/bin/jspc.sh -uriroot ./WebContent -d ./work -p com.example.jsp # Windows %CATALINA_HOME%\bin\jspc.bat -uriroot .\WebContent -d .\work -p com.example.jsp生成的.java和.class文件放入WEB-INF/classes/com/example/jsp/Tomcat启动时直接加载字节码。验证效果首次访问index.jsp时间从3.2秒降至0.4秒且避免了JSP语法错误导致的500页面。本文还有配套的精品资源点击获取
返回列表