ARTICLE DETAIL

资讯详情

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

Java学生信息管理系统实战:JSP+Servlet+MySQL课设完整指南

Java学生信息管理系统实战:JSP+Servlet+MySQL课设完整指南 简介面向计算机专业在校生与Java初学者的学生信息管理系统课程设计资源适配期末大作业、课程设计、项目实战等场景。项目经导师指导并获评审99分代码完整可运行涵盖Java源码、SQL数据库脚本、实验报告与操作演示从环境搭建到功能实现均有说明基础薄弱也能完成部署。资源包共117个文件约30.81MB以png界面截图、class编译文件、java源码、sql脚本、jar依赖包、pdf/docx文档为主并含项目配置文件与mp4演示视频目录按模块组织便于查阅。已有129人学习下载。读者可获得可直接运行的项目源码、配套数据库与完整文档既能用于答辩展示也可借助文档快速梳理设计思路通过源码理解登录权限、学生信息增删改查、管理员管理等典型业务实现方式是课程设计与项目实战的高分参考。1. 课设榜单上的常青树Java 学生信息管理系统要交付什么计算机专业大二大三的课设选题Java 学生信息管理系统几乎是默认项。这个题目看着像增删改查实际考核的是 Java 基础、JDBC、数据库设计和 Web 开发这四件事的串联能力交付物只有三样一套能跑的代码、一份能还原环境的数据库脚本、一篇能讲清设计过程的实验报告。这套系统的翻车点从来不在增删改查本身而在环境变量、驱动类名、编码一致性这些黑盒细节上。我会用 JDK 8 Tomcat 8.5 MySQL 8.0 这套最经得起老师追问的组合来讲适合正在赶课设、或者想拿这个项目练手的人照着复现。2. 先定技术栈为什么课设场景下 JSPServletMySQL 比 Spring Boot 更不容易翻车2.1 版本组合JDK 8、Tomcat 8.5、MySQL 8.0 的对应关系学生信息管理系统这类课程设计项目选择技术栈的第一原则不是新而是“老师能看懂、环境能复现”。Spring Boot 确实写起来快但它在内部把视图解析、连接池、事务管理全部自动化了答辩时老师顺着 Controller 一问到底层答不上来的场面在每年课设答辩里反复上演。JSP Servlet JDBC 这套组合虽然繁琐但每一行代码都落在课程大纲的考点上反而更容易讲清楚。我推荐的具体组合是 JDK 8、Tomcat 8.5、MySQL 8.0、Servlet 3.1 规范。JDK 8 是兼容性最稳的版本Tomcat 8.5 自带 Servlet 3.1 支持能直接用WebServlet注解而不必写 web.xmlMySQL 8.0 是当前主流教学版本。如果你所在学校的实验环境还在用 MySQL 5.7代码几乎不用改只需要把驱动类名和 URL 参数按 5.7 的方式调整这一点在第 5 章详细说。组件推荐版本对应关键配置JDK1.8环境变量 JAVA_HOME 指向 JDK 安装目录Tomcat8.5 或 9.0内置 Servlet 3.1 / 4.0支持注解MySQL8.0 或 5.7驱动类名不同URL 参数不同连接驱动mysql-connector-java 8.0.x必须放进 WEB-INF/lib 下才算部署2.2 工程结构按 controller/service/dao 分层连包名都定好学生信息管理系统的代码量不大但如果不提前把包结构定好写到一半就会出现“类不知道放哪、互相 import 一团乱”的局面。一个经得起检查的动态 Web 工程应该长这样src/main/java ├── model/ // 实体类对应数据库表 │ ├── Student.java │ ├── Course.java │ └── Score.java ├── dao/ // 数据库访问层只写 JDBC │ ├── StudentDao.java │ └── UserDao.java ├── servlet/ // 控制器层接收请求、调 DAO、做跳转 │ ├── LoginServlet.java │ ├── StudentListServlet.java │ └── StudentSaveServlet.java └── util/ └── DBUtil.java // JDBC 连接工具类 src/main/webapp ├── login.jsp ├── studentList.jsp └── WEB-INF/ └── lib/ └── mysql-connector-java-8.0.x.jar包名的约定是三层模型层只放数据载体DAO 层只写 SQLServlet 层负责参数解析和页面跳转。这层划分本身就是实验报告里“系统总体设计”章节的素材答辩时老师问“你这个系统怎么分层的”直接照这个结构回答就行。有一个容易忽略的点WEB-INF/lib下的 jar 包是运行期才加载的。在 IDEA 里即使你在项目的 Libraries 里引了驱动如果没让它部署到WEB-INF/lib本地编译不报错一启动 Tomcat 就抛ClassNotFoundException。这是课设里出现频率最高的环境坑后面第 5 章专门写。2.3 动手前 10 分钟环境变量、端口、JDBC 驱动的检查命令写代码前先花十分钟把环境确认一遍能省掉后面一小时的排障。常见做法是按下面这个顺序跑一轮命令java -version echo $JAVA_HOME netstat -ano | findstr :8080 mysql -uroot -pjava -version确认 JDK 版本是 1.8 而不是 17很多课设代码在 JDK 9 以上会因为模块化限制报奇怪的类加载错误。echo $JAVA_HOME在 Windows 下是echo %JAVA_HOME%确认环境变量没有被 PATH 里的其他 JDK 干扰。netstat那条命令用来查 8080 端口是否被占用Tomcat 启动失败一半以上是这个原因。最后一条是确认 MySQL 服务能连上密码如果忘记后续所有连接代码都白搭。环境检查完之后再测驱动。在项目里新建一个最简单的类只调用一次Class.forName(com.mysql.cj.jdbc.Driver)并打印成功信息。如果这一步都过不了不要往下写业务代码先解决依赖问题。我的血泪经验是环境没验证就写业务最后大概率是环境问题混在业务问题里一起查翻车效率极高。3. 数据库设计四张表怎么建字段和外键怎么定才扛得住答辩3.1 从需求到表登录、学生、课程、成绩四块功能怎么映射成表学生信息管理系统不是上来就建表而是先列功能。一个最小可用系统通常包含管理员登录、学生信息的增删改查、课程信息维护、按学生记录成绩。把这个功能列表翻译成表就是四张核心表。用户表负责登录认证字段只需要用户名、密码和显示名。学生表是系统的中心学号是自然主键姓名、性别、年龄、班级、电话是基本属性。课程表存课程号和课程名。成绩表把学生和课程关联起来除了成绩值之外还需要用外键引用学生表和课程表。这里有个设计决策成绩表不直接用学号当主键而是加一个自增 id 做代理主键学号和课程号组合做唯一索引这样扩展成绩记录时更灵活。四张表的关系一句话就能讲清一个学生可以选多门课一门课可以被多个学生选成绩表就是这个多对多关系的中间表。这是实验报告“数据库设计”章节里 ER 图的核心也是答辩时最常被追问的部分。3.2 建表 SQL库、表、约束、初始数据一份跑通下面这份 SQL 是完整可执行的。库名、表名、字段名都按课设最常见的命名习惯来字符集统一用 utf8mb4避免中文乱码问题CREATE DATABASE IF NOT EXISTS student_ms DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE student_ms; CREATE TABLE t_user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(30) NOT NULL UNIQUE, password VARCHAR(32) NOT NULL, real_name VARCHAR(30) NOT NULL COMMENT 页面显示名 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_student ( student_no VARCHAR(20) PRIMARY KEY COMMENT 学号字符串类型, student_name VARCHAR(30) NOT NULL, gender CHAR(1) DEFAULT 男, age INT DEFAULT 18, class_name VARCHAR(30), phone VARCHAR(11), create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_course ( course_no VARCHAR(20) PRIMARY KEY, course_name VARCHAR(50) NOT NULL, credit DECIMAL(3,1) DEFAULT 2.0, teacher VARCHAR(30) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_score ( id INT AUTO_INCREMENT PRIMARY KEY, student_no VARCHAR(20) NOT NULL, course_no VARCHAR(20) NOT NULL, score DECIMAL(5,2) NOT NULL, exam_time DATETIME, UNIQUE KEY uq_student_course(student_no, course_no), CONSTRAINT fk_score_student FOREIGN KEY (student_no) REFERENCES t_student(student_no), CONSTRAINT fk_score_course FOREIGN KEY (course_no) REFERENCES t_course(course_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO t_user(username, password, real_name) VALUES(admin, 123456, 系统管理员); INSERT INTO t_student(student_no, student_name, gender, age, class_name, phone) VALUES(2023001, 张伟, 男, 20, 计科2301, 13800000001); INSERT INTO t_student(student_no, student_name, gender, age, class_name, phone) VALUES(2023002, 李娜, 女, 19, 计科2301, 13800000002); INSERT INTO t_course(course_no, course_name, credit, teacher) VALUES(C001, Java程序设计, 2.5, 王老师); INSERT INTO t_course(course_no, course_name, credit, teacher) VALUES(C002, 数据库原理, 3.0, 李老师); INSERT INTO t_score(student_no, course_no, score, exam_time) VALUES(2023001, C001, 88.5, NOW());ENGINEInnoDB必须写因为成绩表的外键约束只有 InnoDB 支持MyISAM 建上外键也不会真正生效。UNIQUE KEY uq_student_course这个唯一索引保证同一门课对一个学生只能录入一次成绩避免重复数据。外键的ON DELETE行为默认是RESTRICT意味着如果课程表里有成绩引用直接删课程会报错这在实际使用中是对的能防止误删。初始数据里把第一个学生、第一门课、第一条成绩都准备好了代码写完直接能看到效果。如果你想用自己的姓名和学号改 INSERT 里的值就行但保持字段结构不要变。3.3 三个容易被问住的字段细节学号类型、唯一索引、默认时间课设答辩时老师不会问“你建了几张表”而是会挑字段设计问为什么。第一个经典问题是学号为什么用 VARCHAR 而不是 INT。学号不做算术运算可能含字母或前导零比如“2023_001”而且未来接入其他系统时字符串兼容性更好。用 INT 一旦遇到带字母的学号就当场翻车。第二个是成绩表那个唯一索引。没有它用户在前端重复点击“保存成绩”按钮时数据库会插入两条一模一样的选课记录。有了uq_student_course第二次插入会直接报Duplicate entry错误后端可以捕获这个异常给出友好提示。这个设计本身就是实验报告里“数据完整性”部分的一个亮点。第三个是create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP。学生表里加一个创建时间字段插入时不需要写代码数据库自动填当前时间。别小看这个字段它能让列表页展示加入学时间的排序依据也能在报告里写“系统记录每条数据的入库时间”。这三个细节都体现了你不是在盲目建表而是在按业务规则约束数据。4. 核心代码落地从 JDBC 工具类到增删改查的一条完整链路4.1 DBUtil 工具类把驱动加载和连接释放封装成 20 行JDBC 代码最烦人的两件事是重复写Class.forName和重复写finally释放资源。一个工具类把它们收拢起来DAO 层的代码会干净很多。这是最标准的写法package 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 URL jdbc:mysql://localhost:3306/student_ms ?useUnicodetruecharacterEncodingUTF-8 serverTimezoneAsia/ShanghaiuseSSLfalse allowPublicKeyRetrievaltrue; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(MySQL 驱动类未找到请检查 jar 包位置); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, PreparedStatement ps, ResultSet rs) { if (rs ! null) { try { rs.close(); } catch (SQLException e) {} } if (ps ! null) { try { ps.close(); } catch (SQLException e) {} } if (conn ! null) { try { conn.close(); } catch (SQLException e) {} } } }静态块里的Class.forName在类加载时执行一次完成驱动注册。URL 里的useUnicodetruecharacterEncodingUTF-8是中文不乱码的前提serverTimezoneAsia/Shanghai是 MySQL 8.0 连接时必带的时区参数不写会直接抛时区异常。allowPublicKeyRetrievaltrue是配合 MySQL 8.0 默认认证插件用的很多教材没写这一项导致连接时报Public Key Retrieval is not allowed。注意close方法里每个资源单独 try-catch这是为了防止第一个资源关闭异常把后面的资源释放逻辑截断。连接关闭的顺序和打开顺序相反先关 ResultSet再关 PreparedStatement最后关 Connection。4.2 登录逻辑用 WebServlet 接收请求、比对数据库、跳转页面登录是系统第一个入口代码的教学价值在于doPost里参数的解析、错误信息的回传、会话的建立和页面的跳转。用注解方式注册 Servlet省去 web.xml 的配置步骤package servlet; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import util.DBUtil; WebServlet(/login) public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String username req.getParameter(username); String password req.getParameter(password); if (username null || password null || username.trim().isEmpty()) { req.setAttribute(error, 用户名和密码不能为空); req.getRequestDispatcher(login.jsp).forward(req, resp); return; } String sql SELECT real_name FROM t_user WHERE username? AND password?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next()) { HttpSession session req.getSession(); session.setAttribute(loginUser, rs.getString(real_name)); resp.sendRedirect(studentList); } else { req.setAttribute(error, 用户名或密码错误); req.getRequestDispatcher(login.jsp).forward(req, resp); } rs.close(); } catch (Exception e) { e.printStackTrace(); req.setAttribute(error, 系统异常 e.getMessage()); req.getRequestDispatcher(login.jsp).forward(req, resp); } } }SQL 用WHERE username? AND password?的占位符形式这是防止 SQL 注入的最低要求也是课设代码的加分项。登录成功用sendRedirect而不是forward因为重定向会让浏览器发起一次全新的请求刷新页面时不会重复提交表单。登录失败用forward把 error 属性带回登录页JSP 里用${error}直接显示。try-with-resources会让 Connection 和 PreparedStatement 自动关闭所以这里没调 DBUtil.close。但如果用了 try-with-resourcesResultSet 也需要在 try 块内部手动 close所以示例里保留了rs.close()。4.3 学生增删改查PreparedStatement 占位符和分页 LIMIT 的配合学生信息管理系统的核心是增删改查也就是数据库课程里反复强调的 CRUD。以一个带分页的列表查询和一个新增为例展示数据访问层的标准写法package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import model.Student; import util.DBUtil; public class StudentDao { public ListStudent list(int page, int pageSize) throws Exception { String sql SELECT student_no, student_name, gender, age, class_name, phone FROM t_student ORDER BY student_no LIMIT ?, ?; ListStudent students new ArrayList(); Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ps.setInt(1, (page - 1) * pageSize); ps.setInt(2, pageSize); ResultSet rs ps.executeQuery(); while (rs.next()) { Student s new Student(); s.setStudentNo(rs.getString(student_no)); s.setStudentName(rs.getString(student_name)); s.setGender(rs.getString(gender)); s.setAge(rs.getInt(age)); s.setClassName(rs.getString(class_name)); s.setPhone(rs.getString(phone)); students.add(s); } DBUtil.close(conn, ps, rs); return students; } public boolean insert(Student s) throws Exception { String sql INSERT INTO t_student(student_no, student_name, gender, age, class_name, phone) VALUES(?, ?, ?, ?, ?, ?); Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, s.getStudentNo()); ps.setString(2, s.getStudentName()); ps.setString(3, s.getGender()); ps.setInt(4, s.getAge()); ps.setString(5, s.getClassName()); ps.setString(6, s.getPhone()); int rows ps.executeUpdate(); DBUtil.close(conn, ps, null); return rows 1; } }LIMIT ?, ?是 MySQL 分页的标准写法第一个参数是偏移量(page - 1) * pageSize第二个参数是每页条数。这里必须用ps.setInt动态赋值不能把页码直接拼进 SQL 字符串这也是 SQL 注入的典型入口。Student 是一个简单的 POJO六个字段对应 t_student 的六个列IDE 自动生成 getter/setter 即可。executeUpdate返回受影响的行数新增成功返回 1失败返回 0。这个返回值就是页面提示“保存成功”还是“保存失败”的依据。更新和删除的思路完全一样把 SQL 换成UPDATE ... WHERE student_no?和DELETE FROM t_student WHERE student_no?占位符传参方式不变。4.4 列表页 JSPJSTL 标签渲染数据表格分页链接怎么传参JSP 页面里最忌讳的事情是写一堆% %scriptlet 嵌 Java 代码既难读又容易交叉污染。用 EL 表达式和 JSTL 标签替代页面结构清晰也更接近真实项目的写法。列表页的核心片段% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % table border1 tr th学号/thth姓名/thth性别/thth年龄/thth班级/thth电话/th /tr c:forEach items${students} vars tr td${s.studentNo}/td td${s.studentName}/td td${s.gender}/td td${s.age}/td td${s.className}/td td${s.phone}/td /tr /c:forEach /table a hrefstudentList?page${page - 1}pageSize${pageSize}上一页/a a hrefstudentList?page${page 1}pageSize${pageSize}下一页/a% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %这一行必须放在页面最上方否则c:forEach不可用。${s.studentNo}是 EL 表达式它等同于调用s.getStudentNo()。分页链接里把page和pageSize两个参数向后传Servlet 里通过request.getParameter(page)接收做一个null判断后赋默认值 1。JSTL 需要额外引入两个 jar 包jstl-1.2.jar和standard.jar同样放在WEB-INF/lib下。忘记引包的话页面会直接报 500提示找不到标签库描述文件这个问题在课设里出现频率比想象中高。5. 常见问题排查从启动失败到中文乱码的五条踩坑记录5.1 ClassNotFoundException运行时找不到 MySQL 驱动先检查 WEB-INF/lib现象IDEA 里代码能正常编译一启动 Tomcat 就抛java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver登录页完全打不开。原因编译期找得到 jar 包运行期找不到。Tomcat 运行时只认WEB-INF/lib目录下的驱动IDEA 项目结构里的 Libraries 依赖不会自动部署到 lib 目录。这个脱节是课设里最常见的环境黑匣子。解决把 mysql-connector-java 的 jar 文件复制到src/main/webapp/WEB-INF/lib/下。如果你用了 Maven确认 pom.xml 里 scope 不是providedprovided 会导致 Tomcat 运行时不打包该依赖。然后在 IDEA 的 Artifacts 页面点 “Fix” 把依赖加进打包范围。5.2 中文乱码URL、请求、页面三处编码必须一致现象数据库里数据是正常中文页面上显示???。另一种反向现象是通过页面新增学生数据库里存进去的中文全部乱码。原因乱码的本质是写入和读取用的字符集不一致。常见的漏网之鱼有三个JDBC URL 没写characterEncodingUTF-8Servlet 里没有调用request.setCharacterEncoding(UTF-8)JSP 页面contentType和pageEncoding不一致。解决三处编码全部统一成 UTF-8。DBUtil 的 URL 加useUnicodetruecharacterEncodingUTF-8每个doPost方法第一行写req.setCharacterEncoding(UTF-8)JSP 头部用contentTypetext/html; charsetUTF-8 pageEncodingUTF-8。漏掉任意一处乱码都会在某个环节冒出来。检查顺序是先查数据库存储是否正常再查页面显示逐层定位断点。5.3 Communications link failureMySQL 8.0 的驱动类名和时区参数现象启动项目后点登录控制台报com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value йʱ is unrecognized或者报Communications link failure. The last packet successfully received from the server was 0 milliseconds ago。原因MySQL 8.0 的 JDBC 驱动类名改成了com.mysql.cj.jdbc.Driver如果你还在用 5.x 时代的com.mysql.jdbc.Driver驱动加载就会异常。其次MySQL 8.0 的服务器时区默认值不认识中国时区URL 里必须显式指定。解决驱动类名换成com.mysql.cj.jdbc.DriverURL 追加serverTimezoneAsia/Shanghai。如果连接还报Public Key Retrieval is not allowed在 URL 末尾加allowPublicKeyRetrievaltrue这是因为 MySQL 8.0 默认用了caching_sha2_password认证插件允许客户端在非 SSL 连接下请求公钥是绕过该限制的标准做法。5.4 Address already in use8080 端口被占用时的两条出路现象启动 Tomcat 时控制台立即报Address already in use: JVM_Bind伴随大面积红色异常堆栈。原因8080 端口被其他进程占用了最常见的是上一个 Tomcat 实例没被杀干净或者本机有别的服务占用了同一个端口。这不是代码问题但每年课设都有同学因为改了端口导致页面访问路径不对越修越乱。解决先看谁占了端口。Windows 下执行netstat -ano | findstr 8080查到 PID再用taskkill /F /PID PID强杀。如果你想换个端口改conf/server.xml里Connector port8080这一行的端口同时也要改项目访问路径里的端口。换端口之后JSP 页面里所有硬编码了http://localhost:8080的跳转都要同步改这也是我不建议换端口的原因。5.5 Duplicate entry重复插入学生时数据库报主键冲突现象前端新增一个学号已存在的学生页面直接白屏控制台抛java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 2023001 for key PRIMARY。原因t_student表以student_no为主键数据库层做了唯一性校验重复插入会被拒绝。页面端没有提前校验后端也没有捕获这个异常错误直接抛到了 Tomcat。解决前端在提交按钮的 onclick 里先禁用按钮减少双击误触。真正的兜底在后端DAO 层捕获SQLIntegrityConstraintViolationException把它转成“学号已存在”的提示信息返回登录页或列表页。我一般这样做在 Servlet 里 catch 这个异常子类其余异常按系统异常统一处理保证用户看到的是友好提示而不是白屏。6. 实验报告怎么组织从代码和数据库里提取课设文档素材6.1 报告结构五章正文分别从项目的哪个部分取材实验报告不是项目代码的复述而是把摊开在三层结构里的设计思路重新归纳成文档。五章正文的素材来源其实都在前面的代码和 SQL 里对应关系很直接。报告章节写什么素材从哪里来需求分析系统的参与者、功能清单、数据流描述登录、学生 CRUD、选课、成绩录入四个功能点总体设计功能模块划分、技术架构选型理由第 2 章的 MVC 分层结构和包设计数据库设计ER 图、表结构、字段说明、约束设计第 3 章的四张建表 SQL 和三个细节功能实现登录流程、CRUD 代码、关键页面截图第 4 章的 Servlet 和 DAO 代码测试与总结测试用例、运行效果、存在的问题登录功能、录入重复学号等边界场景6.2 两个答辩加分扩展连接池和密码加密如果你想让这份作业在答辩时更有底气的两个改动成本很小的扩展值得做。第一个是把 JDBC 直连改成 HikariCP 连接池代码改动量极小pom 里加两个依赖配置文件写好连接池参数DBUtil 里把DriverManager.getConnection换成数据源取连接。这个改动能在答辩时直接回答“连接池是什么、为什么用”也能引出数据库连接被反复创建销毁是性能瓶颈这个考点。第二个是密码加密。目前的t_user表密码是明文存答辩时有老师会直接指出这是安全隐患。改动方案是注册时用 MD5 哈希后入库登录时把用户输入用同样算法哈希后对比。用MessageDigest写一个十几行的工具方法就行不需要引入额外依赖。这两个扩展都属于“小而可见”的改进不破坏现有代码结构但会让答辩从“完成了功能”提升到“考虑了安全与性能”。我带课设这几年最深的感受是代码能跑只说明逻辑对环境能复现、原理能讲清才算真正的交付。所以我自己的习惯是先把数据库脚本跑通再写 DAO最后才碰 Servlet 和页面——数据库通了后面的代码只是体力活。希望帮到你。本文还有配套的精品资源点击获取
返回列表