多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

JavaWeb课程设计实战:Servlet+JSP+MySQL学生信息管理系统从搭建到答辩

JavaWeb课程设计实战:Servlet+JSP+MySQL学生信息管理系统从搭建到答辩 简介一份面向JavaWeb课程设计与期末大作业场景的学生信息管理系统完整源码包覆盖学生信息、成绩、科目等核心管理模块代码附有详细注释即使是基础薄弱的新手也能快速理解业务逻辑适合课程设计、期末提交及项目起步参考。资源包共155个文件压缩后9.48MB主要包含Java源码及编译后的class文件、JSP动态页面、SQL建库脚本、XML框架配置另附CSS、JS等前端样式以及docx使用文档目录结构清晰便于按层检索和二次开发。目前已有543人学习下载是期末阶段被反复使用的课程设计资源。项目附带详细文档说明从数据库准备、连接配置到页面部署均有分步讲解下载后简单调整即可直接运行。系统功能完整、界面简洁能够满足期末大作业和课程设计答辩的需要也可作为深入学习JavaWeb项目的实用案例。1. 学生信息管理系统不是玩具这门 JavaWeb 大作业到底在考察什么期末前两周群里最常见的求救消息就是“JavaWeb课程设计期末大作业学生信息管理系统有没有源码数据库文档”。这个标题背后是一套非常典型的 JavaWeb 完整交付物用 Servlet/JSP 做后端和页面用 MySQL 建库存数据外加一篇能过查重的设计文档。它的核心并不复杂——登录、学生信息的增删改查、班级管理、分页和模糊查询但恰恰是这套“不复杂”的功能把前端表单提交、后端路由、JDBC 操作、MVC 分层全部串起来了。如果你正在为这门课熬夜标题里的“源码数据库详细文档”就是你的救命稻草但光跑通还不够答辩时老师一定会追问“数据库为什么这么建”“Servlet 请求怎么走的”。下面按课程设计最常见的实现方案从技术选型到跑通再到避坑和答辩给你一条可以复现的完整路径。2. 为什么是 Servlet JSP MySQL课程设计技术栈的选型逻辑与源码包结构2.1 选型逻辑Servlet/JSP 比 SpringBoot 更适合“讲清楚”很多同学拿到大作业第一反应是“能不能用 SpringBoot 写”我的建议是如果老师没硬性要求框架就别用。学生信息管理系统作为 JavaWeb 课程设计出现频率最高的是 JSP Servlet MySQL Tomcat而不是 SpringBoot 全家桶。原因很直接课程设计答辩考的是“你能不能讲清楚一个请求从前端到后端再到数据库的完整过程”。Servlet 充当 ControllerJSP 充当 ViewJavaBean 和 DAO 充当 Model三层结构一眼就能看懂。SpringBoot 把 Tomcat 内嵌、自动配置、ORM 封装全部藏起来了你写的时候很爽但老师一句“你的数据库连接在哪配置的”“Servlet 是哪一个类”就能把你问住。这不是说 SpringBoot 不好而是这门课的考察点就是“地基”不是“装修”。从交付物的角度看标题里“源码数据库详细文档说明”这种搭配也决定了技术栈不能太冷门。Servlet/JSP 相关教程多IDE 支持成熟网上能找到完整的案例参考。常见做法是项目里包含一个database.sql或student.sql脚本一张user表存登录账号一张student表存学生信息加一张class表存班级后端按servlet、dao、service、entity、util分包。数据库脚本一导入Tomcat 一部署登录页一开就是一个能演示的完整系统。对于要交差的场景“稳定跑通”比“技术新”重要得多。2.2 源码包里应该有哪些文件识别项目结构与运行入口拿到一个“学生信息管理系统源码”第一步不是急着点运行而是先认目录。一个标准的非 Maven JavaWeb 项目通常长这样StudentManager/ ├─ src/ │ ├─ com/student/entity/ # 实体类Student.java, User.java, ClassInfo.java │ ├─ com/student/dao/ # 数据访问层StudentDao.java, UserDao.java │ ├─ com/student/service/ # 业务层StudentService.java可选 │ ├─ com/student/servlet/ # 控制器LoginServlet.java, StudentServlet.java │ ├─ com/student/util/ # 工具类DBUtil.java, StringUtil.java │ └─ com/student/filter/ # 过滤器EncodingFilter.java, LoginFilter.java ├─ WebContent/ # 或 webapp/ │ ├─ index.jsp │ ├─ login.jsp │ ├─ student/ │ │ ├─ list.jsp │ │ ├─ add.jsp │ │ └─ edit.jsp │ ├─ css/ js/ │ ├─ WEB-INF/ │ │ ├─ web.xml │ │ └─ lib/ # mysql-connector-java-x.x.x.jar └─ database/ └─ student.sql如果是 Maven 项目会多一个pom.xmljar 包就不放在lib里了。我一般先看三点一是src里有没有DBUtil.java或JdbcUtils.java这决定了数据库连接怎么写二是WEB-INF/web.xml或 Servlet 类上的WebServlet注解这决定了访问路径怎么映射三是database目录下的.sql脚本这决定了表结构和初始数据。把这三个文件读明白整个项目就能在脑子里跑通了。2.3 Servlet 映射与 web.xml注解配置还是 XML 配置很多源码的 Servlet 同时用了WebServlet注解和web.xml里的servlet-mapping运行时报java.lang.IllegalArgumentException: Servlet mapping specifies an unknown servlet name或Multiple Servlets map to same URI。这些都是配置冲突。Servlet 3.0 之后支持注解方式Tomcat 9 完全没问题课程设计中最省心的做法是保持注解把web.xml中旧映射注释掉或删除。但要注意如果你的项目里还有 Filter 或监听器它们依然需要在web.xml中声明或者用WebFilter/WebListener。一个干净的标准 web.xml 是?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 display-nameStudentManager/display-name welcome-file-list welcome-filelogin.jsp/welcome-file /welcome-file-list /web-app这里没有servlet映射但保留了首页欢迎文件和编码声明。为什么课程设计要刻意这样讲因为老师容易问“你的项目访问根路径后为什么打开的是 login.jsp”答案就在 welcome-file 列表。同时也告诉你Tomcat 启动后index.jsp不是首选文件除非你自己在 welcome-file 写上。注意不要同时保留旧 Servlet class 的 XML 又用注解那样 IDEA 会直接标红启动时也容易报映射冲突。2.4 数据库脚本和文档是你最值得先读的东西很多人的习惯是从index.jsp开始看但我会反过来先读.sql再读DBUtil.java然后读一个 Servlet。数据库脚本告诉你系统有几张表、字段是否规范、有没有初始账号。比如user表里通常会预置一行admin / admin123如果脚本里没写你登录时会卡在“用户名不存在”。文档则决定了你能否顺利交差——详细版设计说明书一般包含功能需求分析、ER 图、表结构、核心代码说明、测试结果这些内容不需要你全部重写但要能在答辩前对着源码逐段说出“为什么这么设计”。先读文档再改代码比直接一头扎进 JSP 里改改动动静要小得多。提示如果下载的源码没有数据库脚本只有.sql的压缩包先解压确认扩展名。很多“源码数据库”里的数据库其实就是一个导出文件不要把它当成 Java 代码放进项目里。3. 让源码跑起来IDEA 导入、Tomcat 配置与 MySQL 连接参数3.1 用 IDEA 导入项目的正确姿势别直接双击 .java 文件拿到源码后最常翻车的操作是直接双击.java文件用 IDEA 打开结果跑不了。正确做法是使用 IDEA 的“Project from Existing Sources”导入整个目录或者用Open选择项目根目录。对非 Maven 项目导入后还需要把WebContent/WEB-INF/lib下的 jar 包添加为依赖右键项目 - Open Module Settings - Libraries - 添加lib目录。这一步漏掉后面一定报ClassNotFoundException: com.mysql.jdbc.Driver。然后配置 Tomcat菜单栏 Run - Edit Configurations - 点- 选择 Tomcat Server - Local。如果列表里没有 Tomcat Server先到 Settings/Plugins 确认 Tomcat 插件没被禁用。配置界面里 Application server 指向你本地解压的 Tomcat 目录HTTP port 用 8080但要先确认本机 8080 没有被占用。最关键的是 Deployment 页签点- Artifact - 选xxx:war explodedApplication context 填/StudentManager或保持/。这个路径就是浏览器里访问的根路径很多人部署完还是 404就是这里没配或者没选 exploded 版本。启动时能看到 Tomcat 日志输出Artifact is deployed successfully才算真正部署成功。如果直接启动时报Error running Tomcat: Address localhost:8080 is already in use说明端口被占。解决方式两个一是找到占用进程关掉二是改端口。IDE 里 Tomcat 端口有三处HTTP port、JMX port、Tomcat 实际 server.xml 里的端口改配置时这三处别改乱否则 Tomcat 能起但浏览器访问不到。3.2 导入数据库脚本并修改 jdbc.properties 连接参数数据库准备是最没有技术含量、但最容易卡住人的一步。先在本地启动 MySQL 服务用命令行或 Navicat 创建数据库。命令行导入最稳mysql -u root -p database/student.sql如果没有把建库语句写在脚本里比如脚本一开始只有CREATE TABLE你就需要先手动建库再指定库导入mysql -u root -p -e CREATE DATABASE student_db CHARACTER SET utf8mb4; mysql -u root -p student_db database/student.sql导入后确认表都进来了mysql -u root -p student_db -e SHOW TABLES;。常见翻车点有两个一是.sql文件编码不是 UTF-8导入后中文乱码二是脚本里的库名和你项目里连接配置的库名不一致数据库导入了项目却连不上。后一种情况最坑因为报错不会告诉你是库名不匹配只会说Unknown database student_manage或Access denied。接下来改连接配置。非 Maven 项目一般在src/com/student/util/下有个.properties文件或者直接在DBUtil.java里写常量。常见写法是jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/student_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.passwordyour_password这里的参数每个都有讲究。useUnicodetruecharacterEncodingutf8解决中文乱码useSSLfalse是让本地开发别因为证书警告刷屏serverTimezoneAsia/Shanghai是 MySQL 8.0 必须加的不加会报时区异常。驱动类名注意如果你用的是 MySQL 8.0 的驱动包要写com.mysql.cj.jdbc.Driver老版本com.mysql.jdbc.Driver在 8.0 下会触发警告某些环境下还会直接报错。3.3 DBUtil 工具类最容易被答辩追问的类DBUtil.java是整个系统最核心的类之一也是老师最爱问的。它通常负责加载驱动、获取连接、关闭资源。一个规范的实现长这样package com.student.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class DBUtil { private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/student_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai; private static final String USERNAME root; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } public static void close(ResultSet rs, PreparedStatement ps, Connection conn) { try { if (rs ! null) rs.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (ps ! null) ps.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }这段代码里有三个答辩考点。第一个是Class.forName(DRIVER)它的作用是在静态代码块里加载驱动类到内存之后DriverManager才能识别这个数据库驱动。第二个是close方法重载注意关闭顺序是先ResultSet再PreparedStatement最后Connection反向关会报数据库连接被占用。第三个是为什么不把连接写死在每个 DAO 里因为数据库连接的创建和释放很贵统一封装后以后改成连接池或数据源只需要动这个类业务代码不用改。如果你想让系统看起来更完整可以在这个工具类里加一个打印日志的System.out.println但注意不要打印密码。4. 数据库设计与增删改查建表脚本、核心表结构与一整套操作链路4.1 三张核心表用户表、学生表、班级表学生信息管理系统的数据量不大但表结构要讲得出设计理由。最常见的三张表是用户表、班级表和学生表。班级表独立出来的好处是避免学生表里有大量重复的班级字符串也方便做班级维度的统计。用户表比较简单只存登录账号。下面是针对 MySQL 5.7 的建表脚本兼容性更好MySQL 8.0 下也适用CREATE DATABASE IF NOT EXISTS student_db DEFAULT CHARACTER SET utf8mb4; USE student_db; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, real_name VARCHAR(50), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE class_info ( id INT PRIMARY KEY AUTO_INCREMENT, class_name VARCHAR(50) NOT NULL UNIQUE, grade VARCHAR(20), major VARCHAR(50), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(50) NOT NULL, gender CHAR(2), birth_date DATE, phone VARCHAR(20), email VARCHAR(100), class_id INT, status TINYINT DEFAULT 1 COMMENT 1正常 0删除, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_student_class FOREIGN KEY (class_id) REFERENCES class_info(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;注意几个选型细节。第一user是 MySQL 的保留字所以建表时要加反引号否则直接执行会报语法错误。第二student_no一定要加唯一约束这是学号不能重复也方便后续按学号查询。第三status字段是逻辑删除标记课程设计阶段老师更认可这种方式——删学生时执行UPDATE student SET status0 WHERE id?而不是DELETE FROM student这样能保留历史数据也方便讲“为什么用逻辑删除”。外键fk_student_class可以加也可以不加加了更严谨但删除班级时会被约束挡住所以很多课程设计案例会故意不加外键靠代码层保证。如果要在答辩时讲数据库设计建议保留外键并说明你理解外键的作用。4.2 从 DAO 到 Servlet一条完整的增删改查链路系统最核心的代码就是一个“查询学生列表 新增/修改/删除”的闭环。先看 DAO它负责所有 JDBC 操作。下面是一段学生查询与分页的典型实现public ListStudent getStudentsByPage(int page, int pageSize, String keyword) { ListStudent list new ArrayList(); String sql SELECT s.*, c.class_name FROM student s LEFT JOIN class_info c ON s.class_id c.id WHERE s.status 1 ; if (keyword ! null !keyword.trim().isEmpty()) { sql AND (s.name LIKE ? OR s.student_no LIKE ?) ; } sql LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { int index 1; if (keyword ! null !keyword.trim().isEmpty()) { ps.setString(index, % keyword %); ps.setString(index, % keyword %); } ps.setInt(index, (page - 1) * pageSize); ps.setInt(index, pageSize); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { Student s new Student(); s.setId(rs.getInt(id)); s.setStudentNo(rs.getString(student_no)); s.setName(rs.getString(name)); s.setGender(rs.getString(gender)); s.setClassName(rs.getString(class_name)); list.add(s); } } } catch (SQLException e) { e.printStackTrace(); } return list; }这段代码里最值得学习的是使用PreparedStatement而不是Statement。好处有两个一是预编译防止 SQL 注入二是占位符传参比拼接字符串干净。注意这里的分页用了LIMIT ?, ?第一个参数是偏移量(page-1)*pageSize第二个是每页条数。如果你发现第一页和第二页数据重复多半是偏移量算错了。还有一个细节try (Connection conn ...)是 Java 7 的 try-with-resources 写法它会在 try 块结束后自动关闭资源配合DBUtil.close手动关闭并不冲突。如果你的 JDK 是 8这个写法没问题如果老师要求你解释AutoCloseable也能说上两句。接着是 Servlet 层。它负责接收请求参数、调用 DAO、把结果放进 request 作用域再转发给 JSP。一个管理学生信息入口的 Servlet 通常这样组织WebServlet(/student/*) public class StudentServlet extends HttpServlet { private StudentDao studentDao new StudentDao(); Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String path req.getPathInfo(); String action path null ? /list : path; switch (action) { case /list: listStudents(req, resp); break; case /add: showAddPage(req, resp); break; case /edit: showEditPage(req, resp); break; case /delete: deleteStudent(req, resp); break; default: resp.sendError(HttpServletResponse.SC_NOT_FOUND); } } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action req.getParameter(action); if (insert.equals(action)) { insertStudent(req, resp); } else if (update.equals(action)) { updateStudent(req, resp); } } private void listStudents(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int page 1; int pageSize 10; String pageStr req.getParameter(page); if (pageStr ! null !pageStr.isEmpty()) { page Integer.parseInt(pageStr); } String keyword req.getParameter(keyword); ListStudent list studentDao.getStudentsByPage(page, pageSize, keyword); req.setAttribute(students, list); req.getRequestDispatcher(/student/list.jsp).forward(req, resp); } }这里有三个需要讲清楚的机制。第一个是doGet/doPost的分工GET 用于查列表、打开新增和编辑页POST 用于提交新增和修改数据这样设计符合 HTTP 语义也能躲开“刷新页面重复提交”的部分问题。第二个是req.getRequestDispatcher(...).forward(req, resp)这是请求转发地址栏不变请求在整个 Servlet/JSP 之间共享所以 JSP 里拿得到req.setAttribute(students, list)。如果你用resp.sendRedirect(/student/list)地址栏会变但 request 里的属性就丢了必须重新查一遍。第三个是WebServlet(/student/*)配合req.getPathInfo()做资源式路由比在web.xml里配多个 Servlet 映射要简洁也好维护。这段代码几乎覆盖了答辩时“Servlet 生命周期”“请求转发和重定向的区别”“SQL 注入怎么防”三个高频问题。4.3 JSP 页面与表单提交把数据渲染出来并回显DAO 和 Servlet 只是后端页面才是老师第一眼看的。学生列表页一般用 JSP JSTL 渲染核心就是把 Servlet 放进去的students列表遍历出来% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % table thead trth学号/thth姓名/thth性别/thth班级/thth操作/th/tr /thead tbody c:forEach items${students} varstu tr td${stu.studentNo}/td td${stu.name}/td td${stu.gender}/td td${stu.className}/td td a href${pageContext.request.contextPath}/student/edit?id${stu.id}编辑/a a href${pageContext.request.contextPath}/student/delete?id${stu.id} onclickreturn confirm(确认删除该学生)删除/a /td /tr /c:forEach /tbody /table这里的重点不是标签语法而是${pageContext.request.contextPath}。它输出项目根路径比如/StudentManager。很多同学在 JSP 里写死href/student/edit一旦部署名不是根路径链接全部失效出现“页面能打开但点链接 404”的怪现象。这个细节是课程设计代码评审时最容易挑出来的硬伤。新增和编辑表单要共用同一套表单回显时用${param.id}或value${student.name}判断这是另外一种需求细节这里不展开。5. 避坑JavaWeb 大作业最常见的七个运行故障与排查方法5.1 环境与版本坑Tomcat、JDK 与驱动带来的经典报错第一个高频坑是 Tomcat 版本和驱动包不匹配。现象启动 Tomcat 时日志出现java.lang.ClassNotFoundException: javax.servlet.http.HttpServlet或者编译时能过、运行时不时抛 NoClassDefFoundError。原因是 Tomcat 10 及以上把包名从javax.servlet换成了jakarta.servlet你在web.xml和 Servlet 里写的import javax.servlet.*会找不到类。解决换 Tomcat 9.0 或把代码里的 javax 全部改成 jakarta。课程设计阶段我一般直接建议用 Tomcat 8.5/9.0稳定且和网上的教程一致。第二个坑是 MySQL 8.0 与旧驱动导致的Public Key Retrieval is not allowed。现象连接数据库时抛异常提示这个句子紧接着是Communications link failure。原因MySQL 8.0 默认用 caching_sha2_password 认证客户端需要向服务器获取公钥旧驱动或连接串没指定允许获取公钥时会拒绝。解决在 JDBC URL 里加allowPublicKeyRetrievaltrueuseSSLfalse或者把数据库用户的认证方式改成mysql_native_password。注意这个参数改的是连接串不是建表脚本。第三个坑是中文乱码。现象数据库里中文正常但页面显示???或者 JSP 页面的中文全乱。原因是字符集链路中某一段不是 UTF-8。解决要管三处项目文件编码统一 UTF-8MySQL 连接串带characterEncodingutf8JSP 页面开头设置pageEncodingUTF-8并用meta charsetUTF-8。另外写一个 EncodingFilter强制所有请求和响应都用 UTF-8WebFilter(/*) public class EncodingFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { req.setCharacterEncoding(UTF-8); resp.setCharacterEncoding(UTF-8); chain.doFilter(req, resp); } }这个 Filter 不是摆设它直接解决表单提交的中文乱码。没有过滤器的话request.getParameter(name)拿到的是乱码因为浏览器按 UTF-8 编码发送而默认解码是 ISO-8859-1。5.2 数据库连接坑库名不一致、连接被拒、驱动加载失败第四类坑集中在数据库连接部分特点是报错五花八门但根因往往只有一个。现象一启动后控制台报Unknown database student_db原因多半是脚本里建库名和你连接串里写的库名不一致。解决检查student.sql开头是CREATE DATABASE student_db还是CREATE DATABASE student_manager把.properties里的 URL 改成和脚本一致或者手动执行CREATE DATABASE IF NOT EXISTS xxx后再导入。现象二报Access denied for user rootlocalhost (using password: YES)这是密码错误或用户权限不足。很多课程的演示环境用的是root / 123456但你本机 MySQL 的 root 密码可能不是这个。解决先拿命令行手工验证一下账密能不能连上再改项目里的密码不要反复重启 Tomcat纯属浪费时间。另一种容易忽略的是你的 MySQL 端口不是 3306报的却是Communications link failure如果确认本机 MySQL 端口是 3307连接串里要写jdbc:mysql://localhost:3307/student_db。现象三启动没报但一查数据就ClassNotFoundException: com.mysql.jdbc.Driver这是 jar 包没放对位置。非 Maven 项目必须把连接驱动 jar 放在WebContent/WEB-INF/lib下而且 IDEA 里要右键 Add as LibraryMaven 项目则检查pom.xml里有没有 mysql 依赖别把两种方式混着配。5.3 代码与配置坑端口、部署路径、空指针与 404/500第五个高频坑是端口占用。现象IDEA 启动时提示Address already in use: JVM_Bind 8080或 Tomcat 服务能启动但浏览器访问 http://localhost:8080/ 一直转圈。解决Windows 下用netstat -ano | findstr 8080查出 PID然后在任务管理器结束进程也可以改 IDEA 中 Tomcat 的 HTTP port 为 8081。改端口后访问路径要同步改特别是 JSP 里如果写死了 8080 的绝对地址全都要换。第六个坑是点击链接 404。现象Tomcat 正常启动登录页能打开但点任何“编辑”或“删除”链接都 404。原因很可能是部署名和实际路径不一致或者 Servlet 用了注解但 URL 写错。排查方法看浏览器地址栏实际请求的是什么路径再对WebServlet(/student/edit)和你写的href${pageContext.request.contextPath}/student/edit?id18。注意WebServlet(/student/*)这种带通配符的映射比较霸道它会把所有/student开头的请求都交给同一个 Servlet再用getPathInfo区分如果同时又写了WebServlet(/student/edit)后者的优先级其实更高但容易造成混乱建议二选一。第七个坑是 500 常见于空指针。现象提交新增表单后直接 500控制台报NullPointerException定位到String gender request.getParameter(gender).trim();这类代码。原因很简单前端某个字段忘了写name属性或者select下拉框没有默认选中导致参数为null再调用.trim()就炸。解决先别急着改代码用浏览器开发者工具看 Network 里的 Form Data确认哪些参数是空的。代码层面统一对参数做容错String gender req.getParameter(gender); gender (gender null ? : gender.trim());。另外数据库字段DATE类型如果插入空字符串也会报DataTruncation要不要判空取决于你的业务。最后一个 404 在 IDEA 里很典型Artifact 没配置导致启动后 404。现象Tomcat 起来了日志也没有异常但访问主页面一直 404Tomcat 目录里也找不到你的项目。原因部署时选了war而不是war exploded或者 Deployment 里没添加 ArtifactTomcat 只是空转。解决在 Run Configuration 的 Deployment 页签里加 Artifact选war explodedApplication context 填/StudentManager然后重新启动。这一步是 IDEA 运行 JavaWeb 项目配置里最容易忽略的很多下载源码跑不起来的案例最后都卡在这。注意排查顺序永远是“看日志”而不是“猜原因”。Tomcat 的控制台日志、IDEA 的 Output 面板、以及浏览器 F12 的 Network 和 Console是三个最直接的证据源。把报错消息原样复制到搜索引擎通常比对着代码发呆有效得多。6. 从“跑通”到“答辩”给系统加三个亮点并把设计意图讲清楚6.1 三个低成本亮点验证码、批量删除和分页跳转当基本功能都能跑起来下一步是让课程设计有“加分项”。我见过很多同学交上去的文档里全是默认代码截图答辩时老师一问就冷场。三个低成本高回报的改动登录验证码、批量删除、分页跳转。验证码不需要自己画图片用 JSP 生成简单数字即可批量删除用checkbox加一个String[] ids request.getParameterValues(ids)就能搞定能在答辩时展示“数组参数”的处理。分页跳转则是把 4.2 里的 DAO 方法接上页码按钮代码量不大讲起来可以聊“LIMIT 的性能边界”。文档和演示是两个战场。文档里不要贴大段代码而是画请求流程图浏览器 - Servlet - DAO - MySQL再原路返回。这个图画清楚胜过十页代码。答辩演示时按“登录 - 新增 - 查询 - 修改 - 删除”的顺序走一遍每一步主动指给老师看“这里走的是 doPost通过 PreparedStatement 写库”。我当年吃过一个亏代码里用的是Statement拼接 SQL老师看了一眼就追问 SQL 注入怎么防。后来我把所有 DAO 都改成PreparedStatement再被问到才缓和。做课程设计最忌“只会跑不会讲”源码不是你写的没问题但你能讲清楚每一处为什么这么写这关才算过。验证方法也很简单列一张测试功能清单逐项打勾。比如“用错误密码登录能否提示”“新增时学号重复数据库是否会报唯一约束”“删除学生后刷新列表是否少了一行”。这些验证记录放进文档老师会觉得你做过测试。最后说一句我的习惯在DBUtil里多打一行System.out.println(连接成功)启动后看到它整个项目才算真的活着。希望帮到你。本文还有配套的精品资源点击获取
返回列表