
简介这是一套面向高校计算机相关专业学生的Java Web课程设计资源采用ServletJSPBootstrapMysql技术栈实现学生信息管理系统适合作为期末大作业、课程设计或Java入门练手项目。压缩包共82个文件约12.03MB包含20个java源文件、21个class编译文件、15个jsp页面、6个css与5个js前端资源以及数据库脚本、jar依赖、图片素材和说明文档覆盖从后端逻辑到前端界面的完整结构。系统按servlet、dao、vo、web等分层组织涵盖学生、教师、验证码、注册登录、找回密码等模块源码经本地编译可运行评审分达98分内容经助教老师审定难度适中。目前已有163人学习下载适合需要快速搭建可运行项目、理解MVC分层与数据库交互的读者参考使用。1. 从一份学生信息管理系统源码说起ServletJSP 这套老架构为什么还值得动手跑一遍很多人第一次接触 JavaWeb 项目实战拿到的就是一份学生信息管理系统源码技术栈写着 JavaServletJSPBootstrapMySQL。第一反应往往是这都什么年代了Spring Boot 满天飞还看 Servlet但真把这份源码跑起来、改一遍、再自己重写一遍你会发现它反而是理解 JavaWeb 请求链路最省事的路径。Servlet 负责接收请求、调业务、转发数据JSP 负责把数据渲染成页面Bootstrap 负责让页面在浏览器里不难看MySQL 负责把学生、班级、成绩这些数据存住。四样东西各管一段边界清楚没有自动配置的黑匣子。这篇文章就围绕这套组合把环境搭建、数据库设计、Servlet 与 JSP 的配合、Bootstrap 页面改造、以及部署排错讲透适合刚学完 Java 基础、想找一个完整案例练手的人也适合工作几年但一直用框架、没亲手写过 Servlet 的人回头补课。2. 环境与数据库把 MySQL 和 Tomcat 先跑通2.1 JDK、Tomcat、MySQL 的版本选择与安装顺序这套技术栈对版本不挑剔但版本选错会带来一堆莫名其妙的报错。我的建议是JDK 用 8 或 11Tomcat 用 8.5 或 9MySQL 用 5.7 或 8.0。JDK 8 和 Tomcat 8.5 是当年这套源码最常跑的搭配兼容性最好。MySQL 8.0 在 Windows 10 上安装时记得选Use Legacy Authentication Method否则老版本 JDBC 驱动连不上。安装顺序上先装 JDK配好JAVA_HOME和Path再装 MySQL记住 root 密码最后解压 Tomcat不需要安装解压后在bin目录下双击startup.bat能弹出窗口且不闪退就说明 Tomcat 正常。验证 JDK 用java -version验证 MySQL 用mysql -u root -p能进命令行。# 验证 JDK java -version # 输出类似 java version 1.8.0_xxx # 验证 MySQL 服务是否启动Windows net start | findstr MySQL # 启动 TomcatWindows cd D:\apache-tomcat-8.5.xx\bin startup.bat这几条命令的作用分别是确认 Java 运行时、确认 MySQL 服务在跑、启动 Tomcat。参数上没什么可调的唯一要注意的是 Tomcat 默认端口 8080如果被占用去conf/server.xml里改Connector port。2.2 学生信息管理系统的库表设计三张表就够用学生信息管理系统的核心数据无非是学生、班级、用户登录用。不要一上来就设计十几张表先把最小可用模型跑通。下面是我常用的三张表结构。-- 学生表 CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, sno VARCHAR(20) NOT NULL UNIQUE COMMENT 学号, name VARCHAR(50) NOT NULL COMMENT 姓名, gender VARCHAR(4) DEFAULT 男, age INT, class_id INT, phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 班级表 CREATE TABLE class ( id INT PRIMARY KEY AUTO_INCREMENT, class_name VARCHAR(50) NOT NULL, teacher VARCHAR(50) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 用户表登录 CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(30) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, role VARCHAR(20) DEFAULT admin ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;字段说明sno加唯一索引防止学号重复这是学生管理系统里最常见的脏数据来源class_id是外键逻辑关联不强制加外键约束方便后期删班级不报错password留 64 位是为了以后换成 SHA-256 存储。字符集统一utf8mb4避免姓名里有生僻字或 emoji 时插入失败。提示MySQL 8.0 默认字符集已经是 utf8mb4但 5.7 需要手动指定建库时写CREATE DATABASE student_db DEFAULT CHARSET utf8mb4;。2.3 JDBC 连接配置与驱动版本对应关系Servlet 里访问 MySQL 靠 JDBC。驱动包mysql-connector-java的版本要和 MySQL 服务端匹配MySQL 5.7 用 5.1.x 驱动MySQL 8.0 用 8.0.x 驱动。驱动类名也不一样5.1.x 是com.mysql.jdbc.Driver8.0.x 是com.mysql.cj.jdbc.Driver。URL 上 8.0 要加时区和 SSL 参数。// DBUtil.java 连接工具类 public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/student_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse; private static final String USER root; private static final String PASSWORD 你的密码; static { try { Class.forName(com.mysql.cj.jdbc.Driver); // 8.0 驱动 } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }serverTimezoneAsia/Shanghai不加会报时区错误这是 MySQL 8.0 最常见的翻车点。useSSLfalse是关掉 SSL 警告本地开发无所谓。驱动 jar 包放到WEB-INF/lib下不要只放在项目 Build Path 里否则部署到 Tomcat 会报 ClassNotFound。3. Servlet 与 JSP 分工请求怎么进来页面怎么出去3.1 一个学生列表功能的最小 Servlet 实现Servlet 的职责很明确接参数、调数据库、把结果塞进 request、转发给 JSP。下面是一个查询学生列表的 Servlet。WebServlet(/student/list) public class StudentListServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ListStudent list new ArrayList(); String sql SELECT s.*, c.class_name FROM student s LEFT JOIN class c ON s.class_id c.id ORDER BY s.id DESC; 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.setSno(rs.getString(sno)); stu.setName(rs.getString(name)); stu.setGender(rs.getString(gender)); stu.setClassName(rs.getString(class_name)); list.add(stu); } } catch (SQLException e) { e.printStackTrace(); } req.setAttribute(studentList, list); req.getRequestDispatcher(/student/list.jsp).forward(req, resp); } }逻辑说明用LEFT JOIN把班级名一起查出来避免 JSP 里再查一次数据库。try-with-resources自动关闭连接防止连接泄漏。查询结果放进request作用域用forward转发而不是redirect因为要带着数据过去。参数上WebServlet注解代替了 web.xml 配置Tomcat 7 以上都支持。3.2 JSP 页面用 JSTL 渲染数据别写 Java 脚本片段JSP 里最忌讳写% %脚本片段可读性差还容易出错。用 JSTL 的c:forEach循环渲染。% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head title学生列表/title link relstylesheet href${pageContext.request.contextPath}/css/bootstrap.min.css /head body div classcontainer mt-4 h3学生信息列表/h3 table classtable table-striped table-hover thead classtable-dark tr th学号/thth姓名/thth性别/thth班级/thth操作/th /tr /thead tbody c:forEach items${studentList} varstu tr td${stu.sno}/td td${stu.name}/td td${stu.gender}/td td${stu.className}/td td a href${pageContext.request.contextPath}/student/edit?id${stu.id} classbtn btn-sm btn-primary编辑/a a hrefjavascript:del(${stu.id}) classbtn btn-sm btn-danger删除/a /td /tr /c:forEach /tbody /table /div /body /html${pageContext.request.contextPath}是拿项目上下文路径避免部署到 Tomcat 后路径写死导致 404。c:forEach的items对应 Servlet 里setAttribute的 key。JSTL 需要jstl.jar和standard.jar两个包放在WEB-INF/lib下。3.3 中文乱码的三个位置请求、响应、数据库中文乱码是这套技术栈的血泪经验三个地方都要设。请求参数用req.setCharacterEncoding(UTF-8)响应用resp.setContentType(text/html;charsetUTF-8)数据库连接 URL 里带characterEncodingutf8。JSP 页面头部pageEncodingUTF-8也不能少。Tomcat 8 以后 GET 请求默认 UTF-8但 POST 必须手动设否则插入的学生姓名全是问号。注意如果用了过滤器统一设编码Servlet 里就不用重复设了。过滤器写法是在doFilter里先request.setCharacterEncoding(UTF-8)再chain.doFilter。4. Bootstrap 页面改造让 JSP 看起来不像上世纪的产物4.1 引入 Bootstrap 的两种方式与国内加载优化Bootstrap 引入有两种CDN 和本地文件。做学生管理系统这种内网或本地演示项目建议下载到本地webapp/static目录下避免网络问题导致样式加载不出来。Bootstrap 5 去掉了 jQuery 依赖但很多老源码用的是 Bootstrap 3 或 4需要 jQuery。看源码里有没有jquery.min.js就能判断。!-- Bootstrap 5 本地引入 -- link relstylesheet href${pageContext.request.contextPath}/static/bootstrap/css/bootstrap.min.css script src${pageContext.request.contextPath}/static/bootstrap/js/bootstrap.bundle.min.js/scriptbootstrap.bundle.min.js已经包含 Popper不用单独引。路径用${pageContext.request.contextPath}开头保证部署后能找到。4.2 用 Bootstrap 栅格和表单组件重写学生新增页新增学生页面用栅格布局左边表单右边提示比原始的一列到底好看得多。div classcontainer mt-4 div classrow div classcol-md-6 offset-md-3 div classcard div classcard-header bg-primary text-white新增学生/div div classcard-body form action${pageContext.request.contextPath}/student/add methodpost div classmb-3 label classform-label学号/label input typetext namesno classform-control required /div div classmb-3 label classform-label姓名/label input typetext namename classform-control required /div div classmb-3 label classform-label性别/label select namegender classform-select option value男男/option option value女女/option /select /div button typesubmit classbtn btn-success保存/button /form /div /div /div /div /divcol-md-6 offset-md-3让表单居中card组件做卡片容器form-control和form-select是 Bootstrap 5 的表单类名。Bootstrap 4 里 select 用的是form-control5 改成了form-select混用会导致下拉框样式丢失。4.3 表格、分页与删除确认的交互细节列表页的删除按钮不要直接跳转用 JavaScript 弹确认框防止误删。function del(id) { if (confirm(确定删除这条学生记录吗)) { window.location.href ${pageContext.request.contextPath}/student/delete?id id; } }分页用 Bootstrap 的pagination组件后端 Servlet 接收page和pageSize两个参数SQL 里用LIMIT做分页。pageSize一般设 10太大页面加载慢太小翻页频繁。分页查询要单独写一个COUNT(*)查总数否则算不出总页数。5. 避坑与排查这套源码跑不起来时先看这几条5.1 现象访问页面报 404控制台无报错原因通常是 Servlet 的WebServlet路径和 JSP 里请求的路径对不上或者web.xml里metadata-completetrue导致注解不生效。解决检查WebServlet(/student/list)和表单action是否一致确认web.xml的web-app标签版本是 3.0 以上且没有metadata-completetrue。5.2 现象数据库连接报No suitable driver found原因有两种驱动 jar 没放进WEB-INF/lib或者驱动类名写错。解决确认mysql-connector-java-x.x.x.jar在WEB-INF/lib下MySQL 8.0 用com.mysql.cj.jdbc.Driver5.7 用com.mysql.jdbc.DriverURL 里jdbc:mysql://不能写成jdbc:mysql//。5.3 现象插入中文变成问号或乱码原因请求编码、响应编码、数据库字符集三者有一个没设对。解决按 3.3 节三个位置逐一检查数据库和表的字符集用SHOW CREATE TABLE student;确认是utf8mb4连接 URL 加characterEncodingutf8。5.4 现象Tomcat 启动报端口被占用原因8080 端口被其他程序占用常见的是另一个 Tomcat 或某些开发工具。解决netstat -ano | findstr 8080找到占用进程 PID任务管理器结束或者改conf/server.xml里的Connector port为 8081。5.5 现象JSP 页面样式全丢变成纯文本原因Bootstrap 的 CSS 路径写错或者用了 CDN 但网络加载失败。解决F12 看 Network 里 CSS 请求是不是 404本地引入时确认static/bootstrap/css/bootstrap.min.css文件真实存在路径用${pageContext.request.contextPath}开头。6. 从能跑到能改把这份源码变成自己的项目经验跑通只是第一步真正让这份源码产生价值的是改它。我一般会做三件事第一把登录密码从明文改成 SHA-256 加盐存储顺手加一个登录过滤器没登录的请求全部拦到登录页第二把 JDBC 裸写 SQL 抽成 DAO 层每个实体一个 DAO 类Servlet 里只调方法不写 SQL这样以后换 MyBatis 也容易第三给列表页加分页和模糊搜索搜索条件用PreparedStatement拼防止 SQL 注入。// 密码加密示例 public static String sha256(String raw, String salt) throws NoSuchAlgorithmException { MessageDigest md MessageDigest.getInstance(SHA-256); md.update((raw salt).getBytes(StandardCharsets.UTF_8)); byte[] digest md.digest(); StringBuilder sb new StringBuilder(); for (byte b : digest) { sb.append(String.format(%02x, b)); } return sb.toString(); }验证方法很简单注册一个用户看数据库里存的是不是 64 位十六进制串用错误密码登录应该失败用正确密码登录应该成功。盐值可以每个用户随机生成存到用户表里也可以全局固定学生项目里固定盐就够用。改造项改动位置验证方式密码加密注册/登录 Servlet数据库密码字段非明文登录过滤器Filter 类 web.xml未登录访问列表跳登录页DAO 分层新增 dao 包Servlet 里无 SQL 字符串分页搜索列表 Servlet JSP传 keyword 能过滤结果这套东西做完你对 Servlet 生命周期、请求转发与重定向的区别、JSP 作用域、JDBC 连接管理的理解会比看十篇教程都扎实。我自己的习惯是每接手一份老源码先不改功能只加日志和异常捕获把每个请求的入参和出参打出来跑一遍所有功能心里有数了再动手。这个习惯帮我省了很多后悔药。希望帮到你。本文还有配套的精品资源点击获取