简介:一份面向JavaWeb初学者的学生信息管理系统课程设计资料包,使用Eclipse开发、MySQL存储数据、Tomcat 9作为服务器,涵盖学生信息增删改查等典型功能,适合计算机专业学生完成课程设计或毕业设计参考。包体共4个文件,约128MB,包括2个zip压缩包(学生信息管理系统源码工程、MySQL与Navicat及驱动工具包)、1个SQL数据库脚本和1个Word课程设计报告,结构清晰,对应部署、数据和文档输出。目前已有7361人学习下载。压缩包内含可直接导入的数据库脚本,配合Navicat可视化工具导入后,用Eclipse打开项目并修改JDBC连接密码即可运行;设计文档提供了系统模块划分与数据库表设计说明,可直接作为课程设计报告素材,帮助读者少走弯路,快速完成作业或项目演示。
1. JavaWeb学生信息管理系统课程设计报告到底装了什么:从能跑通到讲得清
很多同学拿到「JavaWeb学生信息管理系统课程设计报告.zip」这个压缩包时,第一反应是解压、改个名字、直接交差。真正做过一次的人会告诉你,这个压缩包里最值钱的不是那几十页报告,而是代码与文档能不能互相印证。它要回答的问题很具体:登录是怎么鉴权的、学生数据的增删改查走哪几条路径、数据库表为什么这样建、测试记录是不是真能复现。这篇文章就按我平时带课程设计项目时的习惯,把这个压缩包拆成一条可以照着做的完整路径,新手照着能跑通,熟手拿它当检查清单。
2. 学生信息管理系统的技术选型与数据库设计:先定表结构再写代码
课程设计类项目最怕「能跑但讲不清原理」,而且越写到后期,改一张表引起的连锁反应越明显。所以动手写第一行 Java 之前,我会先把技术栈和两张核心表定下来。技术选型决定了答辩时老师提问的方向,数据库表结构决定了业务代码要写多少遍。
2.1 三种技术栈组合:哪一种更适合课程设计答辩
常见做法把JavaWeb课程设计分成三条路线,我按教学场景里最常见的选择排个序,适合情况也一起列出。
| 技术栈组合 | 适合情况 | 上手成本 |
|---|---|---|
| JSP + Servlet + JDBC | 课程要求必须手写 JDBC、重点考察 Web 基础原理 | 中等 |
| Servlet + JSP + MyBatis | 想兼顾 Web 基础和主流 ORM,写增删改查效率高 | 较低 |
| Spring Boot + Thymeleaf | 以后打算直接走企业服务端方向,想提前练 Spring 家族 | 低但提问面宽 |
如果课程要求里明确写了「必须使用 JSP/Servlet」,那就老老实实走第一行。如果只写了「JavaWeb」,我一般推荐第二行:Servlet 负责控制器和转发逻辑,MyBatis 只替换掉手写 JDBC 的部分,课设该考察的 Session、Filter、请求转发、分页这些知识点一个都不少。选第三行不是不行,但答辩时老师容易往前追问 Spring Boot 自动装配、内嵌容器、依赖管理,刚学完 Servlet 的同学往往在这里卡住。
选定组合之后就不要中途换。我见过有同学先写 JSP+JDBC,写到一半觉得重复代码太多又引入 MyBatis,结果连接管理逻辑混在里面,数据库连接一会开一会不关,数据库连接池直接报错。换技术栈的时间成本远高于一开始多花半小时做决定的时间成本。
2.2 学生信息管理系统的核心表设计:人员与业务分离
课程设计规模一般不大,但表设计最好按「人员与业务分离」的思路来。所谓人员表放登录和身份信息,业务表放学生档案数据,不要把所有字段堆在一张表里。这是评审时最容易加印象分的地方,也是后续扩展功能最省事的结构。
我在这类项目里通常只设计两张核心表,必要时再加一张班级表,但我也会把班级直接做成学生表里的一个字段。两张表的结构可以这样起步:
-- 用户表:负责登录和基础权限 CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT '登录账号', password VARCHAR(64) NOT NULL COMMENT '密码,建议存MD5或加盐哈希', real_name VARCHAR(50) COMMENT '真实姓名', role VARCHAR(20) DEFAULT 'ADMIN' COMMENT '角色,预留扩展', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 学生表:业务主体 CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE COMMENT '学号,唯一索引', name VARCHAR(50) NOT NULL COMMENT '姓名', gender TINYINT DEFAULT 0 COMMENT '0-男,1-女', birth_date DATE COMMENT '出生日期', phone VARCHAR(20) COMMENT '联系电话', email VARCHAR(100) COMMENT '邮箱', class_name VARCHAR(100) COMMENT '班级名称,课设里不拆表更省事', status TINYINT DEFAULT 1 COMMENT '1-在读,0-离校', create_time DATETIME DEFAULT CURRENT_TIMESTAMP );字段设计里有三个细节可以重点关注。第一个是 gender 用 TINYINT 而不是 CHAR(2),存 0 和 1 在报表统计时更友好,前端展示时再转换成“男/女”。第二个是 student_no 加 UNIQUE 约束,这是学生信息系统的核心自然键,不能出现两条同样学号的数据。第三个是 class_name 用字符串而不是独立班级表,课程设计阶段可以减少一张表、一个外键关联和一套增删改查,报告也好写;如果题目明确要做班级管理,再拆出去也不迟。
2.3 初始化 SQL 脚本示例与导入建议
数据库不是只建表就结束,初始数据一样重要。课程设计演示的时候,评委直接打开你登录页面输入账户,如果数据库里空无一物,第一印象就崩了。所以初始化脚本要连表带数据一起准备好。
-- 初始化数据 INSERT INTO sys_user (username, password, real_name) VALUES ('admin', 'e10adc3949ba59abbe56e057f20f883e', '管理员'); INSERT INTO student (student_no, name, gender, birth_date, phone, email, class_name) VALUES ('20230001', '张同学', 0, '2003-05-12', '13800000001', 'zhang@example.com', '软件工程2301'), ('20230002', '李同学', 1, '2003-09-20', '13800000002', 'li@example.com', '软件工程2301'), ('20230003', '王同学', 0, '2004-01-08', '13800000003', 'wang@example.com', '软件工程2302');这里 admin 的密码串是空字符串的固定值,我可以明确说它对应的是统一初始密码。很多教程喜欢直接写明文 123456,我看着总觉得不踏实,哪怕只做一个登录表单,这是快速迭代时会认真考虑的一行代码。
导入时注意两点。第一,脚本文件要在数据库客户端里用「运行 SQL 文件」的方式整体执行,不要复制到命令行窗口手动粘贴,编码格式容易出问题。第二,如果之前已经建过同名数据库,先执行 DROP DATABASE 再重新建,避免重复建表报错。你最终交给老师的不应该是一个裸的建表语句,而是一份能一次性恢复演示环境的初始化脚本,这在答辩现场非常加分。
3. 用 Servlet + JSP + MyBatis 把核心功能跑通:登录、增删改查与分页
技术栈定了、表建好了,接下来就是把用户最关心的功能点串起来。我会按项目目录结构、登录过滤器、增删改查、分页查询四个部分展开,每一段都能直接对应到课程设计报告里的「系统实现」章节。
3.1 项目目录结构与 Maven 依赖配置
课程设计项目不需要多复杂的架构,但包结构必须清晰。我习惯把项目拆成 standard Maven 目录,这样报告里画系统架构图的时候可以直接引这一段结构。
src/main/java ├── com.demo.controller // Servlet 控制器 ├── com.demo.service // 业务逻辑层 ├── com.demo.dao // MyBatis 接口 ├── com.demo.entity // 实体类 ├── com.demo.filter // 过滤器 src/main/resources ├── mybatis-config.xml // MyBatis 配置 ├── mapper/StudentMapper.xml // SQL 映射 src/main/webapp ├── WEB-INF/web.xml ├── jsp/login.jsp ├── jsp/student_list.jsp ├── jsp/student_add.jsp └── jsp/student_edit.jsppom.xml 里最关键的依赖是这几个,版本号我不写死,按你本地仓库已有的版本选,重点是版本之间不要冲突。
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.16</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.33</version> </dependency> </dependencies>这段配置里有几个容易踩的小要点:servlet-api 的 scope 必须设成 provided,因为 Tomcat 自带这个库,如果打成 war 包时把它带进去,会和容器本身的实现冲突。JSTL 版本固定用 1.2,别追新,旧项目兼容性最稳。mysql-connector 的版本要和你本地的 MySQL 大版本对应,8.x 驱动配 MySQL 5.x 服务端也行,但反过来容易报认证协议错误。
3.2 登录过滤器与 Session 管理的实现细节
登录功能做完之后,下一步就是避免每个页面都去重复判断登录状态。我的习惯是写一个全局过滤器,把 Session 检查集中起来。这样代码行数少,答辩的时候还能讲清 Filter 的作用。
@WebFilter("/*") public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; String path = req.getRequestURI(); if (path.endsWith("/login.jsp") || path.endsWith("/login") || path.contains("/static/")) { chain.doFilter(request, response); return; } Object user = req.getSession().getAttribute("loginUser"); if (user == null) { resp.sendRedirect(req.getContextPath() + "/login.jsp"); return; } chain.doFilter(request, response); } }这段代码的逻辑不复杂,但值得讲清三处细节。第一处是放行条件,登录页和静态资源必须放行,否则会出现死循环——登录页被过滤器拦下来,重定向到登录页,又被拦住。第二处是过滤器的判断顺序,先放行,再判断 Session,顺序反了会让登录请求直接被踢回登录页。第三处是重定向要用 req.getContextPath()+路径,不能写死成 /login.jsp,部署时如果项目名变了,写死路径就是404。
3.3 学生信息的增删改查:Dao 层与 Service 层的代码分工
学生信息管理的核心是增删改查,这个模块没啥玄学,真正会出问题的是事务控制和 SQL 映射。我平时最少会写一个 dao 接口、一个 mapper XML、一个 service 实现类。下面是一个学生删除功能的简化版。
public interface StudentDao { Student selectByNo(String studentNo); int insert(Student student); int updateById(Student student); int deleteById(Integer id); List<Student> selectPage(@Param("offset") int offset, @Param("size") int size, @Param("keyword") String keyword); long count(@Param("keyword") String keyword); }对应的 XML 映射文件:
<delete id="deleteById" parameterType="int"> DELETE FROM student WHERE id = #{id} </delete> <select id="selectPage" resultType="com.demo.entity.Student"> SELECT * FROM student <where> <if test="keyword != null and keyword != ''"> AND (student_no LIKE CONCAT('%', #{keyword}, '%') OR name LIKE CONCAT('%', #{keyword}, '%')) </if> </where> ORDER BY id DESC LIMIT #{size} OFFSET #{offset} </select>这里 explain 一遍我为什么这样写。deleteById 用 parameterType="int",接口里就是 Integer id,不要顺手写成 String,参数类型不匹配在某些旧版本 MyBatis 里能查出数据但不是预期效果。selectPage 里的 LIMIT 和 OFFSET 都通过 @Param 传参,安全上比字符串拼接强得多,也顺便杜绝了 SQL 注入的可能。WHERE 和 AND 用 和 拼接,keyword 为空时不会报 SQL 语法错,这是处理动态查询的标准写法。
Service 层其实就干两件事:调用 Dao,控制事务。用 MyBatis 时没有 Spring 管理事务,我就在 Service 里显式开启提交:
SqlSession session = MyBatisUtil.getSqlSession(); try { StudentDao dao = session.getMapper(StudentDao.class); dao.deleteById(id); session.commit(); } catch (Exception e) { session.rollback(); throw e; } finally { session.close(); }先说清楚:课程设计里很多人把 session 写在 Servlet 里,写完 SQL 就 close,这不是不能跑,而是耦合太重。一旦后续加第二个操作,代码就要大改。我一般要求把 SqlSession 的开关全部收到 Service 里,Servlet 里输了什么都不直接碰 SqlSession,Controller 变薄,报告里的分层图才画得出来。
3.4 分页查询的参数设计与前端 JSP 表格渲染
学生记录一旦超过几十条,不分页就等着页面卡顿和答辩被问「为什么不分页」。后端分页其实就两个参数:pageNum 当前页和 pageSize 每页条数,再加上一个 keyword 做模糊查询。
int pageNum = 1; int pageSize = 10; String pageNumStr = request.getParameter("pageNum"); if (pageNumStr != null && !pageNumStr.isEmpty()) { pageNum = Integer.parseInt(pageNumStr); } int offset = (pageNum - 1) * pageSize; List<Student> list = studentService.selectPage(offset, pageSize, keyword); long total = studentService.count(keyword); int totalPages = (int) Math.ceil((double) total / pageSize); request.setAttribute("list", list); request.setAttribute("totalPages", totalPages); request.setAttribute("pageNum", pageNum); request.getRequestDispatcher("/jsp/student_list.jsp").forward(request, response);这里有一个经常翻车的细节:MySQL 的 LIMIT 关键字,第一位是偏移量 offset,第二位才是条数 size。第一页 offset 是 0,第二页是 10,如果你直接传 pageNum=2 给 LIMIT 2,10,拿到的就是第 3 条到第 12 条的数据,完全错位。代码里先算 offset 再传给 Dao,就是我不想让这个 bug 有存活空间。
前端 JSP 我习惯用 JSTL 渲染,既简单也符合课程设计预期。
<c:forEach var="stu" items="${list}"> <tr> <td>${stu.studentNo}</td> <td>${stu.name}</td> <td>${stu.gender == 0 ? '男' : '女'}</td> <td>${stu.className}</td> <td> <a href="student/edit?id=${stu.id}">编辑</a> <a href="student/delete?id=${stu.id}" onclick="return confirm('确定删除吗?')">删除</a> </td> </tr> </c:forEach>JSTL 里直接写 ${stu.gender == 0 ? '男' : '女'} 是合法的 EL 三元表达式,不需要在 Servlet 里提前转好字符串。这个思路刚好能和报告里「表现层与数据层分离」的说法对应起来,记录一下,写报告时能用上。
4. 课程设计报告怎么写:把代码转成一份能答辩的十三页文档
压缩包里最难搞的,往往不是代码而是课程设计报告。代码重写一遍不难,报告如果逻辑混乱、截图和代码对不上,答辩现场等于自己在挖坑。我按常见的课程设计报告结构来讲,从需求分析到测试结论,每部分写什么、写多少、截图怎么截。
4.1 报告结构:需求分析、系统设计、数据库设计、测试结论
常见的课程设计报告按下面这个顺序走,顺序错了容易让评委觉得是你把代码硬套到模板里。
| 报告章节 | 重点内容 | 建议篇幅 |
|---|---|---|
| 引言 | 项目背景、解决的问题、开发环境 | 1~2 页 |
| 需求分析 | 功能性需求与用例描述 | 2~3 页 |
| 系统设计 | 功能模块图、架构图、流程图 | 3~4 页 |
| 数据库设计 | ER 图、表结构说明 | 2~3 页 |
| 系统实现 | 关键代码与页面截图 | 3~5 页 |
| 测试 | 测试用例表、结果分析 | 1~2 页 |
| 总结 | 遇到的问题与收获 | 1 页 |
需求分析这一章不要写一堆套话,我建议直接列功能点:系统支持管理员登录、支持学生信息新增、修改、删除、查询,支持按学号/姓名模糊查询,支持分页展示。每一条都要能在代码里找到对应功能,不然老师随手问一个「你说的导出功能在哪」,场面会很尴尬。
系统设计章节里必须有两张图:一张功能模块图,一张系统架构图。我用简单的分层图就行,从上到下是 JSP 展示层 → Servlet 控制层 → Service 业务层 → Dao 数据访问层 → MySQL。这张图画出来,报告的专业感会高一个档次。
4.2 测试用例表格与系统截图怎么截才有说服力
很多同学把测试写成一页「系统功能正常,符合要求」,这等于没写。我自己的习惯是测试章节放一张表格,按功能模块拆几条用例写清楚。
| 功能模块 | 测试步骤 | 预期结果 | 实际结果 |
|---|---|---|---|
| 登录模块 | 输入正确账号密码,点击登录 | 跳转到学生列表页 | 与预期一致 |
| 登录模块 | 输入错误密码,点击登录 | 提示密码错误并留在登录页 | 与预期一致 |
| 学生查询 | 输入关键字「软工」,点击搜索 | 列表显示班级包含软工的学生 | 与预期一致 |
| 学生删除 | 点击删除按钮并确认 | 列表减少一条记录 | 与预期一致 |
截图建议遵循三条原则:一是登录前后都要截,尤其是登录失败和成功两种状态;二是列表页要带上分页效果,不要只截十条数据;三是新增、编辑、删除的操作按钮和结果页都要有。截图时浏览器地址栏、页面数据状态要保持一致,不要一张截图里是旧版本数据,另一张里是新版本,答辩老师眼睛很尖。
每条测试用例写完都要对应一份实际结果的说明。我见过最典型的情况是测试用例写了 8 条,实际结果只有一句「全部通过」,这是整份报告里最没说服力的写法。哪怕结果写成「通过,查询返回 5 条记录,页面正确显示」,都比一句全部通过要具体得多。
4.3 报告与代码的一致性:目录结构、命名、截图对不上是答辩致命伤
这一节我单独拿出来说,是因为几乎每批课设里都有同学在这里翻车。最常见的现象是:报告里的包名叫 com.example,项目里实际叫 com.test;报告里展示的数据库字段是 class_name,实际建表语句里写成了 className;报告里的截图用的是一个旧版本页面,项目里现在跑的是另一个样子。
这类问题不会让系统跑不起来,但会让老师怀疑报告的原创性。有一次我看一份报告,系统实现章节贴的登录代码用的是 PreparedStatement,而项目工程里跑的是纯 Statement,就这一个细节就能看出报告里写的根本不是这个项目。我通常会在写报告前把代码里的包名、类名、字段名统一过一次,然后拷一份最新的项目运行截图,再开始写。不要一边改需求一边写报告,最后交上去的压缩包对不上。
具体操作时,把代码里的关键类名和报告里的功能模块列一张对照表:登录控制器对应 LoginServlet,学生查询对应 StudentServlet,删除对应 StudentDao.deleteById。这张对照表不用放正文,但自己心里要有。答辩老师翻开报告问「你删除功能在哪实现的」,你如果能直接说在 StudentDao 第几行,比现场翻代码要加分十倍。
5. 学生信息管理系统课程设计的避坑指南:六个环境与代码问题排查
代码写完了、报告也写完了,不代表就能交差。下面的这几类问题我在课程设计指导里见过不下十次,基本每个 JavaWeb 学生信息管理系统都会撞上一两个。我按现象、原因、解决的顺序逐条写清楚。
5.1 Tomcat 启动闪退,控制台没有报错信息
现象:双击 Tomcat 的 startup.bat,黑窗口一闪就消失,浏览器访问 localhost:8080 没反应。
原因:九成是环境变量 JAVA_HOME 没有配置,或者配置路径里有空格、引号。Tomcat 启动脚本必须有 JAVA_HOME 才能找到 JVM,配置不对它直接退出,却不往控制台输出有效报错。
解决:确认一下echo $JAVA_HOME(Windows 上就是echo %JAVA_HOME%),然后检查 Java 安装路径是否在这个变量里。注意 JAVA_HOME 的路径应指向 JDK 根目录,不是 bin 目录。改完环境变量之后要把命令行窗口关掉重新打开,因为环境变量重启才生效。有时候闪退是端口占用,可以在命令行先netstat -ano看 8080 端口有没有被其他进程占用,有的话改 Tomcat 的 server.xml 端口或者停掉占用进程。
5.2 登录后跳转页面白屏,控制台报 NumberFormatException
现象:登录成功后进入学生列表页,页面直接空白,控制台有一行 NumberFormatException,定位到某个 Integer.parseInt 的代码。
原因:页面分页参数 pageNum 传了一个空字符串或非数字值,比如点击搜索时表单里有个为空的分页字段正好被拼进 URL。这种情况在第一次打开分页页面时最容易触发,因为 URL 上还没有 pageNum 参数。
解决:在解析参数前必须做空值判断,不能直接 Integer.parseInt(request.getParameter("pageNum"))。改成先判断是否为空,再解析,parse 过程包一层 try-catch,解析失败给默认值 1。这一处是课程设计里最容易出 bug 的边界条件,报告里也能当成一个「异常处理设计」来写。
5.3 页面中文乱码,数据库也乱码
现象:登录页输入中文姓名,列表页显示成问号或者乱码;数据库里直接查看也是一串看不懂的字符。
原因:典型的三处不一致。第一,JSP 页面没设置 UTF-8,第二,Servlet 读取请求参数时没有设置 request 编码,第三,MySQL 连接 URL 没有加 characterEncoding=utf8 参数,或者建库时字符集不是 utf8mb4。
解决:JSP 最上面写<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>;Servlet 里在所有 request.getParameter 之前执行request.setCharacterEncoding("UTF-8");JDBC 连接串写成这样:
String url = "jdbc:mysql://localhost:3306/student_manage" + "?useUnicode=true&characterEncoding=utf8" + "&serverTimezone=Asia/Shanghai";这三处统一之后,中文不会再出问题。用 MyBatis 的 after 阶段我额外加一条:mysql-connector-j 8.x 的连接参数里 serverTimezone 必须要加,不然时间类型映射和解码都不稳定,这是老教程没写但新版驱动必须写的。
5.4 登录状态总是丢失,Session 一会儿有效一会儿无效
现象:登录成功,跳转到一个页面正常,点几下菜单又跳回登录页。
原因:最常见的是过滤器放行路径写得不对,把包含某些关键字的页面也放行了,或者 session 域里存数据的 key 和取数据的 key 不一致。另一种隐蔽原因是项目用了两个不同的 Context Path 访问同一台 Tomcat 的同一个应用,SessionId 分别创建。
解决:从头到尾检查两件事。第一,登录 Servlet 存 Session 的 key 和过滤器读 Session 的 key 是否完全一致,比如都用 "loginUser",不要一个写 user 一个写 loginUser。第二,过滤器的放行规则只放行 login.jsp 和登录接口,其他页面全部走 Session 判断。如果是跨目录访问导致 Session 丢失,坚持统一通过http://localhost:8080/项目名/访问,不要一会儿带项目名一会儿不带。Session 的 key 和路径是这种问题里最需要统一的地方,字符差一个都会让你调试一下午。
5.5 课程设计报告里的运行截图和实际代码对不上
现象:报告里展示的是「学生管理列表」页面,项目和数据库打开后页面完全不是同一套数据,或者按钮位置不一致。
原因:不少同学是先拿网上找的旧截图填充报告,最后才来补代码,两边的版本、字段、功能对不上。判重和答辩时,老师只要对着代码背后的页面刷新一遍就能拆穿。
解决:这是最容易修复但后果最严重的问题。我建议翻工的做法是:先把项目在本地完整跑一遍,按功能模块顺序截图,然后更新报告里的图、字段名和代码片段。时间紧的话,宁可删掉报告里保不准的部分,也不要留一个无法复现的截图。每个截图边上标注「此图由本地环境运行所得」,这份严谨在答辩时反而能成为亮点。
6. 让学生信息管理系统从「能跑」变成「能答辩」:三个加分技巧
课程设计拿到 60 分到 80 分往往只差几个细节,下面三个改动都不大,但对答辩观感影响很明显。
第一,用一个 Filter 统一处理字符编码,不再每个 Servlet 里重复写三行编码设置。你可以在 LoginFilter 之外再写一个 EncodingFilter,在做任何参数读取之前先设置请求和响应编码:
@WebFilter("/*") 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"); resp.setContentType("text/html;charset=UTF-8"); chain.doFilter(req, resp); } }这个 Filter 加载在 LoginFilter 之前还是之后有讲究。如果编码 Filter 不先执行,LoginFilter 里取到的用户名就可能是乱码,所以我在 web.xml 或者使用 @WebFilter 的 filterName 顺序上把它排在前面。它不解决全部问题,但能让你的 Servlet 代码清爽不少,答辩时也能直接讲「我已经把编码处理收敛到一处」。
第二,分页和模糊查询相结合的 SQL 写法有一个边界要注意。LIKE 条件里我用的是 CONCAT('%', #{keyword}, '%'),而不是直接传 "%"+keyword+"%",前者的好处是 keyword 为空时不会影响全表查询的语义。另一个边界是 keyword 里如果含 % 或 _,会被当成通配符。面试和答辩也有可能追问这个,如果你想避免用户输入 % 干扰,可以对 keyword 做一下转义:
keyword = keyword.replace("\\", "\\\\") .replace("%", "\\%") .replace("_", "\\_");再配合 SQL 里的ESCAPE '\\',就能把通配符当成普通字符处理。这属于加分项,写了这一层,说明你不只在调通功能,还在考虑输入安全。
第三,答辩现场准备一份演示检查清单,这是我带过项目后养成的习惯。演示前花五分钟过一遍:Tomcat 是否已经启动、数据库服务进程是否正常、初始账号密码是否还能登录、导入的学生数据是否完整、浏览器是否开了无痕模式。无痕模式这条很多人忽略,它避免浏览器缓存旧页面导致演示翻车。再准备一个降级预案:如果演示时数据库连不上,立刻打开提前截好的截图按报告讲流程,而不是当场敲代码。这个习惯让我少踩了很多次「演示现场环境炸了」的坑。
带了这么多轮课程设计,我最大的教训就一句话:宁可代码少写两个花哨功能,也不要让代码和报告互相矛盾。项目能跑只是一个起点,讲得清、查得到、测得通才是这个 JavaWeb 学生信息管理系统课程设计报告真正值钱的地方。希望你这次不用踩我踩过的坑,希望帮到你。
本文还有配套的精品资源,点击获取