恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

JavaWeb学生成绩管理系统源码与数据库设计实战

  • 首页
  • 资讯中心
  • /
  • JavaWeb学生成绩管理系统源码与数据库设计实战

相关资讯

Agent决胜点不在模型智商,而在agent-skills技能包设计 2026/10/7 17:35:15
操作手册高效记录法:结构化、原子化、可检索的实战指南 2026/10/7 17:35:15
物联网底层连接实战:从协议选型到LoRa网关设计 2026/10/7 17:35:15

最新资讯

网页制作中如何改变鼠标的形状:TaoToken 统一 Key 接入 Cursor Base URL 的配置大纲
OpenClaw 基础认知与架构原理(入门篇):从 TaoToken 统一 Key 通道理解 AI Agent 运行链路
初级教程之---Delphi调试:用TaoToken统一Key打通IDE断点与API调用链
干掉 IDEA!Cursor 3 发布,VS Code 那套 IDE 过时了!TaoToken 统一 Key 接入智能体工作流
Agent-Reach:智能体触达能力的工程落地指南
AI时代IT从业者的生存与发展:替代危机下的技能重塑与人机协同新范式|TaoToken 统一 Key 接入实践

今日推荐

SSD不认盘怎么修?金士顿SV300板级排查与短接ROM进工厂模式
Unity 3D RPG开发:C#状态机与物理更新时机实战指南
AIoT开发工程师岗位全景:从嵌入式Linux到边缘计算与端侧AI部署

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

JavaWeb学生成绩管理系统源码与数据库设计实战

