ARTICLE DETAIL

资讯详情

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

JSP+SQL实验教学管理系统:从环境搭建到部署避坑全解析

JSP+SQL实验教学管理系统:从环境搭建到部署避坑全解析 简介这是一套面向高校计算机专业毕业设计/课程设计的JSPSQL实验教学管理系统完整资料覆盖系统源码、论文、开题报告、封面、中期检查表及英文文献适用于需要快速搭建实验教学管理平台或参考完整毕设文档的开发者。系统基于JSP、EL、JSTL与SQL数据库技术开发实现了用户登录与权限管理、课程管理、实验预约、成绩录入与查询等核心模块同时涉及数据库选型、系统架构设计和前后端交互等内容可帮助理解Web管理系统的完整实现路径。压缩包整体仅1.2MB内含可直接部署运行的Web项目及配套的论文、开题报告等文档材料结构紧凑便于本地调试、二次开发和文档修改。目前已有44人学习浏览既能作为毕业设计答辩的支撑材料也可作为实验教学管理项目原型或JSPSQL技术综合案例能有效节省从选题、编码到文档撰写的整体时间。1. JSPSQL 实验教学管理系统老技术栈为什么还能支撑一整届毕设开学第三周助教抱着一摞实验报告找到我纸质版收上来没人改改了也没人看学生不知道自己哪里扣了分。想要一个能在线发布实验、提交报告、批改打分的小系统周期只有一个月还要能写进毕业论文。我给出的方案就是标题里这套 JSPSQL 实验教学管理系统。它解决的是高校实验教学里最典型的“布置—提交—批改—反馈”链路用 JSP 做页面、SQL Server 存数据代码直白到几乎没有黑匣子。适合准备毕设的本科生、要快速交付课设的开发者也适合需要接手老教务系统维护的人。有人觉得 JSP 已经过气但恰恰是这种“过气”让答辩现场每个函数都能讲清楚论文里每张表都能对上号。2. 需求先于代码实验教学系统的用户角色与五张核心数据表拿到这类交付包最先该看的不是源码而是它能不能回答三个问题谁在用、用哪些页面、数据怎么流转。实验教学管理系统通常跑在校园内网用户分三类学生提交实验报告、教师批改评分、管理员维护课程和账号。数据链路是课程下挂实验实验下挂提交记录提交记录关联学生和成绩。先把这条链理顺后面无论是改代码还是换 Spring Boot都只是换壳不换骨。2.1 三端权限学生、教师、管理员分别该看到什么学生端的核心动作是三个查看实验任务、上传实验报告、查看成绩和评语。不要给学生开放“编辑实验”或“批量打分”的入口这既是权限问题也是后续数据校验的源头。教师端要能创建实验、设置截止时间、下载学生提交的文件、打分并写评语、查看本课程提交率。管理员端负责初始化系统导入学生名单、分配课程、重置密码、按学期归档数据。权限模型直接决定数据表设计。很多毕设翻车前就翻在这里权限写在 JSP 页面里用 if 判断结果是学生直接输入教师页面的 URL 就能访问。正确做法是登录后把用户角色写进 session每个 Servlet 在入口处做一次角色校验页面上的按钮只是展示层的隐藏真正的拦截必须在后端。一套三端权限做下来表结构里至少要有用户表、课程表、实验表、提交表外加一张可选的课程选课关联表。2.2 实验提交与成绩回写的状态流转实验教学管理系统的核心状态机只有三个状态未提交、已提交、已批改。如果需要让学生修改重交可以扩展一个“已退回”状态。状态流转是单向的未提交到已提交已提交到已批改或已退回已退回再到已提交。不要在状态字段里存字符串“未提交”“已提交”用 TINYINT 存 0、1、2展示层再用 JSTL 或 Java 代码映射成中文。原因很简单字符串状态在统计时容易写错一个“已提 交”带空格就能让整月的报表数据对不上。状态字段还要配合时间字段使用。提交时间 submit_time 用来判断是否迟交批改时间 review_time 用来统计教师响应时长。设计表结构时凡是状态流转都要问一句这个状态从哪来、到哪去、触发动作是什么。把状态机画在纸上再建表比写完全部代码再回头加字段省事得多。以下是一套 SQL Server 的核心建表脚本适合做毕设主库。-- 用户表0管理员 1教师 2学生 CREATE TABLE t_user ( user_id INT IDENTITY(1,1) PRIMARY KEY, account VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name NVARCHAR(50) NOT NULL, role TINYINT NOT NULL DEFAULT 2, class_name NVARCHAR(50) NULL, create_time DATETIME DEFAULT GETDATE() ); -- 课程表 CREATE TABLE t_course ( course_id INT IDENTITY(1,1) PRIMARY KEY, course_name NVARCHAR(80) NOT NULL, teacher_id INT NOT NULL, semester VARCHAR(20) NOT NULL ); -- 实验表 CREATE TABLE t_experiment ( exp_id INT IDENTITY(1,1) PRIMARY KEY, course_id INT NOT NULL, exp_title NVARCHAR(100) NOT NULL, exp_desc NVARCHAR(500) NULL, deadline DATETIME NOT NULL, create_time DATETIME DEFAULT GETDATE() ); -- 提交记录表 CREATE TABLE t_submission ( sub_id INT IDENTITY(1,1) PRIMARY KEY, exp_id INT NOT NULL, student_id INT NOT NULL, file_path NVARCHAR(255) NOT NULL, submit_time DATETIME DEFAULT GETDATE(), score DECIMAL(5,2) NULL, comment_text NVARCHAR(255) NULL, status TINYINT NOT NULL DEFAULT 1 ); -- 提交记录高频查询按 实验学生 过滤加联合索引 CREATE INDEX idx_sub_exp_student ON t_submission(exp_id, student_id);这段脚本用的是 SQL Server 语法几个细节要注意。IDENTITY(1,1) 是自增主键比手动生成 GUID 更适合这种系统的分页查询和排序。real_name 和 comment_text 用了 NVARCHAR因为评语可能包含中文VARCHAR 在中文场景下容易出乱码。password 字段留了 64 位建议存 MD5 或 SHA-256 后的十六进制串不要存明文。联合索引建在 exp_id 和 student_id 上这是提交记录表最频繁的查询条件避免全表扫描。如果改用 MySQL脚本差异集中在三处INT IDENTITY 换成 INT AUTO_INCREMENTDATETIME DEFAULT GETDATE() 换成 DEFAULT CURRENT_TIMESTAMPNVARCHAR 换成 VARCHARMySQL 的 VARCHAR 默认就是 UTF-8。SQL Server 和 MySQL 二选一即可不要想着写一套代码同时兼容两个库分页语法和驱动配置都不一样兼容的代价比换库大得多。2.3 打开交付包后先做的事核对论文中的表结构是否与 SQL 脚本一致这类交付包通常包含系统源码、论文、开题报告、中期检查表、英文文献。最值钱的是论文里的数据字典——它会画出一张 ER 图和所有表的字段说明。拿到包的第一件事不是运行源码而是把论文里画的表和实际 SQL 脚本的表逐字段核对。常见的情况是论文里写了 8 张表源码里只剩 5 张或者属性名对不上比如论文叫 submit_time代码里叫 upload_time。答辩时老师最喜欢问这张表是干什么的、和那张表怎么关联如果你对着不一致的文档讲很容易被问住。核对的另一个重点是实验编号规则。有的系统用 t_experiment.exp_id 直接关联课程有的则要求实验编号全局唯一。改成全局唯一需要在插入时手动算 max(exp_id)1这在并发提交时会撞号。建议用数据库自增序列不要自己维护编号除非需求里明确要求“实验编号按课程分组从 01 开始”。3. 把环境装对JDK、Tomcat、SQL Server 的版本搭配与首个可运行页面写 JSP 项目最怕的不是代码是环境。每年都有人卡在 Tomcat 启动报错、驱动类找不到、端口被占这些基础问题上一卡就是两三天。这里给出我实际跑通这类系统的版本搭配JDK 8、Tomcat 8.5、SQL Server 2019 开发版或 Express 版、IDEA 或 Eclipse。这套组合兼容性最好网上绝大部分 JSP 教程和源码包都是按这个配置写的。3.1 版本矩阵为什么是 JDK 8 而不是 JDK 17JSP 和 Servlet 是 Java EE 规范的一部分而 Java EE 规范中 javax.servlet 包在 Tomcat 10 之后改名成了 jakarta.servlet。所有基于 javax 写的老项目直接放到 Tomcat 10 会报 ClassNotFoundException本质上不是代码错了而是包名迁移问题。JDK 8 配合 Tomcat 8.5 或 9用的是老一套 javax 命名空间交付包里的源码不需要任何改动就能编译。另一个实际因素是编译路径。很多学校机房还在用 JDK 8线上服务器给的也是 JDK 8 的镜像。你本地用 JDK 17 编译出的 class 文件放到 JDK 8 的机器上可能直接报 UnsupportedClassVersionError。毕设答辩时用的往往是学院服务器环境由不得你选稳妥起见就锁 JDK 8。如果是新开课题且不要求 JSP我建议直接上 Spring Boot但如果标题指定了 JSPSQL那就老老实实用 JDK 8省得给自己找麻烦。SQL Server 的版本选择上本地开发装 Developer 版或 Express 版即可两种都免费。默认实例名是 MSSQLSERVER默认端口 1433。安装时记得选“混合模式”身份验证也就是同时支持 Windows 身份和 SQL 身份否则 JDBC 连接串里写用户名密码会连不上。安装完成后打开 SQL Server Configuration Manager确认 TCP/IP 协议已启用端口保持 1433。这是 JSP 连不上数据库的第一大坑我见过有人重装了三次 SQL Server最后发现只是 TCP/IP 协议默认是禁用状态。3.2 建库与连接配置db.properties 里的参数决定能不能连上服务装好后第一步是建库。打开 SQL Server Management Studio执行第 2 章那段 CREATE TABLE 脚本数据库名建议叫 lab_manage。JSP 项目访问数据库常见方式是用 javax.sql.DataSource 配连接池Tomcat 在 context.xml 里读配置。但我更推荐在项目里放一个 db.properties 文件用简单的 JDBC 连接先跑通再决定要不要上连接池。代码如下。jdbc.drivercom.microsoft.sqlserver.jdbc.SQLServerDriver jdbc.urljdbc:sqlserver://localhost:1433;DatabaseNamelab_manage;encrypttrue;trustServerCertificatetrue jdbc.usernamesa jdbc.password你的密码 jdbc.maxActive20 jdbc.maxIdle8这里最容易被忽略的是 URL 后边那串参数。encrypttrue;trustServerCertificatetrue 是针对 SQL Server 2019 之后强制 SSL 加密的策略。如果不加这两项驱动会尝试用 SSL 连接 SQL Server而 Java 的信任库中没有服务器的自签名证书直接报“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接”。很多教程里的连接串只有 jdbc:sqlserver://localhost:1433;DatabaseNamexxx那是针对老版本的放到 SQL Server 2019 上就会失败。这个细节在避坑章会再展开。3.3 在 IDEA 里新建 JSP 项目并跑通数据库联通测试IDEA 里建 JSP 项目有两种路径用 Maven 骨架建一个 war 项目或者建普通 Java 项目后手动添加 Web 支持。毕设项目通常不用 Maven因为交付包里的源码大多是直接把 jar 扔进 WEB-INF/lib。这里给出不用 Maven 的做法。步骤一IDEA 中新建一个普通 Java 项目项目名 lab-manageJDK 选 8。步骤二右键项目选“添加框架支持”勾选 Web ApplicationIDEA 会生成 web 目录和 WEB-INF 目录。步骤三把 sqljdbc 驱动 jar 复制到 WEB-INF/lib 下。步骤四在 src 下新建一个 DbUtil.java负责读 db.properties 并返回 Connection。步骤五在 web 目录下新建 test.jsp执行查询并输出结果。先写一个最简单的页面验证链路通不通。% page contentTypetext/html;charsetUTF-8 languagejava % % page importjava.sql.* % % Connection conn null; Statement stmt null; ResultSet rs null; try { Class.forName(com.microsoft.sqlserver.jdbc.SQLServerDriver); String url jdbc:sqlserver://localhost:1433;DatabaseNamelab_manage;encrypttrue;trustServerCertificatetrue; conn DriverManager.getConnection(url, sa, 你的密码); stmt conn.createStatement(); rs stmt.executeQuery(SELECT COUNT(*) FROM t_user); if (rs.next()) { out.println(t_user 表当前记录数: rs.getInt(1)); } } catch (Exception e) { out.println(数据库连接失败: e.getMessage()); } finally { if (rs ! null) try { rs.close(); } catch (Exception ignored) {} if (stmt ! null) try { stmt.close(); } catch (Exception ignored) {} if (conn ! null) try { conn.close(); } catch (Exception ignored) {} } %这段代码故意写在 JSP 里不是为了好看而是为了最快验证环境。Class.forName 注册驱动DriverManager.getConnection 建立连接查询 t_user 的行数页面显示出来就说明 Tomcat、SQL Server、驱动、账号密码四者都正确。注意 finally 里逐级关闭资源虽然这个页面用完即弃但从一开始就养成习惯避免后续写 DAO 时出现连接泄漏。跑通这个页面后后续所有 Servlet 和 DAO 都可以复用同一套连接逻辑。常见的替代方案是用 tomcat-dbcp 连接池这能扛住几十人同时提交报告的场景毕设演示足够了。连接池配置在 context.xml 里写 Resource 标签然后在 DbUtil 里用 InitialContext.lookup(java:comp/env/jdbc/labDB) 获取数据源。对本科毕设来说直接 DriverManager 也不是不能用但论文里写“使用连接池管理数据库资源”会比“每次请求都新建连接”显得专业不少答辩印象分会高一些。4. 用 JSPServlet 把业务落进代码四层结构、PreparedStatement 与文件上传环境通了之后真正的业务代码才登场。交付包里如果是那种 JSP 页面直接写 JDBC 代码的“一坨流”结构建议改成 JSPServletServiceDAO 四层。这不是为了好看是为了让后续改需求时少熬夜。JSP 只负责渲染页面Servlet 接收请求做参数校验Service 层写业务规则DAO 层只做增删改查。各层之间用普通 Java 对象传递数据不让 JDBC 的 ResultSet 漏到 JSP 里。4.1 从 JSP 直接内嵌 JDBC 到四层结构的迁移成本改造的前提是先把数据流转理清。拿提交实验报告这个核心功能举例JSP 页面上学生点了提交按钮表单以 POST 方式发给 UploadServletServlet 先取 session 里的学生 ID再接收上传文件判断是否迟交把文件写到磁盘最后调用 SubmissionDAO 插入一条记录。这套流程里 JSP 只提供表单Servlet 做控制DAO 做数据库写入逻辑是哪一层的事一眼就能看出来。迁移过程不用推翻重写。先把原来的 JDBC 代码块从 JSP 里摘出来放进一个叫 BaseDAO 的类封装 getConnection、close 这些模板方法。然后按表拆 DAOUserDAO、CourseDAO、ExperimentDAO、SubmissionDAO。每个 DAO 只操作一张表方法名和业务动作对应比如 findByExpIdAndStudentId、insertSubmission、updateScore。Service 层组装 DAO 调用比如提交报告这个动作就涉及查询实验截止时间、判断迟交、插入提交记录三步。如果原来的代码在一个大 JSP 里拆完会发现代码量变多但每段代码都能被解释这对答辩比代码行数重要。4.2 防 SQL 注入的正反例PreparedStatement 与字符串拼接的差距标题带着“SQL”那 SQL 注入就是避不开的考点。学生登录页面是注入重灾区攻击者在账号框输入 OR 11如果后端用字符串拼接 SQL这条语句会变成 WHERE account OR 11恒真直接登进去。很多毕设系统就是这么被攻破的。正确写法是用 PreparedStatement 的占位符参数。// 正确PreparedStatement 参数化查询 String sql SELECT user_id, account, real_name FROM t_user WHERE account ? AND password ?; try (Connection conn dataSource.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, account); ps.setString(2, md5Password); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { // 登录成功把用户信息放进 session User user new User(); user.setUserId(rs.getInt(user_id)); user.setAccount(rs.getString(account)); user.setRealName(rs.getString(real_name)); req.getSession().setAttribute(loginUser, user); } } }// 错误字符串拼接 SQL存在注入风险 String sql SELECT * FROM t_user WHERE account account AND password password ; Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql);PreparedStatement 之所以安全是因为它把 SQL 结构和服务端参数分开传输参数值只作为数据处理永远不会被拼进语句里当关键字解析。上面的正确写法里还有两个细节密码字段传的是 md5Password说明密码入库前要做单向哈希不能明文存储查询字段只取了需要的列没有用 SELECT *。写到论文里时这两点都有加分效果尤其“用户密码不允许明文存储”是很多高校对安全性的硬性要求。顺带一提SQL 注入的防护同样适用于班级查询、成绩统计这类带条件筛选的接口不要只在登录页用 PreparedStatement。4.3 实验报告上传与迟交判断文件路径存数据库文件本体存磁盘实验报告的上传是实验教学系统区别于一般 CRUD 系统的重点。常见错误是图省事把文件直接存进数据库的 BLOB 字段结果数据库文件迅速膨胀备份要半小时页面打开越来越慢。正确做法是文件存磁盘数据库只保存相对路径。上传目录要放在 Tomcat 部署目录之外比如 D:/lab_uploads/避免重新部署项目时文件被清掉。Servlet 3.0 开始提供了原生文件上传注解不需要再引第三方 upload 组件。核心代码如下。WebServlet(/upload) MultipartConfig(maxFileSize 20 * 1024 * 1024, sizeThreshold 1024 * 1024) public class UploadServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); User loginUser (User) req.getSession().getAttribute(loginUser); if (loginUser null || loginUser.getRole() ! 2) { resp.sendRedirect(login.jsp); return; } int expId Integer.parseInt(req.getParameter(expId)); // 判断是否迟交拿当前时间和实验截止时间对比 ExperimentService expService new ExperimentService(); Experiment exp expService.findById(expId); boolean late new Date().after(exp.getDeadline()); Part filePart req.getPart(reportFile); String fileName Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); String saveDir D:/lab_uploads/ expId /; File dir new File(saveDir); if (!dir.exists()) dir.mkdirs(); filePart.write(saveDir fileName); // 入库filePath 只存相对路径或拼接后的字符串 SubmissionDAO dao new SubmissionDAO(); dao.insertSubmission(expId, loginUser.getUserId(), saveDir fileName, late ? 1 : 0); resp.sendRedirect(student_dashboard.jsp); } }这段代码有四个关键点。第一个是入口处的角色校验上传接口必须确认 session 里存在学生身份否则任何人拿个 URL 就能往你的服务器写文件。第二个是用 Part.write 保存文件这是 Servlet 规范内置能力不需要手动处理 InputStream 和 OutputStream。第三个是文件名的防路径穿越处理Paths.get(...).getFileName() 会把用户传入的 ../../etc/passwd 这类路径剥掉只保留真正的文件名否则攻击者能把文件写到任意目录。第四个是迟交标记的存储我在 SubmissionDAO.insertSubmission 中收了一个 int isLate 参数库里用 submit_time 配合一个 is_late 字段记录后续教师端可以按迟交过滤。前端表单只要保证 enctypemultipart/form-datainput 的 type 是 filename 和 Servlet 里的 getPart 参数一致即可。提交成功后要提示学生文件已上传并显示提交时间避免学生重复点击。重复点击在并发下会产生两条 submission 记录解决方式是在 DAO 里先按 exp_id 和 student_id 查询已有记录存在则执行 UPDATE 而不是 INSERT。这个去重逻辑不是 SQL 层能完全兜住的因为学生可能在两个 Tab 页同时提交所以业务层要加事务或先查后插。4.4 成绩列表的分页查询SQL Server 与 MySQL 的语法差异成绩列表是教师端最常用的页面几十个学生还好一旦一个班上百人、一个学期上百份报告不分页页面会直接卡死。分页查询的 SQL 是这类系统里最容易踩坑的地方因为 SQL Server 和 MySQL 的写法完全不同。-- SQL Server 写法OFFSET 从 0 开始FETCH NEXT 取每页条数 SELECT sub_id, exp_id, student_id, file_path, score, status FROM t_submission ORDER BY submit_time DESC OFFSET ? ROWS FETCH NEXT ? ROWS ONLY;-- MySQL 写法LIMIT 第一个参数是偏移量第二个是条数 SELECT sub_id, exp_id, student_id, file_path, score, status FROM t_submission ORDER BY submit_time DESC LIMIT ?, ?;两条语句的语义相同但参数位置不一样。SQL Server 的 OFFSET 从 0 开始第一页传 0第二页传 10MySQL 的 LIMIT 5, 10 表示跳过 5 条取 10 条。代码里用后台计算 offset (pageNo - 1) * pageSize前台页码从 1 开始这样两种数据库都能适配。分页查询还有一个隐藏要求ORDER BY 里的字段最好有索引否则数据量增长后 ORDER BY submit_time 会触发文件排序慢 SQL 日志里会频繁出现这个查询。t_submission 表建了联合索引后再给 submit_time 加一个普通索引能显著改善体验。5. 部署与移植避坑JDBC 驱动、字符集、Tomcat 版本的 5 条踩坑记录环境搭建和业务代码都跑通后真正的翻车往往在部署那一刻等着你。本地 IDEA 里点一下绿色三角就能启动的项目导出成 war 放到服务器上就各种报错。这里整理了几条我处理这类系统时反复踩过的坑按现象、原因、解决三部分记录对照排查能省下不少时间。5.1 中文乱码三处编码必须一致现象页面上中文正常但插入数据库后变成问号或者数据库里正常页面上显示一堆乱码。原因JSP 文件编码、Tomcat 请求编码、数据库连接编码三处不一致。JSP 里需要同时设置 contentType 和 pageEncodingTomcat 的 server.xml 里 Connector 标签要加 URIEncodingUTF-8如果用的 MySQL 库连接串里还要加 characterEncodingutf8而 SQL Server 的情况不一样乱码大多数时候不是因为连接串而是因为表字段用了 VARCHAR 而不是 NVARCHAR。解决统一成 UTF-8。JSP 页面头部写% page contentTypetext/html;charsetUTF-8 languagejava %web.xml 里配置一个 CharacterEncodingFilter强制 request 和 response 都用 UTF-8。SQL Server 这侧把所有保存中文的字段类型改成 NVARCHAR删除表重建或者用 ALTER TABLE 修改字段类型。中文乱码这条是最容易修的也是最容易遗漏的因为本机开发库可能恰好是默认排序规则兼容中文到了服务器环境就暴露。5.2 SQL Server 连接失败端口协议与 SSL 加密两座大山现象一代码里连接串写法没问题但运行时报“The TCP/IP connection to host localhost, port 1433 has failed”。原因SQL Server 的 TCP/IP 协议默认是禁用的安装时如果没手动开启JDBC 根本连不上。解决打开 SQL Server Configuration Manager找到 SQL Server 网络配置启用 TCP/IP右键重启 SQL Server 服务然后用 telnet localhost 1433 验证端口是否通。现象二端口通了但连接报“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接”。原因SQL Server 2019 及之后的版本默认强制启用 SSL 加密Java 客户端没有把 SQL Server 的自签名证书加入信任库SSL 握手失败。解决连接串加两个参数 encrypttrue 和 trustServerCertificatetrue。注意这两个参数是配套的只加 trustServerCertificate 不开 encrypt某些驱动版本反而会走回老路报错。这条坑在网上的老教程里基本没写因为早期的 SQL Server 2008/2012 没有强制加密照着旧文章配的新版本必然翻车。5.3 Tomcat 启动慢、JSP 首次访问卡顿内存参数和预编译现象Tomcat 启动后第一次访问任意一个 JSP 页面要等十几秒之后才变快。原因JSP 页面在第一次被访问时才由 JSP 引擎编译成 Servlet class这个编译过程比较耗时尤其是页面比较多、机器内存又小时编译和 GC 抢资源会更慢。解决本机调试时在 IDEA 的运行配置里给 Tomcat 的 VM 参数加上 -Xms512M -Xmx2048M -XX:MetaspaceSize256M让 JVM 一次申请足够的内存不要频繁扩容。如果线上访问量上来后还是慢可以考虑部署前用 Tomcat 的 JspC 工具把所有 JSP 预编译成 class或者干脆在项目启动时用一个 ServletContextListener 触发一次首页访问让 JSP 提前完成编译。对毕设演示来讲第一次访问多等几秒不算致命但答辩现场如果老师让你演示页面卡住十秒相当尴尬。我一般会在系统启动后手动访问一遍核心页面完成预热再开始演示。5.4 传统 JSP 项目打包 war 后 NoClassDefFoundError现象IDEA 里运行一切正常但导出 war 包后部署到另一台 Tomcat启动时报 NoClassDefFoundError: com/microsoft/sqlserver/jdbc/SQLServerDriver。原因war 包里的 WEB-INF/lib 目录没有包含 sqljdbc 驱动 jar。IDEA 的默认项目结构中外部 jar 如果只是被 IDE 引用而没有标记为发布打包时不会被带进 war。解决在 Project Structure 里确认这个 jar 的 scope 是 Compile 而不是 Provided或者直接把 jar 放到 src/main/webapp/WEB-INF/lib 目录下再重新打包。打完包用解压工具看一眼 war 文件的 WEB-INF/lib确认里面有驱动 jar 再上传这一步一分钟就能避免线上翻车。同一个现象也可能是 Tomcat 版本造成的本地用的 Tomcat 8.5线上用的 Tomcat 10javax 和 jakarta 包名不一致代码里的 import javax.servlet.* 全部失效。部署前先确认线上 Tomcat 版本大版本号是 8 或 9不要用 10 或 11 跑老项目。5.5 MySQL 8 时区报错与 SQL Server 强制加密选型时被忽略的差异现象如果交付包默认用的 MySQL 8连接时可能报“The server time zone value Öйú±ê׼ʱ¼ä is unrecognized”或“Public Key Retrieval is not allowed”。原因MySQL 8 的驱动要求客户端显式指定时区且默认禁止从服务器公钥交换做非 SSL 连接。解决连接串补全参数?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingutf8。这条解决了MySQL 这边就没大问题。但更值得说的是选型差异。SQL Server 的默认强制 SSL 加密会在 JDBC 连接时报错MySQL 8 则需要处理时区报错两个数据库各有各的坑。如果你是从零开始做这个课题我会建议优先选 SQL Server因为标题里写的就是 SQL论文里写存储过程的篇幅也好凑如果交付包已经给了 MySQL 的脚本就用 MySQL 别换库。不要因为听说哪个库更流行就临时换库一旦换了所有分页语句、日期函数、驱动配置全部要跟着改这个工作量比写一个模块还大。6. 让这套老代码还能用从 JSP 到 Spring Boot 的三步改造验证老项目改造最容易卡在选择上推倒重写成本高缝缝补补又不甘心。我常用的路径是先做三个小改造让系统在不换技术栈的前提下变得更好维护。第一步给所有页面引入 JSTL替换 JSP 里的% %脚本片段。JSP 里塞 Java 代码的问题不是写起来难受而是页面设计师和开发没法并行。把forEach、if这些逻辑用 JSTL 标签重写后页面结构清晰很多。第二步把 Servlet 的返回值改成 JSON前端页面用 fetch 调用接口JSP 退化成纯静态壳。这一步做完后续迁 Spring Boot 时 Controller 可以直接复用。第三步如果真要迁目标选 Spring Boot 2.7Tomcat 9因为 Spring Boot 3.0 移除了 JSP 支持老页面直接搬过去会全部报错。验证改造是否成功我习惯写一段并发登录脚本模拟三十个学生同时提交报告。用 JMeter 压登录接口观察 Tomcat 线程栈和数据库连接池水位如果提交表没有重复数据且响应时间在 2 秒内说明事务和索引都扛得住。顺带看一下慢 SQL 日志把 ORDER BY submit_time 的查询加个索引压掉。还有一个细节如果要在前面加 nginx 做动静分离记住 nginx 本身不支持 JSP静态资源交给它动态请求反向代理到 Tomcat 8080 端口看到“nginx 支持jsp吗”这类问题基本就是这么回事。做过太多套毕设系统我的习惯是拿到代码先看数据流转再看权限校验最后才看页面漂不漂亮。这套 JSPSQL 系统值不值得投入取决于你愿不愿意把选课、提交、批改这条链路讲清楚。技术栈可以换但这套模型吃透了后面换什么都是在换壳。希望帮到你。本文还有配套的精品资源点击获取
返回列表