ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JavaWeb学生信息管理系统实战:Servlet+JSP+Bootstrap+Mysql完整链路

JavaWeb学生信息管理系统实战:Servlet+JSP+Bootstrap+Mysql完整链路 简介这份资源是面向高校计算机相关专业学生的Java Web学生信息管理系统完整源码包采用ServletJSPBootstrapMysql技术栈适合作为期末大作业、课程设计或Java Web入门练手项目。项目难度适中源码经本地编译可运行评审分达98分内容经助教老师审定能较好满足学习与提交需求。压缩包共82个文件约12.03MB包含20个java源文件、21个class编译文件、15个jsp页面、6个css与5个js前端资源以及3个jar依赖、1个sql建表脚本和1个md说明文档覆盖后端Servlet、DAO、VO分层与前端页面、样式、脚本等模块并附使用说明便于快速部署。目前已有163人学习下载。读者可据此掌握用户注册登录、验证码、找回密码、教师与学生角色管理等典型功能的实现思路理解MVC分层结构与数据库设计直接用于课程设计参考或二次开发省去从零搭建的时间成本。1. JavaServletJSPBootstrapMysql 学生信息管理系统一套能跑通、能改、能交作业的完整链路很多同学第一次接触 JavaWeb 项目卡住的地方往往不是某个语法点而是「环境配好了、代码也下了但就是跑不起来」。这套基于 JavaServletJSPBootstrapMysql 的学生信息管理系统恰好是解决这个问题的典型样本它把 Java 基础、Servlet 请求处理、JSP 页面渲染、Bootstrap 前端布局和 Mysql 数据持久化串成了一条完整链路。适合谁适合正在做课程设计、毕业设计或者想用一个真实项目把 JavaWeb 知识串起来的人。它不追求高并发架构但胜在结构清晰、依赖少、每一层都能看懂。接下来我会按「环境怎么搭 → 数据库怎么建 → 后端怎么写 → 前端怎么接 → 坑在哪」的顺序把这条链路拆开讲透让你拿到源码后能真正跑起来而不是对着报错发呆。2. 环境与工程结构把 JDK、Tomcat、Mysql 三件套配到能跑2.1 版本选型为什么这套组合至今仍是教学主流这套技术栈的核心是 Servlet JSP它们依赖 Servlet 容器运行最常见的就是 Tomcat。选型上我一般建议JDK 用 8 或 11Tomcat 用 8.5 或 9Mysql 用 5.7 或 8.0。原因很直接——JDK 8 是绝大多数教学项目和旧版 Tomcat 的稳定搭配Mysql 5.7 的驱动包mysql-connector-java版本兼容性最好8.0 则需要把驱动类名从com.mysql.jdbc.Driver改成com.mysql.cj.jdbc.Driver并加上时区参数。很多「java 环境配置」的搜索热度高就是因为这一步没配对后面全是连锁报错。工程结构上标准 Maven Web 项目长这样student-manager/ ├── src/main/java/ # Servlet、DAO、实体类 ├── src/main/resources/ # db.properties 等配置 ├── src/main/webapp/ │ ├── WEB-INF/web.xml # 可选注解方式可省 │ ├── css/ js/ img/ # Bootstrap 静态资源 │ └── *.jsp # 页面 └── pom.xml # 依赖管理如果你拿到的是非 Maven 的 Eclipse 老项目那就把 jar 包放进WEB-INF/lib效果一样。关键是webapp目录必须是 Web 根目录JSP 放在这里才能被容器解析。2.2 依赖配置pom.xml 里必须锁死的三个坐标用 Maven 的话pom.xml里最关键的依赖是 Servlet API、JSP API 和 Mysql 驱动。注意 Servlet 和 JSP 的 scope 要设成provided因为 Tomcat 自带这两个包重复打包会冲突。dependencies !-- Servlet APITomcat 已提供scope 必须 provided -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency !-- JSP API同上 -- dependency groupIdjavax.servlet.jsp/groupId artifactIdjavax.servlet.jsp-api/artifactId version2.3.3/version scopeprovided/scope /dependency !-- Mysql 驱动8.0 用这个版本5.7 可用 5.1.x -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency !-- JSTLJSP 页面做循环和判断要用 -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency /dependencies参数说明scopeprovided表示编译时需要、打包时不带入避免和容器自带包打架Mysql 驱动版本要和数据库服务端匹配8.0 驱动连 5.7 库通常也能用但反过来容易出问题。JSTL 是 JSP 里写c:forEach的前提缺了它页面标签会原样输出。2.3 数据库连接db.properties 与工具类写法把连接信息抽到配置文件避免硬编码在 Java 里。src/main/resources/db.propertiesjdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/student_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 jdbc.usernameroot jdbc.password你的密码对应的 JDBC 工具类核心逻辑public class DBUtil { private static String url, user, pwd, driver; static { try (InputStream in DBUtil.class.getClassLoader() .getResourceAsStream(db.properties)) { Properties p new Properties(); p.load(in); driver p.getProperty(jdbc.driver); url p.getProperty(jdbc.url); user p.getProperty(jdbc.username); pwd p.getProperty(jdbc.password); Class.forName(driver); // 加载驱动8.0 可省略但保留更稳 } catch (Exception e) { throw new RuntimeException(数据库配置加载失败, e); } } public static Connection getConn() throws SQLException { return DriverManager.getConnection(url, user, pwd); } }逻辑说明静态代码块只在类加载时执行一次配置读一次就够serverTimezone不写会在 8.0 驱动下报时区错误这是「mysql 安装配置教程」里最常被忽略的一条。characterEncodingutf8保证中文不乱码。生产项目会换成连接池但教学项目用DriverManager足够少一层依赖少一层坑。3. 数据库设计学生表、用户表怎么建才不返工3.1 建库建表 SQL字段类型和约束一次定对学生信息管理系统的核心表就两张学生表和登录用户表。字段设计要提前想清楚不然后面改表结构很痛苦。CREATE DATABASE IF NOT EXISTS student_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE student_db; -- 学生表 CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, sno VARCHAR(20) NOT NULL UNIQUE COMMENT 学号, name VARCHAR(50) NOT NULL COMMENT 姓名, gender CHAR(2) DEFAULT 男, age INT, major VARCHAR(50), phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 用户表 CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, role VARCHAR(20) DEFAULT admin ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 初始化一个管理员 INSERT INTO sys_user(username, password, role) VALUES (admin, 123456, admin);参数说明字符集统一用utf8mb4比utf8多支持 emoji 和部分生僻字避免姓名乱码sno加UNIQUE约束从数据库层挡住重复学号比只在 Java 里判断可靠ENGINEInnoDB支持事务和外键是现在的默认选择。密码这里存的是明文教学够用但真实项目必须加盐哈希这点后面避坑章会再提。3.2 实体类与 DAO把 ResultSet 映射成对象实体类Student的字段要和表字段一一对应DAO 层负责增删改查。以查询全部和新增为例public class StudentDao { // 查询全部学生 public ListStudent findAll() { ListStudent list new ArrayList(); String sql SELECT id,sno,name,gender,age,major,phone FROM student ORDER BY id DESC; try (Connection conn DBUtil.getConn(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Student s new Student(); s.setId(rs.getInt(id)); s.setSno(rs.getString(sno)); s.setName(rs.getString(name)); s.setGender(rs.getString(gender)); s.setAge(rs.getInt(age)); s.setMajor(rs.getString(major)); s.setPhone(rs.getString(phone)); list.add(s); } } catch (SQLException e) { e.printStackTrace(); } return list; } // 新增学生 public boolean insert(Student s) { String sql INSERT INTO student(sno,name,gender,age,major,phone) VALUES(?,?,?,?,?,?); try (Connection conn DBUtil.getConn(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, s.getSno()); ps.setString(2, s.getName()); ps.setString(3, s.getGender()); ps.setInt(4, s.getAge()); ps.setString(5, s.getMajor()); ps.setString(6, s.getPhone()); return ps.executeUpdate() 0; } catch (SQLException e) { e.printStackTrace(); return false; } } }逻辑说明全程用PreparedStatement而不是Statement拼接字符串这是防 SQL 注入的基本功也是「javaweb 项目完整案例」里必须体现的规范。try-with-resources自动关闭连接、语句和结果集省掉手写finally的样板代码。ORDER BY id DESC让新增的学生排在最前符合使用直觉。注意rs.getInt(age)在字段为 NULL 时返回 0如果年龄允许为空实体类里要用Integer包装类型并配合rs.getObject判断。4. Servlet 与 JSP 协作请求怎么进、页面怎么出4.1 Servlet 处理流程一个请求的完整生命周期Servlet 是这套系统的后端入口。以学生列表为例浏览器访问/student?actionlistTomcat 根据WebServlet注解找到对应 Servlet调用doGet或doPostServlet 调 DAO 拿数据把结果放进request域再转发给 JSP 渲染。WebServlet(/student) public class StudentServlet extends HttpServlet { private StudentDao dao new StudentDao(); Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action req.getParameter(action); if (action null) action list; switch (action) { case list: req.setAttribute(students, dao.findAll()); req.getRequestDispatcher(/student_list.jsp) .forward(req, resp); // 转发URL 不变能带 request 数据 break; case delete: int id Integer.parseInt(req.getParameter(id)); dao.deleteById(id); resp.sendRedirect(req.getContextPath() /student?actionlist); break; default: resp.sendError(404); } } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); // POST 中文必须设且要在取参数前 Student s new Student(); s.setSno(req.getParameter(sno)); s.setName(req.getParameter(name)); s.setGender(req.getParameter(gender)); s.setAge(Integer.parseInt(req.getParameter(age))); s.setMajor(req.getParameter(major)); s.setPhone(req.getParameter(phone)); dao.insert(s); resp.sendRedirect(req.getContextPath() /student?actionlist); } }参数说明forward是服务器内部跳转request域数据能带到 JSPsendRedirect是让浏览器重新发请求用于增删改后防止刷新重复提交。req.setCharacterEncoding(UTF-8)只对 POST 体有效且必须在第一次getParameter之前调用否则中文乱码。GET 请求的中文乱码要在 Tomcat 的server.xml里给 Connector 加URIEncodingUTF-8。4.2 JSP 页面渲染用 JSTL 替代 Java 脚本片段JSP 里最忌讳写一堆% %脚本可读性差还难维护。正确做法是用 JSTL 标签配合 EL 表达式。% 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 hrefcss/bootstrap.min.css /head body div classcontainer mt-4 h3学生信息列表/h3 a hrefadd.jsp classbtn btn-primary mb-3新增学生/a table classtable table-bordered table-hover thead classtable-light trth学号/thth姓名/thth性别/thth年龄/thth专业/thth操作/th/tr /thead tbody c:forEach items${students} vars tr td${s.sno}/td td${s.name}/td td${s.gender}/td td${s.age}/td td${s.major}/td td a hrefstudent?actiondeleteid${s.id} classbtn btn-sm btn-danger onclickreturn confirm(确认删除)删除/a /td /tr /c:forEach /tbody /table /div /body /html逻辑说明c:forEach遍历request域里的students${s.sno}是 EL 表达式会自动调用 getter。Bootstrap 的table table-bordered table-hover三个类就能把表格做得干净container mt-4控制整体边距。删除按钮的onclick返回confirm结果点取消就不跳转这是最轻量的二次确认。注意 JSP 顶部pageEncoding和contentType都要写 UTF-8少一个都可能乱码。5. Bootstrap 前端与常见坑排查页面丑、乱码、连不上库怎么办5.1 Bootstrap 引入方式与布局要点Bootstrap 有两种引入方式CDN 和本地文件。教学项目建议下载到本地webapp/css和webapp/js避免断网打不开。核心就三个文件bootstrap.min.css、bootstrap.bundle.min.js含 Popper、以及可选的图标库。布局用栅格系统rowcol-*表单用form-control按钮用btn btn-*。登录页典型写法div classcontainer div classrow justify-content-center mt-5 div classcol-md-4 form actionlogin methodpost classcard p-4 h4 classtext-center mb-3学生信息管理系统/h4 input typetext nameusername classform-control mb-2 placeholder用户名 required input typepassword namepassword classform-control mb-3 placeholder密码 required button classbtn btn-primary w-100登录/button /form /div /div /divjustify-content-center让列水平居中col-md-4表示中等屏幕占 4 格共 12 格w-100让按钮撑满。这套写法不用写一行自定义 CSS 就能出效果是 Bootstrap 最实用的地方。5.2 避坑与排查五个高频翻车现场现象一页面中文全是问号或乱码。原因数据库字符集、连接 URL、JSP 页面编码、POST 请求编码四处任意一处不是 UTF-8 都会乱码。 解决数据库建库用utf8mb4URL 加characterEncodingutf8JSP 顶部写contentTypetext/html;charsetUTF-8Servlet 里 POST 先setCharacterEncoding(UTF-8)。四处对齐乱码必消。现象二启动报ClassNotFoundException: com.mysql.cj.jdbc.Driver。原因驱动 jar 没进WEB-INF/lib或 Maven 依赖没刷新或 8.0 驱动却写了旧类名com.mysql.jdbc.Driver。 解决确认依赖已下载检查db.properties里的驱动类名和实际 jar 版本一致。8.0 用com.mysql.cj.jdbc.Driver5.1 用com.mysql.jdbc.Driver。现象三连库报The server time zone value ... is unrecognized。原因Mysql 8.0 驱动要求明确时区URL 里没写serverTimezone。 解决URL 追加serverTimezoneAsia/Shanghai。这是「mysql 安装教程 8.0」之后最容易踩的一脚。现象四JSP 页面把c:forEach原样输出不解析。原因缺 JSTL 依赖或 taglib 的 uri 写错。 解决确认jstl-1.2.jar在依赖里页面顶部% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %一字不差。现象五删除后刷新页面又提交一次或新增重复。原因表单提交后直接forward到列表页浏览器刷新会重发上一次 POST。 解决增删改操作完成后一律用sendRedirect重定向到查询接口这就是常说的 PRG 模式能根治重复提交。6. 从能跑到好用分页、登录拦截与密码处理的进阶改法把系统跑起来只是第一步真正让它像个「系统」而不是「demo」还得补三块。第一块是分页。学生数据一多findAll全查出来页面会卡正确做法是 SQL 层分页SELECT ... FROM student LIMIT ?, ?配合SELECT COUNT(*)算总数Servlet 接收page和size两个参数JSP 底部渲染上一页/下一页。这里有个血泪经验LIMIT的偏移量是(page-1)*sizepage 从 1 开始别从 0 开始否则第一页永远是空的。第二块是登录拦截。每个后台 Servlet 都手动判断 session 太啰嗦用 Filter 统一处理WebFilter(/*) public class AuthFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; String uri request.getRequestURI(); // 放行登录页、登录接口和静态资源 if (uri.endsWith(login.jsp) || uri.endsWith(/login) || uri.contains(/css/) || uri.contains(/js/)) { chain.doFilter(req, resp); return; } Object user request.getSession().getAttribute(user); if (user null) { response.sendRedirect(request.getContextPath() /login.jsp); } else { chain.doFilter(req, resp); } } }参数说明WebFilter(/*)拦截所有请求放行名单要包含登录相关和静态资源否则登录页自己都被拦形成死循环。session 里存的user在登录成功时setAttribute写入退出时invalidate清掉。第三块是密码处理。前面建表时密码存了明文真实项目必须改。最省事的做法是用 JDK 自带的MessageDigest做 SHA-256 加盐public static String hash(String pwd, String salt) throws Exception { MessageDigest md MessageDigest.getInstance(SHA-256); md.update((pwd 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(); }登录时用同样盐值算一遍比对即可。盐值每个用户随机生成存进用户表这样即使库被拖走彩虹表也打不动。这套改法不引入额外依赖教学项目升级到「像样」的程度足够了。最后说个验证习惯每次改完 DAO 或 SQL先在 Mysql 命令行里把语句单独跑一遍确认能出结果再回 Java 里调。我踩过太多次「Java 报错其实是 SQL 写错」的坑把数据库层和代码层分开验证能省掉一半排查时间。这套学生信息管理系统源码的价值不在于它多复杂而在于每一层你都能改、能验证、能讲清楚为什么这么写——把这套链路吃透再去看 Spring Boot MyBatis 的项目会发现只是换了个更省事的壳。希望帮到你。本文还有配套的精品资源点击获取
返回列表