ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

JavaWeb体育竞赛管理系统:从报名到成绩公示的完整复现指南

2026/10/4 17:19:14 拓冰建站 浏览量
JavaWeb体育竞赛管理系统:从报名到成绩公示的完整复现指南 简介基于JavaWeb的体育竞赛管理系统毕业设计资料包面向计算机相关专业毕业生及JavaWeb初学者用于解决体育赛事组织中的报名、成绩与用户管理信息化问题。系统完整覆盖运动员报名与成绩管理、管理员用户与参赛管理、裁判员成绩与申诉处理三大功能模块基于JDK1.8、MySQL5.7与JSP/Servlet开发可帮助读者掌握经典JavaWeb分层项目结构。资源共2662个文件、29.37MB包含JSP动态页面、Java源码与Class编译文件以及HTML/CSS/JS前端资源、Jar依赖库、SQL数据库脚本和IntelliJ IDEA配置信息导入后便于直接运行和二次开发。已有903人学习下载适合作为毕业设计参考、课程设计模板或竞赛管理项目起步代码。资料内还附带PDF/MD说明文档、静态图片素材与工程目录结构可辅助理解设计思路、部署流程与数据库表关系。1. 一套JavaWeb体育竞赛管理系统从报名到成绩公示值得复现的完整案例体育竞赛报名还在用Excel表统计、成绩靠人工核算的项目组不在少数尤其校运会、区级赛事这类规模不大但项目繁杂的比赛一个报名审核翻来覆去能搞到赛前夜。这套基于JavaWeb的体育竞赛管理系统解决的正是这条链路上最磨人的三个环节运动员在线报名与资格校验、管理员对项目和用户的统一管控、裁判员录入成绩后自动排名并公示。它用的是JSP Servlet MySQL 5.7这套经典JavaWeb组合跑在JDK1.8上用IntelliJ IDEA就能直接部署。适合两类人一是做毕设需要完整案例的学生二是想搞清JSP页面、Servlet控制层和DaoImpl数据层如何串成一条真业务线的JavaWeb初学者。下面按我实际拆解和复现的顺序来写。2. 技术骨架JDK1.8 JSP MySQL 5.7 为什么还是毕设主力2.1 技术选型这套组合的取舍逻辑先说JDK1.8。它已经是很成熟的版本市面上绝大多数JavaWeb教材、培训机构笔记包括你搜到的黑马JavaWeb那套资料里的数据库脚本和代码风格都是基于这个版本写的。用JDK1.8意味着你复制粘贴别人的代码片段时不用处理var关键字、新日期API带来的语法差异编译报错概率低很多。MySQL选5.7而不是8.0理由有两个一是5.7是当前存量项目里占比最高的版本老环境的备份导入导出不会出幺蛾子二是8.0默认的认证插件是caching_sha2_password老驱动连不上的问题一堆5.7的mysql_native_password省心。前端用JSP是这套系统的核心特征。JSP允许在HTML里嵌Java代码服务端渲染出来的页面直接响应给浏览器不需要额外的前端构建工具。以这个毕设的规模来说JSP Servlet就能把登录、报名、录分、排名公示全部做完一个Tomcat就能跑起来。有人会问为什么不直接上Spring Boot这个问题我在答辩被评委问过。答案是毕设和真实项目不同评委想看到你理解请求是怎么到达控制器的、控制器又是怎么调DAO拿数据的JSP Servlet把这个过程完全摊开没有任何黑匣子。Spring Boot里一个Controller注解就带过去的东西反而失去了展示价值。2.2 从压缩包文件反推架构Class文件名透露的信息拿到压缩包后我没急着跑先把里面那一串.class文件理了一遍。文件名虽然重复但信息量不小StudentServlet.class运动员模块的控制器入口对应报名、查成绩等请求。DirectorServlet.class裁判员模块控制器管理成绩录入和申诉处理。DirectorDaoImpl.class裁判模块的DAO实现类说明数据访问层被拆成了接口和实现这是标准三层架构的写法。对照这个命名规律系统应该是ControllerServlet→ Service → DaoImpl → MySQL 的四层结构。JSP页面在web目录下负责展示Servlet负责接收请求和转发DaoImpl直接操作数据库。值得注意的是压缩包里混进了一个controller.ashx文件这个是ASP.NET的东西和JavaWeb没有任何关系属于打包时混入的杂文件直接删掉就好别被它干扰判断。2.3 IDEA部署配置Artifacts和Tomcat的关联IDEA里跑JavaWeb项目最容易卡住的就是部署配置。核心是把项目打包成war exploded展开的war包丢给Tomcat。步骤是打开File → Project Structure在Artifacts里新增Web Application: Exploded选择当前项目然后在Run Configurations里新建Tomcat Server把刚才的Artifact加到Deployment列表。# Tomcat 部署配置的关键项 Deployment → 选择 sports_competition:war exploded Application context → /sports 访问路径 → http://localhost:8080/sports/login.jspApplication context决定了你访问项目的根路径。这里填/sports是为了避免和Tomcat自带的/冲突也方便后面拼接资源路径。如果你在JSP里用了绝对路径的CSS或JS引用context填错了页面会全部裸奔。这个配置是IDEA运行JavaWeb项目的标准动作几乎所有资料里都会强调但我见过不少同学Reimport项目后Artifact丢失、或者改了代码点运行还是旧页面基本都是这一步没配对。3. 数据库设计报名审核与自动排名的表结构怎么落3.1 核心表结构用户、运动员、赛事、报名、成绩五张表系统涉及三种角色管理员、裁判员、运动员数据库至少要承载这几件事登录认证、运动员基本资料、赛事定义、报名记录、比赛成绩。我按最常见的做法拆成五张表下面是建库脚本的关键部分CREATE DATABASE IF NOT EXISTS sports_competition DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE sports_competition; CREATE TABLE sys_user ( user_id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, role VARCHAR(20) NOT NULL COMMENT admin/director/athlete, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE athlete ( athlete_id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, real_name VARCHAR(50) NOT NULL, gender CHAR(2), phone VARCHAR(20), FOREIGN KEY (user_id) REFERENCES sys_user(user_id) ); CREATE TABLE event ( event_id INT PRIMARY KEY AUTO_INCREMENT, event_name VARCHAR(100) NOT NULL, event_date DATETIME, location VARCHAR(100), score_rule VARCHAR(10) DEFAULT desc COMMENT asc:越小越好, desc:越大越好 ); CREATE TABLE registration ( reg_id INT PRIMARY KEY AUTO_INCREMENT, athlete_id INT NOT NULL, event_id INT NOT NULL, status VARCHAR(20) DEFAULT pending, audit_remark VARCHAR(255), FOREIGN KEY (athlete_id) REFERENCES athlete(athlete_id), FOREIGN KEY (event_id) REFERENCES event(event_id) ); CREATE TABLE score ( score_id INT PRIMARY KEY AUTO_INCREMENT, registration_id INT NOT NULL, score_value DECIMAL(6,2) NOT NULL, rank_no INT, FOREIGN KEY (registration_id) REFERENCES registration(reg_id) );建表顺序有讲究sys_user和event没有外键依赖可以先建athlete依赖sys_userregistration依赖athlete和eventscore依赖registration。按依赖顺序执行才不会报外键错误。表名我用了sys_user而不是user因为user在某些MySQL版本里是保留字直接用会报语法错误这是个容易踩的小坑。score_rule这个字段值得单独说一下。它不是必选项但加了之后裁判员模块录入成绩时就能根据项目类型动态决定排名方向100米短跑用时越短越好asc铅球跳远则是成绩越大越好desc。如果没有这个字段排名逻辑写死在Java代码里换项目类型就得改代码重新编译很麻烦。3.2 成绩排名MySQL 5.7没有窗口函数的处理方式这块是我拆这套系统时觉得最有价值的地方。如果你用MySQL 8.0一个ROW_NUMBER() OVER (ORDER BY score_value DESC)就把名次算完了。但5.7不支持窗口函数只能用两种替代方案一是ORDER BY后取结果集在Java的Service层里循环赋值二是用用户变量模拟。-- 方案一只排序列名次计算交给Java层 SELECT s.score_id, a.real_name, e.event_name, s.score_value FROM score s JOIN registration r ON s.registration_id r.reg_id JOIN athlete a ON r.athlete_id a.athlete_id JOIN event e ON r.event_id e.event_id WHERE e.event_id ? AND e.score_rule desc ORDER BY s.score_value DESC; -- 方案二MySQL 5.7 用户变量模拟行号 SET rank_no : 0; SELECT rank_no : rank_no 1 AS rank_no, real_name, score_value FROM (SELECT a.real_name, s.score_value FROM score s JOIN registration r ON s.registration_id r.reg_id JOIN athlete a ON r.athlete_id a.athlete_id WHERE r.event_id ? ORDER BY s.score_value DESC) t;两个方案的差别在于方案一拿到的是无序排名列表需要在Java代码里for循环维护一个计数器遇到相同成绩还要决定是否并列方案二直接用MySQL变量生成rank_noSQL执行完名次就是现成的。我一般推荐方案二SQL本身就能呈现排名逻辑答辩时讲起来也更有说服力。注意变量的初始化语句SET rank_no : 0不能省略否则每次查询行号从上次的遗留值继续累加这是血泪经验。3.3 中文乱码连接参数和建库字符集体育竞赛系统里运动员姓名、赛事名称全是中文乱码是复现率最高的翻车点。问题通常不在JDBC驱动而在三处没统一数据库字符集、连接URL参数、JSP页面编码。数据库这边建库时已经指定了utf8mb4utf8mb4比utf8多支持emoji和生僻字现在新项目基本都用它。连接URL这处比较容易漏String url jdbc:mysql://localhost:3306/sports_competition ?useUnicodetruecharacterEncodingUTF-8 useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/Shanghai;useUnicodetruecharacterEncodingUTF-8这两个参数是标配少了任何一个都不能保证中文正常读写。serverTimezone在MySQL 5.7上不加有时也能跑但加上可以避免驱动解析时区时的警告和日期偏差。JSP页面这边每个页面的pageEncoding和contentType都要显式声明UTF-8不要依赖IDE默认设置。4. 三大角色链路实现运动员报名、管理员审核、裁判录分4.1 运动员模块报名请求如何走完一整套逻辑运动员进入系统后能看到已开放报名的赛事列表选择赛事后填写参赛信息提交。这个动作在Servlet里要完成三件事校验登录状态、检查是否重复报名、插入报名记录。下面是RegisterServlet的核心逻辑注释里标了每一步对应的数据库操作WebServlet(/athlete/register) public class RegisterServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); HttpSession session req.getSession(false); if (session null || session.getAttribute(userId) null) { resp.sendRedirect(req.getContextPath() /login.jsp); return; } int userId (Integer) session.getAttribute(userId); int eventId Integer.parseInt(req.getParameter(eventId)); // 第一步查 athlete 表拿到运动员ID // 第二步查 registration 表确认该运动员没有报名同一赛事 // 第三步插入 registrationstatus 默认 pending // 第四步重定向到报名列表页面 } }这段代码演示的是最基础的Servlet用法从session取当前用户、从请求参数取目标赛事、按顺序完成查重和插入。注意session里存的是sys_user的user_id而registration关联的是athlete表的主键中间需要一个SELECT athlete_id FROM athlete WHERE user_id ?的转换。这个细节很典型我见过不少初学的人直接把userId当athleteId用导致外键约束报错。运动员模块的资格自动审核在系统里并不是一个复杂的人工审批流程而是程序层面的查重和合法性判断同一赛事只能报名一次、赛事状态必须是开放中。真正的人工审核落在管理员模块这样职责拆分符合输入描述里的分工。4.2 管理员模块审核报名和管理赛事资源的实现路径管理员的界面和普通运动员不在同一套导航里常见做法是登录时根据role字段跳转不同首页。管理员的主要操作是两件事一是对registration表里pending状态的记录逐条审核通过或驳回二是维护event表的赛事信息。WebServlet(/admin/audit) public class AuditServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int regId Integer.parseInt(req.getParameter(regId)); String action req.getParameter(action); // approve 或 reject String newStatus approve.equals(action) ? approved : rejected; String remark req.getParameter(auditRemark); // 更新 registration 表set status?, audit_remark? where reg_id? // 如果是 approve还需要校验该赛事当前报名人数是否已达上限 // 完成后重定向回待审核列表 } }审核接口虽然代码量不大但在参数设计上有个容易被忽略的点executor_id审核人这个字段。如果表结构里没有记录谁在什么时间审核的这条记录后续出问题没法追溯。我一般会在registration表里再加audit_user_id和audit_time两个字段算是管理员模块的小升级毕设答辩时提这个理由很容易加分。管理员维护赛事这块和前端的联动主要体现在一个地方新建赛事时把score_rule字段一并保存。这个字段就是第3章建表脚本里那个asc/desc裁判员录分时依赖它来决定排名方向。4.3 裁判员模块录分后如何触发自动排名裁判员模块是整个系统里业务最重的一块。裁判员进入系统后先看到自己负责的赛事列表这个对应关系一般在event表里加一个director_id字段点进某场赛事后系统列出所有报名状态为approved的运动员裁判员逐个录入成绩。public void updateScoreAndRank(int regId, double scoreValue, String rule) { // 第一步更新 score 表写入成绩 // UPDATE score SET score_value ? WHERE registration_id ? // 第二步查出该赛事所有成绩按 rule 排序 // ruledesc 走 ORDER BY score_value DESC // ruleasc 走 ORDER BY score_value ASC // 第三步遍历结果集从1开始给 rank_no 赋值 // 如果有并列成绩常见处理是保留空位比如 1, 1, 3 // 第四步批量 UPDATE score SET rank_no ? WHERE score_id ? }这里的排名计算虽然在数据量小的时候用方案一的Java循环就够了但我建议用第3章方案二的变量法在SQL里直接生成排名。裁判员录分这个动作对实时性要求很高比赛现场裁判录完一个成绩公示页立刻要有反应。如果排名在Java层循环算录分接口的事务边界要包住所有UPDATE一旦中间有一条失败成绩写入了但名次没更新页面就会出现有成绩无名次的尴尬状态。我处理这个问题的习惯是录分接口和排名计算做成一个事务要么都成功要么都回滚。成绩公示页的JSP就简单了从score表按rank_no排序查询渲染成一个带序号的表格。运动员端看到的成绩和自己的排名其实读的是同一张score表不存在两套数据不一致的问题这是这套系统设计上最干净的地方。5. 避坑指南IDEA部署JavaWeb项目的五个翻车点5.1 高频踩坑记录现象、原因、解决翻车点一Tomcat启动后访问页面报404。现象IDEA里Tomcat控制台显示启动成功但浏览器打开localhost:8080出现404页面。 原因最常见的是Artifact没有部署到Tomcat或者Application context配置的路径和实际访问路径不一致。很多新手只配置了项目结构忘了在Run Configuration的Deployment里添加war包。 解决打开Run → Edit Configurations切到Deployment页签点号添加当前项目的war exploded然后检查Application context。改完重启Tomcat不要点Rerun那样会保留旧部署。翻车点二改完代码重新运行页面还是老样子。现象JSP改了表格列名刷新浏览器死活不变Servlet加了打印日志控制台看不到。 原因IDEA默认构建方式是Build on Save但如果你改的是web.xml、JSP或配置文件Tomcat不一定会触发热部署。更隐蔽的是Tomcat的conf目录里部署描述符指向的是out目录而out目录没有被清理。 解决养成一个固定动作Build → Rebuild Project然后重启Tomcat。从那以后我只要改了非Java文件就强制走一遍Rebuild再加重启不再把时间浪费在玄学热部署上。翻车点三数据库连接报Public Key Retrieval is not allowed。现象JDBC连接MySQL时抛出这个异常程序完全起不来。 原因MySQL连接器版本较新而MySQL 5.7的认证方式默认使用mysql_native_password两者握手时驱动需要获取服务器公钥但URL里没放开限制。这个问题在MySQL 8.0上更常见5.7偶尔也会触发取决于驱动版本。 解决在JDBC URL末尾追加allowPublicKeyRetrievaltrueuseSSLfalse。这是5.7环境下最省心的两个参数保证连接过程不做SSL加密校验也不限制公钥获取。翻车点四导入SQL脚本时外键关联失败。现象source执行建表脚本创建registration或score表时报外键约束错误。 原因建表顺序不对。sys_user还没建完就开始建athlete或者athlete表引擎不是InnoDB。顺带说一句如果MySQL 5.7的默认引擎被改成了MyISAM外键约束是虚设的约束不生效但SQL也不报错这种问题更可怕。 解决严格按依赖顺序执行sys_user和event先建然后athlete再registration最后score。建库脚本里显式加上ENGINEInnoDB DEFAULT CHARSETutf8mb4不依赖服务器默认配置。翻车点五Tomcat端口被占用无法启动。现象启动Tomcat弹窗提示Port 8080 is already in use或者8005端口被占用导致控制台闪现后退出。 原因之前的Tomcat进程没有完全杀掉或者电脑上已经跑了别的服务占用端口。 解决命令行执行netstat -ano | findstr 8080找到PID然后taskkill /F /PID 对应PID强杀。如果频繁遇到多开情况可以在Run Configuration的Tomcat设置里把端口改成8081、8006改端口比杀进程快得多。5.2 源码丢了别慌从class文件反推和兜底手段如果你拿到的压缩包和这次一样只有.class没有.java源码IDEA是没法直接运行的因为class是编译后的字节码不是IDEA能编辑的源文件。但class文件并非完全不可读两个实用手段一是用反编译工具JD-GUI、Luyten都能打开class文件查看逻辑对着逻辑重新手写源码虽然字段名和方法名会变成无意义的a、b、c但结构是看得懂的二是检查项目里是否还有同名不同后缀的资源文件比如jsp和xml一般不会编译掉可以从这些文件反推页面流。我的习惯是拿到任何JavaWeb项目包先打开Project Structure看模块结构确认src目录下有没有源码。只有class的话直接反编译成本太高建议优先找完整版或者把class当作接口参考页面和SQL自己重写。这不丢人毕设项目本来就是以学习和复现为主不是生产系统。6. 验证清单与进阶把一次部署变成可复用的习惯6.1 功能验证用例部署完成后不要直接关机走人按这组用例逐条过一遍能覆盖三大角色的主要链路。我复现这套系统时就用这张表做回归验证每改一次代码就过一遍编号操作步骤预期结果1用运动员账号登录进入赛事列表能看到状态为open的赛事已截止的不可报名2对同一赛事重复提交报名第二次提交被拦截提示已报名3管理员进入审核列表通过一条报名该运动员状态变为approved出现在裁判员名单中4裁判员录入该运动员成绩查看排名排名自动计算成绩公示页顺序正确5运动员端查看成绩能看到自己的分数和名次和裁判端一致6用裁判员账号访问管理员审核接口被重定向回登录页角色权限生效第6条容易忽略因为很多毕设demo只限制了页面入口没限制Servlet接口级权限。如果你要做得更严谨可以在每个Servlet的doGet/doPost开头加一个WebFilter拦截校验session里的role是否匹配。6.2 一个加分技巧成绩导出为CSV答辩现场老师大概率会问成绩数据能不能导出。不想引入POI依赖的话一个最简单的方案是把响应ContentType改成CSV格式resp.setContentType(text/csv;charsetUTF-8); resp.setHeader(Content-Disposition, attachment;filenamescores.csv); PrintWriter out resp.getWriter(); out.println(排名,姓名,赛事,成绩); out.println(1,张三,100米,12.30); out.flush();浏览器会直接下载CSV文件Excel能正常打开。这个技巧不增加任何外部依赖代码量只有几行但对系统可用性的展现效果很好数据留存和价值一下就体现出来了。这套系统我前前后后部署过三台不同的电脑每次环境细节都有差异有的MySQL装的是5.7.42有的是5.7.18有的IDEA是社区版新建Artifact的入口位置都不同。从那以后我每次复现JavaWeb项目都强制走一遍固定流程先建库导脚本再核对JDBC连接四要素然后配置Artifact最后按验证用例跑完整条报名录分链路全部通过才收工。这套流程救过我很多次希望帮到你。本文还有配套的精品资源点击获取