发布时间:2026/10/7 17:40:16
JavaWeb学生成绩管理系统源码与数据库设计实战 简介一份基于Java Web技术的高分学生成绩管理系统源码与数据库实现面向计算机相关专业在校生特别是需要完成课程设计或期末大作业的Java初学者可用于掌握业务系统从设计到落地的完整流程。系统采用模块化设计覆盖学生信息管理、成绩录入与查询、统计分析等核心功能通过Servlet与JSP完成前后端交互并使用MySQL作为数据存储端项目结构清晰代码注释详尽便于理解Java Web开发流程与MVC设计模式的实际应用。压缩包内共包含405个文件整体大小约3.45MB其中不仅包括java源码、class编译文件、jsp页面、js脚本、css样式还包含sql数据库脚本及少量IDE配置信息方便直接导入运行和对照学习。目前已有64人浏览学习获取后既能获得可运行的完整项目也能参考数据库设计表结构与分层代码组织方式为自主开发同类管理系统提供扎实的实践范本。1. 基于JavaWeb的高分学生成绩管理系统源码与数据库实现到底在交付什么如果你在课程设计、毕业设计或者求职作品集里见过“基于JavaWeb的高分学生成绩管理系统源码与数据库实现”这个标题它对应的其实是一类很具体的东西一份能跑通的 JavaWeb 工程代码外加一个配套的数据库脚本合在一起完成“学生→课程→成绩”这条主线的增删改查、权限区分和简单的统计报表。反直觉的地方在于这个系统功能上不难可每年都有大量人拿不到高分问题不在代码写不写得出来而是卡在“跑不起来”和“数据库设计不合理”这两关上。作为评选型项目老师看的是工程结构是不是规范、SQL 设计有没有经过思考、事务和权限有没有做对。这篇笔记适合正在做课设/毕设的在校生以及想快速搭一个 JavaWeb 完整案例的入门开发者。我按“选型 → 骨架 → 数据库 → 代码 → 避坑 → 加分”的顺序把一套能拿到高分的做法和盘托出。2. 选型与工程骨架ServletJSP 还是 Spring Boot决定了你后面五天的体验2.1 两个技术路线的界限拿到源码先看有没有 pom.xml“基于JavaWeb”这个说法比较宽现实中对应两种主流交付传统 Servlet JSP JDBC/MyBatis以及 Spring Boot Thymeleaf/Vue。如果你手里是一份现成的源码包第一步是打开工程根目录看有没有pom.xml或者build.gradle。有 Maven/Gradle 坐标文件说明是标准依赖管理工程没有只有一个.war工程目录和 lib 文件夹多半是手工导 jar 的传统 Web 工程。选型上没有绝对的好坏要看交付场景。课程设计我一般会选 Servlet JSP因为答辩时老师最常问的三个问题——“Filter 怎么拦截未登录请求”“事务在哪一层控制”“SQL 怎么防注入”——在传统 Servlet 代码里能讲得最清楚每一行都摆在那。而 Spring Boot 适合毕业设计或求职项目它能展示你懂自动配置、依赖管理和分层架构但代价是老师一句话“你这代码被框架包了大半”你得能接得住。我这里按最贴“JavaWeb源码”惯例的路线来讲Maven 工程 Servlet 4.0 JSP MySQL Druid 连接池。这个组合在“javaweb项目完整案例mysql”和“idea运行javaweb项目配置”这两个高频检索词下能找到最多参照也最能对应“源码与数据库实现”的字面含义。2.2 参考骨架按包结构把三层拆开Filter 统一拦权限一个成绩管理系统业务边界非常清晰管理员管用户和基础数据教师录成绩、改成绩学生查成绩和打印成绩单。代码骨架我一般建议按下面这样铺别把类全堆在一个包下面score-system ├── pom.xml ├── src/main/java │ ├── com/score/entity // User, Student, Course, Score 四张表对应的实体类 │ ├── com/score/dao // 数据访问层只写 SQL 逻辑 │ ├── com/score/service // 业务层控制事务和业务规则 │ ├── com/score/servlet // 控制器层接收请求、调服务、跳转 │ ├── com/score/filter // 编码过滤器、登录鉴权过滤器 │ └── com/score/util // DBUtil、分页工具、字符串校验 ├── src/main/resources │ └── db.properties // 数据库连接配置 ├── src/main/webapp │ ├── WEB-INF/web.xml │ ├── login.jsp │ ├── student/ // 学生端页面 │ ├── teacher/ // 教师端页面 │ └── admin/ // 管理员端页面 └── database └── score_system.sql // 建库建表脚本 初始数据这个结构的好处是实体类只对应数据表字段DAO 只做增删改查Service 管事务和权限判断Servlet 负责把请求参数解析成实体再调用 Service。逻辑链路“JSP → Servlet → Service → DAO → MySQL”每一步都能拿到类名说清楚这正好是评分老师想听的东西。database目录单独放 SQL 脚本是容易被忽视的加分点。老师拿到源码第一件事是打开数据库脚本看表结构而不是先跑代码。脚本里写清楚建库、建表、外键、索引和初始数据比代码里任何一个类都更能证明你“会数据库设计”。2.3 让 IDEA 能直接跑的配置JDK、Tomcat、连接池参数用 IDEA 运行 javaweb 项目配置核心就三处Project Structure 里的 SDK 和 ArtifactRun Configuration 里的 Tomcat Server以及db.properties里的连接参数。SDK 用 JDK 8 最省心Tomcat 用 8.5 或 9.0.xx这两个版本跟 Servlet 4.0 的 API 完全对应。数据库连接这一块不要裸写DriverManager.getConnection()散在 DAO 里而是用一个连接池统一管理。Druid 是国产开源里文档和排错信息最全的课程设计也够用。db.properties这样配driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/score_system?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue usernameroot password123456 initialSize5 maxActive20 maxWait30000关键参数说明characterEncodingUTF-8管的是中文写入不乱码serverTimezoneAsia/Shanghai解决 MySQL 8.0 的时区报错allowPublicKeyRetrievaltrue是 MySQL 8.0 用caching_sha2_password认证时必须要加的不加会报Public Key Retrieval is not allowed。initialSize5是启动时建 5 个初始连接maxActive20是峰值连接上限课设并发量根本碰不到顶保持默认就行。用 IDEA 跑的时候大多数人第一次都在 Artifact 上翻车IDEA 默认的 Artifact 输出不会自动把依赖 jar 包进WEB-INF/lib结果代码里import com.alibaba.druid.*全报红但不报编译错一旦启动 Tomcat 就爆ClassNotFoundException。正确操作是Project Structure → Artifacts → 选择你的 war exploded → 在 Available Elements 里把druid.jar、mysql-connector-java.jar等右键 Put into /WEB-INF/lib。这一步做完启动时才能真正连上数据库。3. 数据库实现四张表的设计、外键与唯一索引是评分老师第一眼看的地方3.1 表结构设计为什么成绩表必须独立且要带唯一索引很多新手会把“学生选课成绩”做成一张大宽表字段全塞进去一个学生一行一行java、math、english三个成绩列。这样设计当时写起来爽后面每个查询都能把自己绕晕而且老师一眼就能看出你还没建立关系的概念。成绩管理系统的核心关系是三张基础表加一张关联表用户表管登录学生表、课程表是基础数据成绩表是学生与课程的多对多关系落点。这里我重点说两个评分点第一个是成绩表必须独立。因为一名学生在同一门课里可能有平时分、期中分、期末分还可能重修补考这些都是纵向行而不是横向列。放在一行里的三个成绩列遇到重修记录就彻底没法表达了。第二个是成绩表需要唯一索引。UNIQUE KEY uk_student_course(student_id, course_id)的作用是数据库层面防重复录入——同一学生对同一门课只能有一条总评记录。这个约束比在 Java 代码里先查一遍再插入要可靠得多因为两个请求并发打进来时代码里的“先查后插”拦不住并发冲突唯一索引能。外键在课设里建议加上。有人觉得外键影响性能、然后把它全删了但在评分场景里外键是展示关系数据库设计能力的标志。只要注意删除策略——学生表删除时成绩表会被约束挡住这是好事不是坏事我们后面专门讲怎么处理。3.2 建库建表 SQL先建主表再建从表初始化一个管理员账号score_system.sql脚本在建表顺序上有讲究先建用户表再建学生表和课程表最后建成绩表。因为成绩表的外键依赖前两张表。反过来先跑成绩表MySQL 会直接报Cannot add foreign key constraint。完整脚本如下CREATE DATABASE IF NOT EXISTS score_system DEFAULT CHARACTER SET utf8mb4; USE score_system; -- 用户表区分管理员、教师、学生三类角色 CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(30) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, user_type TINYINT NOT NULL COMMENT 1管理员 2教师 3学生, real_name VARCHAR(20) NOT NULL, status TINYINT DEFAULT 1 COMMENT 1启用 0禁用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; -- 学生表业务基础数据 CREATE TABLE t_student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(20) NOT NULL, gender TINYINT COMMENT 1男 2女, class_name VARCHAR(50), major VARCHAR(50), phone VARCHAR(20), entry_year VARCHAR(4), user_id INT, CONSTRAINT fk_student_user FOREIGN KEY (user_id) REFERENCES t_user(id) ) ENGINEInnoDB; -- 课程表基础数据 CREATE TABLE t_course ( id INT PRIMARY KEY AUTO_INCREMENT, course_no VARCHAR(20) NOT NULL UNIQUE, course_name VARCHAR(50) NOT NULL, credit DECIMAL(3,1) NOT NULL COMMENT 学分, teacher_name VARCHAR(20), course_type TINYINT COMMENT 1必修 2选修 ) ENGINEInnoDB; -- 成绩表学生与课程的多对多关联 CREATE TABLE t_score ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, course_id INT NOT NULL, regular_score DECIMAL(5,1) COMMENT 平时分, exam_score DECIMAL(5,1) COMMENT 期末分, final_score DECIMAL(5,1) COMMENT 总评 平时*0.3 期末*0.7, semester VARCHAR(20), UNIQUE KEY uk_student_course(student_id, course_id), CONSTRAINT fk_score_student FOREIGN KEY (student_id) REFERENCES t_student(id), CONSTRAINT fk_score_course FOREIGN KEY (course_id) REFERENCES t_course(id) ) ENGINEInnoDB; -- 初始管理员账号密码在 Java 代码中用 MD5 加密后写入 INSERT INTO t_user (username, password, user_type, real_name) VALUES (admin, MD5(admin123), 1, 系统管理员);逻辑和参数说明t_user里的user_type是权限判断的关键后端每次请求都要拿它来决定能不能继续执行。t_student.user_id外键把登录账号和学生档案连接起来学生登录后系统通过这个外键找到他的档案进而查成绩。t_score的UNIQUE KEY uk_student_course就是前面说的防重复约束DECIMAL(5,1)限定了成绩范围最大 999.9既能存 0~100 又能带一位小数。final_score我刻意做了注释它是regular_score * 0.3 exam_score * 0.7的冗余字段冗余的目的是查询时直接用、不用每行临时计算。这类“可控冗余”在数据库设计答辩里是加分表述。初始数据除了管理员账号还建议插入 2 个学生账号、1 个教师账号、3 门课和几条成绩。老师打开系统看到有演示数据比自己现录要友好得多这也是“能演示”和“演示到一半没数据”的差别。3.3 统计与算绩点平均分、及格率和 GPA 的三条常用 SQL成绩管理系统的价值一半在统计上。MySQL 的常用命令里AVG、COUNT、CASE WHEN三件套就能把成绩分析做出来。第一段是每门课的平均分和及格率SELECT c.course_name, COUNT(s.id) AS total_count, AVG(s.final_score) AS avg_score, SUM(CASE WHEN s.final_score 60 THEN 1 ELSE 0 END) / COUNT(s.id) AS pass_rate FROM t_course c LEFT JOIN t_score s ON c.id s.course_id GROUP BY c.id, c.course_name;这段 SQL 里LEFT JOIN是为了让没有成绩的课程也能显示出来否则 0 人选的课会从统计里消失。SUM(CASE WHEN ...)在 MySQL 里等效于COUNT(IF(...))但CASE WHEN的可读性更好老师看代码能一眼看懂及格率怎么算的。第二段是单个学生的学期 GPA。GPA 换算规则每个学校不一样常见做法是分数除 10 减 560 分为 1.0100 分为 5.0也可以用 CASE 分段类似“顶底信号”指标的分段逻辑——按区间映射权重SELECT st.name, ROUND(SUM(s.final_score * c.credit) / NULLIF(SUM(c.credit), 0), 2) AS weighted_avg, ROUND(SUM(GPA_POINT(s.final_score) * c.credit) / NULLIF(SUM(c.credit), 0), 2) AS gpa FROM t_score s JOIN t_student st ON s.student_id st.id JOIN t_course c ON s.course_id c.id WHERE s.semester 2024-2025-1 AND st.id ? GROUP BY st.id, st.name;NULLIF(SUM(c.credit), 0)是防 SQL 报除零错误的写法当总学分为 0 时返回 NULL整个表达式的值也变成 NULL不会报Division by 0。这两条 SQL 可以直接放进 DAO 层做报表查询也可以在 Navicat 里先跑通验证数据再去配对 Java 代码。数据库脚本里的内容足够扎实“数据库实现”这一栏的分数基本就稳了。4. 代码实现登录、权限拦截和成绩的增删改查是全部核心4.1 登录与会话Session 里放什么Filter 拦哪些路径JavaWeb 的权限控制有两个环节登录成功后把用户信息放 Session之后每个受限请求由 Filter 检查 Session。我见过很多课设只做“登录时判断一下用户名密码”然后就默认用户登录了——这等于没做权限因为直接访问teacher/score_list.jsp一样能打开页面。登录的 Servlet 核心逻辑用代码写出来是这样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); // 用 MD5 加密后去数据库比对避免明文密码落库 User user userDao.findByUsernameAndPassword( username, DigestUtils.md5Hex(password).toUpperCase()); if (user null) { req.setAttribute(error, 用户名或密码错误); req.getRequestDispatcher(/login.jsp).forward(req, resp); return; } // 只放关键信息进 Session不要把整个密码也塞进去 req.getSession().setAttribute(loginUser, user); req.getSession().setAttribute(userType, user.getUserType()); String path switch (user.getUserType()) { case 1 - /admin/index.jsp; case 2 - /teacher/index.jsp; default - /student/index.jsp; }; resp.sendRedirect(req.getContextPath() path); } }逻辑说明MD5加密这块我用的是 Spring 自带的DigestUtils如果你不想额外引依赖JDK 自带的MessageDigest也能做。密码落库存的是密文老师提问“为什么密码不存明文”时能答出“防止数据库泄露后密码直接暴露”就够了。switch表达式来自 JDK 14如果你还在 JDK 8就改回if/else别为了秀语法让工程编译不过。参数说明req.setCharacterEncoding(UTF-8)必须放在读取参数之前否则 POST 提交的中文用户名会乱码。sendRedirect用的是重定向而不是forward因为登录成功后不能让浏览器停留在 POST 请求的地址上否则刷新页面会重复提交。Filter 部分全工程用一个AuthFilter用WebFilter(/*)拦截所有请求然后在白名单外的路径上做检查WebFilter(/*) public class AuthFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpReq (HttpServletRequest) req; HttpServletResponse httpResp (HttpServletResponse) resp; HttpSession session httpReq.getSession(false); User user session null ? null : (User) session.getAttribute(loginUser); String uri httpReq.getRequestURI(); // 白名单登录页、静态资源和登录接口不拦截 boolean needAuth !uri.endsWith(/login) !uri.endsWith(.css) !uri.endsWith(.js) !uri.endsWith(.png) !uri.contains(/login.jsp); if (needAuth user null) { httpResp.sendRedirect(httpReq.getContextPath() /login.jsp); return; } // 二次校验学生访问教师路径直接拦下 if (user ! null uri.contains(/teacher/) user.getUserType() ! 2) { httpResp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } chain.doFilter(req, resp); } }这段里有三个容易被忽略的细节。第一getSession(false)里传了false意思是拿不到会话就返回 null而不是自动创建一个新会话避免“未登录用户每次请求都产生一个 Session”的浪费。第二白名单判断用endsWith或contains做字符串匹配在课设规模下简单直接不用上 Shiro 这类安全框架但如果你的项目要求高一点也会被问“能不能用注解式更细粒度控制”这时可以提一句WebFilter 路径枚举。第三教师接口的判断条件是userType ! 2也就是学生和管理员都不允许访问教师专属路径返回 403。这三层合起来权限控制就完整了。4.2 成绩录入与修改PreparedStatement 事务避免 SQL 注入和半截更新教师录入成绩是最容易出事故的功能一门课几十个学生录入到一半数据库连接断了或者代码抛异常可能第一批学生写进去了、第二批没写进去。这就是事务要解决的问题——要么全部成功要么全部回滚。Service 层的事务控制代码public void saveScoreBatch(ListScore scoreList) throws SQLException { Connection conn DBUtil.getConnection(); try { conn.setAutoCommit(false); // 关闭自动提交开启事务 for (Score score : scoreList) { scoreDao.insertOrUpdate(conn, score); } conn.commit(); // 全部成功才提交 } catch (SQLException e) { conn.rollback(); // 任何一条失败整批回滚 throw new RuntimeException(成绩保存失败已回滚, e); } finally { conn.setAutoCommit(true); // 恢复自动提交归还连接前必须做 conn.close(); } }这里我把事务放在 Service 层而不是 DAO 层是本系统的关键设计点一个业务操作涉及多条 SQL 时事务必须横跨它们。setAutoCommit(true)在finally里恢复目的是这个Connection归还到连接池后状态是正常的否则下次从池子里拿到的连接还带着 false代码会静默出错。DAO 层的 SQL 用PreparedStatement占位符不拼字符串public void insertOrUpdate(Connection conn, Score score) throws SQLException { String sql INSERT INTO t_score (student_id, course_id, regular_score, exam_score, final_score, semester) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE regular_score VALUES(regular_score), exam_score VALUES(exam_score), final_score VALUES(final_score); try (PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, score.getStudentId()); ps.setInt(2, score.getCourseId()); ps.setDouble(3, score.getRegularScore()); ps.setDouble(4, score.getExamScore()); ps.setDouble(5, score.getRegularScore() * 0.3 score.getExamScore() * 0.7); ps.setString(6, score.getSemester()); ps.executeUpdate(); } }ON DUPLICATE KEY UPDATE是这条 SQL 的关键设计——它配合t_score表上的唯一索引uk_student_course使用。第一次录成绩是INSERT同一门课再次录成绩比如第二天改了某个学生分数自动变成UPDATE。这样做的好处是代码里不用先查一遍记录是否存在再决定 insert 还是 update一个 SQL 搞定也躲开了并发下“先查后写”的竞态。这就是为什么第 3 章我坚持要加唯一索引它不只是一个防重复的工具还是这个 upsert 写法的地基。final_score的计算放在 DAO 层不太合适严格讲它属于领域规则应该放 Service 层算好再传进来。课设规模这么写问题不大但如果你想让代码经得起推敲把 0.3/0.7 的比例提到一个常量或者配置项里并命名为REGULAR_RATE答问时会顺畅很多。4.3 分页查询成绩列表的 SQL 和页面分页条怎么配合“学生查成绩”和“老师看成绩单”的列表超过 30 条之后就很难一口气看完分页是管理系统必备的能力也是 JavaWeb 课设的常见加分点。分页查询的 SQL 用LIMITpublic ListScore findPage(int offset, int pageSize, String keyword) { String sql SELECT s.id, st.student_no, st.name AS student_name, c.course_name, s.regular_score, s.exam_score, s.final_score, s.semester FROM t_score s JOIN t_student st ON s.student_id st.id JOIN t_course c ON s.course_id c.id WHERE (? IS NULL OR st.name LIKE CONCAT(%, ?, %)) ORDER BY s.id DESC LIMIT ?, ?; // offset 从 0 开始pageSize 是每页条数 }LIMIT的两个参数别写反第一个是跳过多少条第二个是取多少条。前端传页码pageNo后端计算offset (pageNo - 1) * pageSize当前页 1、每页 10 条offset 就是 0第二页就是 10。WHERE (? IS NULL OR ...)这段用于可选的关键字查询——当keyword参数为 null 时条件恒真不影响查询结果不为 null 时按学生姓名模糊匹配。这种把“可选条件”写进一条 SQL 的方式能省掉写两套 SQL 的麻烦。JSP 页面里分页条长这样页码用脚本循环生成点击后重新带参数请求列表 Servlet% int currentPage (Integer) request.getAttribute(currentPage); % % int totalPages (Integer) request.getAttribute(totalPages); % nav a href% request.getContextPath() %/score/list?pageNo% currentPage - 1 %上一页/a span第 % currentPage % / % totalPages % 页/span a href% request.getContextPath() %/score/list?pageNo% currentPage 1 %下一页/a /nav第一页时上一页链接应该禁用最后一页时下一页链接应该置灰否则用户点到头会得到空列表。这里我故意简化了实际上要拿到totalPagesDAO 里还要再执行一条SELECT COUNT(*) FROM t_score ...来计算总量再除以 pageSize 向上取整。分页做出来后再顺手把导出 Excel 的功能接在同一个查询结果集上功能就完整了。5. 避坑排查IDEA 跑 JavaWeb 项目最常见的 5 次翻车5.1 现象项目启动后 404 或 ClassNotFoundException现象Tomcat 能正常启动但访问http://localhost:8080/score_system/login.jsp时要么 404要么页面打开后报java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver。原因两类问题。404 是没有把项目部署到 Tomcat 的 webapps 上——IDEA 里 Run Configuration 的 Deployment 选项卡没添加 Artifact或者添加的是不带/lib依赖的 Artifact。ClassNotFound 是依赖 jar 没进WEB-INF/lib目录编译期 IDEA 靠 Classpath 能找到 jar但运行时 Tomcat 从WEB-INF/lib加载类两边不一致。解决先Project Structure → Artifacts选中.war exploded把druid.jar、mysql-connector-java.jar右键Put into /WEB-INF/lib。再看 Run Configuration 的 Deployment 里有没有score_system:war exploded没有就点加号补上。全改完后Rebuild Project不要用增量编译因为 Artifact 的 lib 目录有时不会自动刷新。5.2 现象页面中文乱码库里也乱码现象系统登录进去后学生名字显示成å¼ ä¸或者往 MySQL 里写中文后表里是???。原因三层编码不一致——JSP 的pageEncoding、请求的characterEncoding、MySQL 的连接参数和表字符集只要有一层不是 UTF-8数据就会在这一层被错误解码。最典型的是db.properties的连接 URL 没带characterEncodingUTF-8或者 JSP 页面 是 GBK 而 Servlet 响应是 UTF-8。解决统一为 UTF-8 一条链路。第一步db.properties的 URL 加上useUnicodetruecharacterEncodingUTF-8。第二步建表脚本里声明DEFAULT CHARACTER SET utf8mb4。第三步在 Filter 里面对每个请求和响应统一设置编码httpReq.setCharacterEncoding(UTF-8); httpResp.setContentType(text/html;charsetUTF-8);上面这段不要放在“只有登录才走”的接口里而要放在AuthFilter.doFilter的chain.doFilter之前让所有请求一进来就被清洗成 UTF-8。设置完成后把库里的乱码数据删掉重新录一遍不要想着“将就一下”乱码数据会连锁污染后续所有查询结果。5.3 现象SQL 文件导入报错外键约束过不去现象在 Navicat 或 IDEA Database 里运行score_system.sql报Cannot add foreign key constraint或者导入到一半卡住。原因脚本里的建表顺序错了。MySQL 在建表时遇到外键会先确认被引用的表存在。如果你把t_score写在t_student前面此时父表尚未创建外键约束加不上。另一个原因是两张表的ENGINE不一致比如父表是 MyISAM、子表是 InnoDB外键无法跨引擎建立。解决按依赖顺序执行t_user → t_student → t_course → t_score所有表统一用ENGINEInnoDB。实际开发里还有人把 SQL 文件整个导入时遇到中间某条数据重复导致中断先删掉前面部分数据或者加SET FOREIGN_KEY_CHECKS0;再导入导入完成后再执行SET FOREIGN_KEY_CHECKS1;。这个开关适合调试用正式提交的脚本里不推荐写它会让导入时绕过所有外键校验容易留下脏数据。5.4 现象数据库连不上报时区或 SSL 错误现象Tomcat 启动日志报The server time zone value й׼ʱ is unrecognized或者SSL connection error或者Public Key Retrieval is not allowed。原因MySQL 8.0 换了认证插件默认值caching_sha2_password同时连接器默认开启 SSL 校验和时区校验。MySQL 5.7 时代能跑通的连接串直接套到 MySQL 8.0 上就会遇到连锁错误。解决连接串补三个参数urljdbc:mysql://localhost:3306/score_system?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue同时确认mysql-connector-java版本与 MySQL 服务端匹配。MySQL 8.0 配8.0.xx驱动Driver类名是com.mysql.cj.jdbc.DriverMySQL 5.7 配5.1.49驱动类名是com.mysql.jdbc.Driver。这两个类名很多人混着抄驱动版本与类名不匹配时启动就会报ClassNotFound。5.5 现象删除学生记录时被外键拦住现象在管理员界面删除一个学生后台直接抛Cannot delete or update a parent row: a foreign key constraint fails页面弹一个 500什么提示都没有。原因这不是 bug是外键的正常保护——t_student里有被t_score引用的记录直接删学生成绩表里对应成绩就变成没有归属人的孤儿数据。不少人对这个错误的第一反应是“把外键删掉”这属于修掉了报错、丢掉了设计答辩老师一问“成绩表里的孤儿数据怎么办”就露馅。解决按业务规则选择策略。成绩系统里“学生退学或毕业”通常不该物理删除他的历史成绩所以更合理的做法是逻辑删除——在t_student加一个status字段删除操作只做UPDATE t_student SET status0 WHERE id?查询列表时默认过滤status1。如果确实要物理删除则在一个事务里先删成绩再删学生DELETE FROM t_score WHERE student_id?; DELETE FROM t_student WHERE id?;并把这两条放进 Service 层事务。这才是对“外键约束会不会影响删除”的标准回答。6. 验证与加分怎样从“能跑”到“值得给高分”系统写得差不多时先不要急着写文档或录演示视频按下面的验证清单完整跑一遍每一关都是评分老师实际会操作的动作操作预期结果验证要点管理员登录 admin/admin123跳转到管理员首页密码是否加密存储未登录直接访问/student/index.jsp被 Filter 重定向到 login.jsp权限拦截是全局的学生账号访问/teacher/score_list返回 403角色权限不是摆设教师录入两门课成绩列表出现新数据刷新无重复唯一索引 upsert 生效学生查询成绩单按学期展示平均分、绩点统计 SQL 在真实数据上正确删除一个已有成绩的学生提示不可删除或逻辑删除成功外键策略明确验证通过后的加分项优先做三个。第一成绩列表导出 Excel用 PoI 把分页查询的 List 渲染成表格老师想拿你的数据做分析时这个功能最实用。第二批量导入成绩Excel 上传后用PreparedStatement批量写入配合事务保证“要么全部导成要么全部不导”。第三成绩发布功能教师录入后先存草稿状态确认无误再点击发布发布后学生才可见这个“审批流转”的语义是管理系统里真正有价值的设计。最后一个我个人的血泪经验做课设时别把“代码写完”当天真你会花三分之一时间在环境搭建和排错上第一次跑通 Tomcat 到连上 MySQL 之间那块黑匣子谁都绕不过去。所以把数据库脚本和连接配置写干净比多写几十行功能代码更能保平安。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号