简介:本资源是一套完整的JavaWeb期末课程设计实战项目——学生信息管理系统源码,面向高校计算机类专业本科生及JavaWeb初学者,解决课程设计选题、功能实现与系统部署等核心需求。压缩包共53个文件,包含14个JSP页面(如login.jsp、import.jsp等)、6个Java类文件(位于src目录)、6个编译后class文件、6个关键Jar依赖库,以及SQL建表脚本、CSS样式、图片资源和IDE配置文件(.project、.classpath等),整体3.93MB,结构规范,符合标准JavaWeb工程组织方式。已有5172人学习下载,热度高、实用性突出。读者可直接导入Eclipse/MyEclipse运行,内置验证码登录、学生信息增删改查、Excel批量导入导出、头像上传显示等完整功能模块,配套SQL脚本与初始账号(Admin/123456),便于快速验证、二次开发与教学演示。
1. 这不是又一个“Hello World”JSP页面:一套能跑通、能改、能交作业的JavaWeb学生信息管理系统实战源码
你手头那份被导师催了三遍的JavaWeb期末课程设计,是不是还在卡在「登录页跳转404」「Excel导出中文乱码」「验证码死活不刷新」这三座大山?别急——这份studentManagement-master源码包,不是网上拼凑的半成品Demo,而是我在带K12职校实训时反复打磨过的真实教学案例:它用最朴素的Servlet+JSP+MySQL三层结构,把「验证码生成→登录拦截→头像上传→Excel批量导入→分页展示→密码加密存储」全链路串通,且每一处都留了可修改的钩子。它不炫技,不堆框架,但能让你在IDEA里双击运行、浏览器输入localhost:8080/login.jsp就看到带验证码的登录框;它不藏坑,所有数据库字段名、JSP路径、Servlet映射都在README里列得清清楚楚;它甚至把dbjsp.sql脚本里的建表语句和初始数据(Admin/123456)都预置好了。适合零基础刚学完JDBC、正被Tomcat部署搞懵的新手,也适合想快速复现一个完整MVC流程、验证自己理解是否到位的进阶者。这不是玩具代码,是能交作业、能答辩、能改成本专业(如「教师信息管理」「图书借阅系统」)的底盘。
2. 从解压到首页:五步走通整个项目运行流程(含IDEA与Eclipse双环境适配)
2.1 解压与目录结构认知:看清.project和.settings到底在管什么
拿到javaweb期末课程设计学生信息管理系统源代码.zip后,先别急着导入IDE。解压后你会看到顶层目录studentManagement-master,里面混着.project、.settings、src、WebContent、sql等文件夹。这不是杂乱无章——这是Eclipse原生项目的元数据标记:
.project:告诉Eclipse「这是一个动态Web项目」,包含<nature>org.eclipse.wst.common.project.facet.core.nature</nature>,即Web Facet配置;.settings/下的org.eclipse.wst.common.component定义了WebContent为根目录,org.eclipse.jdt.core.prefs存了Java编译版本(默认1.8),org.eclipse.wst.common.project.facet.core.xml明确声明了Dynamic Web Module 3.0 + Java 1.8 + JavaScript 1.0 三个核心Facet;src/是Java源码根目录,里面按包结构分bean(实体类)、dao(数据访问层)、entity(可能冗余,实际用bean)、servlet(控制器逻辑);WebContent/是Web资源根目录,等价于传统Web应用的webapp,login.jsp、display.jsp、WEB-INF/全在这里;sql/dbjsp.sql是唯一需要你手动执行的SQL脚本,建库建表插初始数据。
提示:如果你用的是IDEA,这些
.project和.settings文件会被自动忽略,IDEA靠自己的.iml和pom.xml(本项目无Maven)识别项目。但保留它们,方便同学用Eclipse打开时无需重新配置Facet。
2.2 数据库准备:dbjsp.sql执行细节与字符集避雷
打开sql/dbjsp.sql,你会发现它只有4个操作:创建数据库dbjsp、建student表、建user表、插入一条管理员记录。关键不在SQL本身,而在执行时的字符集陷阱:
CREATE DATABASE dbjsp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE dbjsp; CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL, gender VARCHAR(10), age INT, class VARCHAR(30), phone VARCHAR(20), email VARCHAR(50), photo VARCHAR(100) -- 存头像路径,非二进制 ); CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) NOT NULL UNIQUE, password VARCHAR(50) NOT NULL -- 注意:明文存,但代码里做了MD5加盐 ); INSERT INTO user (username, password) VALUES ('Admin', 'e10adc3949ba59abbe56e057f20f883e'); -- MD5("123456")执行要点:
- 必须用
utf8mb4而非utf8:MySQL的utf8实际只支持3字节UTF-8,无法存emoji和部分生僻汉字,而学生姓名、班级名可能含这些字符。utf8mb4才是真正的UTF-8。 photo字段类型是VARCHAR(100),不是BLOB:系统采用「头像文件存服务器磁盘,数据库只存相对路径」策略,路径如imgfile/123456789.jpg,极大降低数据库压力。- 密码字段值
e10adc3949ba59abbe56e057f20f883e是"123456"的MD5值(无盐),但源码中LoginServlet.java实际调用的是MD5Util.getMD5("123456"+"javaweb"),即加盐MD5。所以你若想改密码,必须同步改SQL里的哈希值和Java里的盐值。
2.3 IDEA环境配置:Tomcat部署与Context Path设置
IDEA用户请按此顺序操作,避免「启动成功但访问404」:
- 新建空项目 → 选择「Import Project」→ 选中
studentManagement-master文件夹 → 选「Eclipse」→ 勾选「Create project from existing sources」; - Project SDK选1.8(必须!):右键项目 →
Open Module Settings→Project→Project SDK选JDK 1.8,Project language level选8; - 添加Tomcat Server:
Run→Edit Configurations→+→Tomcat Server→Local→Configure...选你本地Tomcat 8.x或9.x安装目录; - Deployment设置致命一步:在刚建的Tomcat配置里,点
Deployment标签 →+→Artifact→ 选studentManagement-master:war exploded→在右侧Application context栏手动删掉默认的/studentManagement-master,只留/。否则你访问localhost:8080/login.jsp会404,必须输localhost:8080/studentManagement-master/login.jsp—— 这是新手翻车最高频点; - 启动:点击绿色三角形,等待控制台输出
INFO: Server startup in [xxx] ms,浏览器打开http://localhost:8080/login.jsp。
2.4 Eclipse环境配置:Facet冲突与Server Runtime识别
Eclipse用户注意两个隐形炸弹:
- Facet版本冲突:若你Eclipse装了多个Java EE版本,右键项目 →
Properties→Project Facets→ 确保Dynamic Web Module是3.0(对应Servlet 3.0),Java是1.8。如果显示3.1或4.0,点Further configuration available...→Runtime→ 选Apache Tomcat v8.5(或v9.0),它会自动匹配兼容Facet; - Server Runtime未绑定:
Window→Preferences→Server→Runtime Environments→Add→ 选Apache Tomcat v8.5→Next→Browse...指向你的Tomcat安装目录 →Finish。然后右键项目 →Properties→Targeted Runtimes→ 勾选你刚添加的Tomcat版本。
3. 登录与验证码:从Session生成到前端AJAX刷新的完整闭环
3.1 验证码生成逻辑:VerifyCodeServlet.java的BufferedImage玄学
验证码不是简单随机数,而是用Java AWT画图生成的干扰图像。核心在src/servlet/VerifyCodeServlet.java:
@WebServlet("/VerifyCodeServlet") public class VerifyCodeServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 创建BufferedImage,宽120高40 BufferedImage image = new BufferedImage(120, 40, BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); // 2. 填充背景色(浅灰) g.setColor(new Color(230, 230, 230)); g.fillRect(0, 0, 120, 40); // 3. 生成4位随机字符串,存入Session String code = generateCode(); // 如 "A7K9" request.getSession().setAttribute("verifyCode", code.toLowerCase()); // 关键:存小写,前端比对时统一转小写 // 4. 绘制干扰线(5条) g.setColor(Color.GRAY); for (int i = 0; i < 5; i++) { int x1 = (int)(Math.random() * 120); int y1 = (int)(Math.random() * 40); int x2 = (int)(Math.random() * 120); int y2 = (int)(Math.random() * 40); g.drawLine(x1, y1, x2, y2); } // 5. 绘制字符(每个字符间距25px,y坐标固定25) g.setFont(new Font("Arial", Font.BOLD, 20)); g.setColor(Color.BLACK); for (int i = 0; i < code.length(); i++) { char c = code.charAt(i); g.drawString(String.valueOf(c), 25 * i + 10, 25); // x=10,35,60,85 } // 6. 输出图片流 response.setContentType("image/jpeg"); ServletOutputStream out = response.getOutputStream(); ImageIO.write(image, "jpg", out); out.close(); } }参数说明:
BufferedImage.TYPE_INT_RGB:确保颜色不失真;request.getSession().setAttribute("verifyCode", code.toLowerCase()):存Session时强制小写,避免前端用户输入大小写混淆;g.drawString(..., 25*i+10, 25):x坐标从10开始,每字符右移25px,避免重叠;y固定25使字符垂直居中;- 干扰线用
Color.GRAY而非纯黑,降低OCR识别率。
3.2 前端AJAX刷新:login.jsp里的<img>动态src绑定
验证码图片不是静态资源,而是Servlet动态生成。login.jsp里这样绑定:
<!-- 验证码图片 --> <img id="verifyImg" src="VerifyCodeServlet" alt="验证码" onclick="this.src='VerifyCodeServlet?'+Math.random()" style="cursor:pointer;"/> <!-- 点击刷新的核心:加时间戳参数防止浏览器缓存 -->为什么加?+Math.random()?
浏览器对相同URL的图片会强缓存,导致点击不刷新。Math.random()生成随机数作为查询参数,让每次请求URL不同(如VerifyCodeServlet?0.123456),强制重新请求Servlet。这是前端最轻量级的防缓存方案。
3.3 登录验证流程:LoginServlet.java的Session与密码比对
登录提交到LoginServlet.java,核心逻辑三步:
- 获取表单参数:
request.getParameter("username")、request.getParameter("password")、request.getParameter("verifyCode"); - 验证码校验:
String sessionCode = (String) request.getSession().getAttribute("verifyCode");,若为空或不等于表单值,跳转fail.html; - 密码比对:调用
MD5Util.getMD5(password + "javaweb")生成加盐MD5,再与数据库查出的user.password字段比对。
// LoginServlet.java 片段 String inputCode = request.getParameter("verifyCode"); String sessionCode = (String) request.getSession().getAttribute("verifyCode"); if (sessionCode == null || !sessionCode.equalsIgnoreCase(inputCode)) { response.sendRedirect("fail.html"); return; } // 查询用户 User user = userDao.findByUsername(username); if (user != null && user.getPassword().equals(MD5Util.getMD5(password + "javaweb"))) { request.getSession().setAttribute("user", user); // 登录成功存user对象到Session response.sendRedirect("display.jsp"); // 跳转主页面 } else { response.sendRedirect("fail.html"); }注意:equalsIgnoreCase()用于忽略验证码大小写,但密码比对必须严格区分大小写——这是安全底线。
4. 增删改查与Excel导入导出:DAO层封装与POI实战细节
4.1 DAO层设计:StudentDao.java的CRUD方法与SQL注入防护
src/dao/StudentDao.java是数据访问核心,所有SQL都用PreparedStatement参数化,杜绝SQL注入:
public class StudentDao { private Connection conn; // 查询全部(带分页) public List<Student> findAll(int start, int pageSize) throws SQLException { String sql = "SELECT * FROM student LIMIT ?, ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, start); // 第一个?设为start ps.setInt(2, pageSize); // 第二个?设为pageSize ResultSet rs = ps.executeQuery(); // ... 封装Student对象列表 return list; } // 插入 public void insert(Student student) throws SQLException { String sql = "INSERT INTO student (name, gender, age, class, phone, email, photo) VALUES (?, ?, ?, ?, ?, ?, ?)"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, student.getName()); ps.setString(2, student.getGender()); ps.setInt(3, student.getAge()); ps.setString(4, student.getClass()); ps.setString(5, student.getPhone()); ps.setString(6, student.getEmail()); ps.setString(7, student.getPhoto()); ps.executeUpdate(); } // 删除 public void deleteById(int id) throws SQLException { String sql = "DELETE FROM student WHERE id = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, id); ps.executeUpdate(); } }关键点:
LIMIT ?, ?实现物理分页,比SELECT * FROM (SELECT ..., ROW_NUMBER() OVER() rn FROM student) t WHERE t.rn BETWEEN ? AND ?更高效;- 所有
setXxx()方法传参,避免字符串拼接; deleteById用int id而非String id,防止传入恶意字符串如"1 OR 1=1"。
4.2 Excel导入:Import1.jsp与ImportServlet.java的Apache POI解析
导入功能在import1.jsp页面触发,后端ImportServlet.java处理:
// ImportServlet.java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Part filePart = request.getPart("excelFile"); // 获取上传的Excel文件 String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // 1. 读取Excel流 InputStream is = filePart.getInputStream(); Workbook workbook = WorkbookFactory.create(is); // 自动识别xls/xlsx Sheet sheet = workbook.getSheetAt(0); // 2. 遍历行(跳过标题行) for (int i = 1; i <= sheet.getLastRowNum(); i++) { Row row = sheet.getRow(i); if (row == null) continue; Student student = new Student(); student.setName(getCellValue(row.getCell(0))); student.setGender(getCellValue(row.getCell(1))); student.setAge(Integer.parseInt(getCellValue(row.getCell(2)))); student.setClass(getCellValue(row.getCell(3))); student.setPhone(getCellValue(row.getCell(4))); student.setEmail(getCellValue(row.getCell(5))); // photo留空,导入时不处理头像 studentDao.insert(student); // 调用DAO插入 } response.sendRedirect("display.jsp?msg=导入成功"); }getCellValue()辅助方法:
private String getCellValue(Cell cell) { if (cell == null) return ""; switch (cell.getCellType()) { case STRING: return cell.getStringCellValue(); case NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { return cell.getDateCellValue().toString(); } else { return String.valueOf((long) cell.getNumericCellValue()); // 防止科学计数法 } default: return ""; } }避坑点:
WorkbookFactory.create(is)自动适配.xls和.xlsx,不用分开判断;getCell(2)取年龄时用Integer.parseInt(),但Excel里数字单元格类型是NUMERIC,需先转字符串再解析;DateUtil.isCellDateFormatted(cell)判断是否为日期格式,避免把日期当数字解析成毫秒值。
4.3 Excel导出:ExportServlet.java的响应头与中文文件名
导出功能由export.jsp触发,ExportServlet.java生成Excel并写回响应流:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Student> students = studentDao.findAll(0, Integer.MAX_VALUE); // 查全部 // 创建工作簿 Workbook workbook = new XSSFWorkbook(); // 强制用xlsx,兼容性更好 Sheet sheet = workbook.createSheet("学生信息"); // 写表头 Row headerRow = sheet.createRow(0); String[] headers = {"ID", "姓名", "性别", "年龄", "班级", "电话", "邮箱", "头像路径"}; for (int i = 0; i < headers.length; i++) { Cell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); } // 写数据 for (int i = 0; i < students.size(); i++) { Row row = sheet.createRow(i + 1); Student s = students.get(i); row.createCell(0).setCellValue(s.getId()); row.createCell(1).setCellValue(s.getName()); row.createCell(2).setCellValue(s.getGender()); row.createCell(3).setCellValue(s.getAge()); row.createCell(4).setCellValue(s.getClass()); row.createCell(5).setCellValue(s.getPhone()); row.createCell(6).setCellValue(s.getEmail()); row.createCell(7).setCellValue(s.getPhoto()); } // 设置响应头 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("UTF-8"); String fileName = URLEncoder.encode("学生信息_" + System.currentTimeMillis() + ".xlsx", "UTF-8"); response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + fileName); // 写出流 ServletOutputStream out = response.getOutputStream(); workbook.write(out); out.close(); workbook.close(); }中文文件名关键:
URLEncoder.encode(..., "UTF-8")编码文件名;filename*=UTF-8''是RFC 5987标准,Chrome/Firefox/Edge均支持,IE需用filename=+new String(fileName.getBytes("GBK"), "ISO8859-1")兼容,但本项目未做IE兼容;response.setCharacterEncoding("UTF-8")确保Excel内中文不乱码。
5. 头像上传与显示:UploadServlet.java的文件保存路径与安全边界
5.1 头像上传流程:upload.jsp表单与UploadServlet.java的磁盘写入
头像上传在upload.jsp页面完成,表单enctype="multipart/form-data",后端UploadServlet.java处理:
// UploadServlet.java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Part filePart = request.getPart("photo"); String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // 1. 生成唯一文件名(防重名) String ext = fileName.substring(fileName.lastIndexOf(".")); String newFileName = System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8) + ext; // 2. 确定保存路径(WebContent/imgfile/) String uploadPath = request.getServletContext().getRealPath("/imgfile/"); File uploadDir = new File(uploadPath); if (!uploadDir.exists()) uploadDir.mkdirs(); // 3. 写入文件 Path filePath = Paths.get(uploadPath, newFileName); filePart.write(filePath.toString()); // 4. 返回相对路径给前端(存入student.photo字段) String relativePath = "imgfile/" + newFileName; request.setAttribute("photoPath", relativePath); request.getRequestDispatcher("Update1.jsp").forward(request, response); }路径安全要点:
request.getServletContext().getRealPath("/imgfile/")获取Web应用根目录下的imgfile文件夹绝对路径,确保文件存到项目内;Paths.get(uploadPath, newFileName)构造安全路径,避免../../etc/passwd路径遍历攻击(因为getSubmittedFileName()返回的是原始文件名,但write()方法内部已做路径净化);relativePath = "imgfile/" + newFileName是存入数据库的值,前端show.jsp用<img src="${student.photo}">直接渲染。
5.2 头像显示优化:show.jsp中的CSS裁剪与响应式
头像显示在show.jsp,用naive.css控制样式:
<!-- show.jsp 片段 --> <div class="avatar-container"> <img src="${student.photo}" alt="头像" class="avatar-img"> </div>/* naive.css */ .avatar-container { width: 120px; height: 120px; border-radius: 50%; overflow: hidden; border: 2px solid #ddd; margin: 0 auto; } .avatar-img { width: 100%; height: 100%; object-fit: cover; /* 关键:等比缩放并裁剪,填满容器 */ }object-fit: cover的价值:
- 用户上传的头像可能是1920×1080大图,也可能是100×100小图;
cover保证图片等比缩放后完全覆盖容器,多余部分裁剪,视觉统一;- 若用
contain,则会出现白边;用fill会拉伸变形。
5.3 文件类型与大小限制:服务端校验的硬性防线
UploadServlet.java在写入前必须校验,否则可能被上传JSP木马:
// 在write之前加入 String contentType = filePart.getContentType(); if (!contentType.equals("image/jpeg") && !contentType.equals("image/png") && !contentType.equals("image/gif")) { request.setAttribute("error", "只允许上传JPG、PNG、GIF格式图片!"); request.getRequestDispatcher("upload.jsp").forward(request, response); return; } long fileSize = filePart.getSize(); if (fileSize > 5 * 1024 * 1024) { // 5MB request.setAttribute("error", "文件大小不能超过5MB!"); request.getRequestDispatcher("upload.jsp").forward(request, response); return; }为什么只信getContentType()?
- 浏览器上传时
Content-Type由文件扩展名决定,可伪造; - 但结合
getSize()限制,已能阻挡99%的恶意上传; - 真正严谨的做法需用
Tika解析文件魔数(Magic Number),但课程设计级别无需过度复杂化。
6. 避坑指南:五个血泪经验总结(现象→原因→解决)
6.1 现象:启动Tomcat后访问login.jsp返回404
原因:IDEA中Tomcat的Application context未清空,默认为/studentManagement-master,导致实际访问路径是http://localhost:8080/studentManagement-master/login.jsp,而你直接输/login.jsp;
解决:在IDEA的Tomcat Run Configuration → Deployment → Application context栏,手动删除所有字符,只留一个/,重启Tomcat。
6.2 现象:Excel导入中文姓名显示为??或乱码
原因:dbjsp.sql建库时未指定CHARACTER SET utf8mb4,或MySQL连接URL缺少useUnicode=true&characterEncoding=utf8mb4参数;
解决:
- 重建数据库:
DROP DATABASE dbjsp; CREATE DATABASE dbjsp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 修改
src/dao/BaseDao.java中连接URL:jdbc:mysql://localhost:3306/dbjsp?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=GMT%2B8 - 重启Tomcat,重新执行
dbjsp.sql。
6.3 现象:验证码图片不显示,控制台报java.lang.NoClassDefFoundError: java.awt.Graphics2D
原因:Tomcat运行在Headless模式(无图形界面),而BufferedImage依赖AWT图形库;
解决:在Tomcat启动脚本(bin/catalina.sh或catalina.bat)中添加JVM参数:
# Linux catalina.sh 第200行附近添加 JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=false"或Windowscatalina.bat中:
set JAVA_OPTS=%JAVA_OPTS% -Djava.awt.headless=false6.4 现象:点击「删除」按钮后页面空白,无任何提示
原因:DeleteServlet.java中删除后未做重定向,而是直接forward到display.jsp,但display.jsp依赖request.getAttribute("students"),而forward时该属性未设置;
解决:修改DeleteServlet.java末尾:
// 错误写法(forward导致request域丢失) // request.getRequestDispatcher("display.jsp").forward(request, response); // 正确写法(重定向,重新发起请求) response.sendRedirect("display.jsp?msg=删除成功");并在display.jsp开头加:
<c:if test="${not empty param.msg}"> <script>alert('${param.msg}');</script> </c:if>6.5 现象:头像上传后show.jsp显示404,图片路径为http://localhost:8080/imgfile/xxx.jpg
原因:UploadServlet.java中生成的relativePath是imgfile/xxx.jpg,但show.jsp用${student.photo}直接拼接,而Tomcat默认将WebContent作为WebRoot,所以正确路径应是/imgfile/xxx.jpg(前面多一个/);
解决:在UploadServlet.java中:
// 原来 String relativePath = "imgfile/" + newFileName; // 改为(加前导斜杠) String relativePath = "/imgfile/" + newFileName;确保数据库存的路径以/开头,前端<img src="${student.photo}">才能正确解析。
7. 进阶技巧:三步把「学生信息管理」改成「教师信息管理」(含字段、SQL、JSP联动修改)
做完课程设计交差只是起点,真正体现你工程能力的是快速定制化改造。我带学生做过的最典型需求:把student系统改成teacher系统。这不是全局替换字符串,而是有逻辑的三步联动修改,漏一步就会报错。
7.1 第一步:数据库层——建表与初始数据迁移
dbjsp.sql不能只改表名,还要考虑业务字段差异。学生有class(班级),教师有department(院系);学生有age,教师更关注title(职称)。修改如下:
-- 原student表 -- CREATE TABLE student (id..., class VARCHAR(30), ...); -- 改为teacher表 CREATE TABLE teacher ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL, gender VARCHAR(10), age INT, department VARCHAR(50), -- 替换class title VARCHAR(20), -- 新增职称 phone VARCHAR(20), email VARCHAR(50), photo VARCHAR(100) ); -- 初始数据也要改(可选) INSERT INTO teacher (name, gender, age, department, title, phone, email) VALUES ('张教授', '男', 45, '计算机学院', '教授', '13800138000', 'zhang@university.edu');关键点:
department长度设为50,因院系名通常比班级名长(如“人工智能与大数据研究院”);title设为VARCHAR(20),覆盖“讲师/副教授/教授/特聘研究员”等;- 不删原
student表,新表名teacher,避免影响已有代码逻辑(后续Java类名也同步改)。
7.2 第二步:Java层——实体类、DAO、Servlet全链路重命名
src/下所有student相关类必须同步改名,否则编译失败:
| 原路径 | 新路径 | 修改内容 |
|---|---|---|
src/entity/Student.java | src/entity/Teacher.java | 类名、字段class→department、新增title字段及getter/setter |
src/dao/StudentDao.java | src/dao/TeacherDao.java | 类名、SQL语句中student→teacher、class→department |
src/servlet/AddServlet.java | src/servlet/AddTeacherServlet.java | 类名、StudentDao→TeacherDao、request.getParameter("class")→("department") |
特别注意AddTeacherServlet.java中的字段映射:
// 原student代码 student.setClass(request.getParameter("class")); // 改为teacher teacher.setDepartment(request.getParameter("department")); teacher.setTitle(request.getParameter("title")); // 新增7.3 第三步:JSP层——页面字段与URL路由更新
WebContent/下所有JSP需改三处:表单字段、数据显示、URL跳转:
| JSP文件 | 修改点 | 示例 |
|---|---|---|
add.jsp | <input name="class">→<input name="department">,新增<input name="title"> | <input type="text" name="department" placeholder="所属院系"> |
display.jsp | <th>班级</th>→<th>院系</th>,<td>${s.class}</td>→<td>${s.department}</td>,新增<th>职称</th>列 | <td>${s.title}</td> |
Update.jsp | 所有class字段改为department,并增加title输入框 | <input type="text" name="title" value="${teacher.title}"> |
终极验证技巧:
改完后不要急着启动,先用IDEA的Find in Path(Ctrl+Shift+F)搜索整个项目:
- 搜
student,确认只剩studentManagement-master项目名和README.md中的描述; - 搜
class(作为字段名),确认结果只有Teacher.java中的department字段,无残留; - 搜
/student,确认所有URL路径(如response.sendRedirect("display.jsp"))未硬编码/student前缀。
从那以后我每次接到「把A系统改成B系统」的需求,都强制走一遍这三步:数据库→Java→JSP,逐层穿透,绝不跨层跳改。因为Java类名错了编译不过,JSP字段名错了页面报500,而SQL表名错了连启动都失败——这种分层校验就是最好的后悔药。希望帮到你。
本文还有配套的精品资源,点击获取