ARTICLE DETAIL

资讯详情

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

Java田径运动会管理系统实战:从数据库设计到排名算法部署

Java田径运动会管理系统实战:从数据库设计到排名算法部署 简介这套Java田径运动会管理系统是一份面向课程设计或项目实战的完整资源能解决运动会中运动员报名、赛事编排、成绩录入与排名发布等环节的信息化管理问题。压缩包共81个文件涵盖25个Java源文件、48个class编译文件、项目jar包、MySQL驱动、数据库脚本、数据库课设报告和说明文档整体仅2.04MB目录划分明确。资源重点展示了Java Swing图形界面与JDBC数据库操作相结合的开发方式配套课设报告详细说明了系统架构、功能模块和实现流程结合源码与数据库脚本可快速搭建运行环境并初始化数据。对于已掌握Java基础并希望提升信息系统开发能力的读者这是一份可直接参考的课程设计模板也适合作为田径运动会管理系统二次开发的基础。目前已有2167人学习下载实用性强。1. java田径运动会管理系统把课程设计最常点的题做成能跑通的完整闭环java田径运动会管理系统是Java课程设计题目里出镜率最高的题型之一。如果你正在找java课程设计案例源码多半第一眼就会相中它表面是管理系统实际上把增删改查全部包圆还额外塞了成绩排名、赛程校验、登录权限这些“算活”。真正动手做你会发现它远不止给运动员建个档案那么简单径赛按时间升序排田赛按距离/高度降序排同一个项目可能跑预赛和决赛两轮要取最好成绩报名时还得拦住同一选手的时间冲突。这些细节恰恰是java面试题里排序、精度、事务一致性最现实的落点比死背八股文有用得多。这套资源是一份可运行的Java信息系统覆盖建库、登录权限、成绩管理、排名输出到部署启动的完整闭环。适合两类人做运动会课设和毕设的本科生以及准备Java开发面试、想找一个能讲清业务链路的实战项目做背书的人。源码直接拿库建好就能跑后面的章节会把参数和坑位都铺开。2. 技术栈与数据库设计Spring Boot MyBatis MySQL 的六张核心表2.1 为什么是这套组合选型围绕“能跑通、能讲清、能复现”三个目标这套资源基于Spring Boot 2.x MyBatis MySQL 5.7/8.0 Thymeleaf。选型理由不是“流行”而是它最贴合课程设计和面试场景。Spring Boot用Java配置代替了SSH时代一堆XML启动就是java -jar一个命令的事不用在Tomcat里手工部署war包Thymeleaf做服务端渲染前端页面和后端接口放同一个工程打开就能跑比前后端分离少搭一套Node和跨域配置对新手友好答辩时也方便顺着Controller一路把链路讲下去。MyBatis保留手写SQL的能力这一点在运动会场景里很关键成绩排名要按径赛、田赛区分升降序报表统计要按代表队聚合这些逻辑写成SQL比用JPA的自动方法直观得多排错时直接把SQL丢进Navicat跑一遍就知道问题出在哪。相比之下JPA虽然省事但碰到复杂的排序和关联查询自动生成的SQL像黑匣子查起来反而费劲。这套组合还有个隐藏价值它正好卡在java基础语法和框架应用之间的衔接带上。面试里问的“怎么保证数据一致性”在这个项目里落地就是成绩录入的Transactional与唯一索引问的“对象深浅拷贝”落地就是多轮成绩汇总时的对象引用陷阱。把这份源码吃透等于把八股文里最常考的几个点用业务场景串了一遍。2.2 六张表怎么设计报名关系表是整条业务链的中枢数据库设计直接决定后面模块写起来顺不顺。这套资源一共六张核心表各自的职责如下。表名作用关键字段备注sys_user管理员和裁判账号id, username, password, role, real_namerole为ADMIN或REFEREEteam参赛代表队id, team_name, coach, phone运动员归属athlete运动员档案id, team_id, name, gender, student_no, birth_datestudent_no唯一event比赛项目id, event_name, event_type, unit_type, start_time, end_time径赛/田赛、计时/测距signup报名关系id, athlete_id, event_id, create_time多对多中间表result比赛成绩id, signup_id, event_id, athlete_id, round_no, score_value, is_validsignup_id挂靠报名记录几个设计点值得说清楚。第一signup表解决运动员与项目之间的多对多关系同时通过unique(athlete_id, event_id)唯一索引挡住重复报名这是从源头卡数据的做法比在Service层判重更可靠。第二score_value用DECIMAL(8,3)而不是float或double因为浮点数在二进制里无法精确表示0.1这种小数径赛100米跑出9.989999999的后果就是排名错位这一条在避坑章还会单独展开。第三event.event_type用TRACK和FIELD两个枚举值区分径赛和田赛unit_type告诉前端这个成绩单位是秒还是米排名方向由这两个字段共同决定而不是写死在代码里。成绩表挂在signup_id上而不是直接挂athlete_id event_id是刻意为之的。这样一轮预赛、一轮决赛各生成一条result记录round_no区分轮次signup_id保证“同一个运动员同一个项目的成绩”始终有唯一归属后面做多轮取最好成绩时按运动员项目分组即可不会串数据。2.3 建库SQL脚本一份能直接执行的初始化代码拿到源码第一件事不是启动项目而是先把库建起来。初始化脚本在src/main/resources/sql/init.sql里核心内容如下。CREATE DATABASE IF NOT EXISTS sports_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; USE sports_db; CREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(64) NOT NULL COMMENT 密码摘要, role VARCHAR(20) NOT NULL DEFAULT REFEREE COMMENT ADMIN/REFEREE, real_name VARCHAR(50) DEFAULT NULL ) ENGINEInnoDB; CREATE TABLE team ( id BIGINT PRIMARY KEY AUTO_INCREMENT, team_name VARCHAR(100) NOT NULL, coach VARCHAR(50) DEFAULT NULL, phone VARCHAR(20) DEFAULT NULL ) ENGINEInnoDB; CREATE TABLE athlete ( id BIGINT PRIMARY KEY AUTO_INCREMENT, team_id BIGINT NOT NULL, name VARCHAR(50) NOT NULL, gender CHAR(1) NOT NULL COMMENT M/F, student_no VARCHAR(30) NOT NULL UNIQUE, birth_date DATE DEFAULT NULL ) ENGINEInnoDB; CREATE TABLE event ( id BIGINT PRIMARY KEY AUTO_INCREMENT, event_name VARCHAR(100) NOT NULL, event_type VARCHAR(10) NOT NULL COMMENT TRACK/FIELD, unit_type VARCHAR(10) NOT NULL COMMENT SECOND/METER/CENTIMETER, start_time DATETIME DEFAULT NULL, end_time DATETIME DEFAULT NULL ) ENGINEInnoDB; CREATE TABLE signup ( id BIGINT PRIMARY KEY AUTO_INCREMENT, athlete_id BIGINT NOT NULL, event_id BIGINT NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_athlete_event (athlete_id, event_id) ) ENGINEInnoDB; CREATE TABLE result ( id BIGINT PRIMARY KEY AUTO_INCREMENT, signup_id BIGINT NOT NULL, event_id BIGINT NOT NULL, athlete_id BIGINT NOT NULL, round_no INT DEFAULT 1 COMMENT 1预赛 2决赛, score_value DECIMAL(8,3) NOT NULL, is_valid TINYINT DEFAULT 1, recorder_id BIGINT DEFAULT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; INSERT INTO sys_user (username, password, role, real_name) VALUES (admin, MD5(admin123), ADMIN, 系统管理员);建库用utf8mb4而不是utf8这是血泪经验utf8在MySQL里最多存3字节遇到生僻字和emoji直接报错或存成问号运动会报名表里出现少数民族姓名带点特殊符号就翻车。utf8mb4才是完整的UTF-8实现。密码字段用MD5(admin123)这种写法是课设常见做法够用但不推荐上生产真实的项目至少要加盐——如果你对安全有要求拿到源码后改成BCrypt即可后面登录校验处换一个PasswordEncoder就行。score_value字段的DECIMAL(8,3)含义要看清总长8位、小数点后3位。径赛100米成绩存成10.250田赛跳远存成7.850铅球存成12.310都能容纳。排序和比较都在Java层用BigDecimal的compareTo来做这一点后面排名代码里会用到先记住结论凡是成绩、金额、比例这类精确小数一律decimal别用float。3. 核心模块实现登录权限、成绩排名与赛程冲突检查3.1 登录与权限一个拦截器区分管理端和裁判端管理系统的权限如果一上来就引Spring Security配置类、过滤器链、密码加密器一套下来课设答辩时反而讲不清。这份源码用拦截器实现够用且直观管理员能维护运动员、项目、报名和成绩裁判只能进入成绩录入页面并提交成绩。Component public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); User loginUser (User) session.getAttribute(loginUser); if (loginUser null) { response.sendRedirect(request.getContextPath() /login); return false; } String role loginUser.getRole(); if (ADMIN.equals(role)) { return true; } // 裁判角色只允许访问成绩相关的路径 String uri request.getRequestURI(); if (uri.contains(/result/)) { return true; } response.sendError(403, 当前账号无权操作); return false; } }Configuration public class WebConfig implements WebMvcConfigurer { private final AuthInterceptor authInterceptor; public WebConfig(AuthInterceptor authInterceptor) { this.authInterceptor authInterceptor; } Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor) .addPathPatterns(/**) .excludePathPatterns(/login, /css/**, /js/**, /error); } }拦截器逻辑里有两个容易被忽略的边界。第一个excludePathPatterns里放行了/error否则Spring Boot的错误页地址也会被拦截403页面本身渲染不出来前端只会看到一个空白页第二个裁判越权时返回403而不是重定向到登录页如果重定向前端会把“没权限”误判成“没登录”反复跳转很迷惑。路径匹配用uri.contains(/result/)这种写法是偷懒但在这个小型项目里够用如果你想写得更严谨可以改成AntPathMatcher精确匹配。3.2 成绩排名径赛升序、田赛降序、并列名次一次讲清排名是运动会管理系统最核心的算法题也是最容易写出bug的地方。直接贴排名核心逻辑。public ListResultVO buildRanking(ListResultDO rawList) { // 第一步过滤无效与空成绩 rawList.removeIf(r - r.getScoreValue() null || r.getScoreValue().compareTo(BigDecimal.ZERO) 0); // 第二步把同一运动员同一项目的多轮成绩压缩成最好成绩 MapString, ResultDO bestMap new HashMap(); for (ResultDO r : rawList) { String key r.getAthleteId() _ r.getEventId(); ResultDO old bestMap.get(key); if (old null || r.getScoreValue().compareTo(old.getScoreValue()) 0) { bestMap.put(key, r); } } ListResultDO bestList new ArrayList(bestMap.values()); boolean isTrack TRACK.equals(bestList.get(0).getEventType()); // 第三步径赛成绩越小越好升序田赛成绩越大越好降序 ComparatorResultDO byScore (a, b) - isTrack ? a.getScoreValue().compareTo(b.getScoreValue()) : b.getScoreValue().compareTo(a.getScoreValue()); bestList.sort(byScore); // 第四步并列成绩给相同名次后续名次按断层跳跃 int rank 0; for (int i 0; i bestList.size(); i) { if (i 0 byScore.compare(bestList.get(i), bestList.get(i - 1)) ! 0) { rank i; } bestList.get(i).setRank(rank 1); } return toVO(bestList); }这段代码每一步都有讲究。第二步用HashMap的key athleteId _ eventId做分组压缩而不是用TreeSet因为TreeSet会按Comparator去重两个不同运动员成绩恰好相同其中一个会被直接吞掉这是“成绩莫名少了几条”的经典元凶。如果你不想拼字符串可以用HashMapLong, MapLong, ResultDO嵌套结构可读性更好。第三步的逻辑前提是score_value是BigDecimal且用compareTo比较。如果用double比较0.1的精度误差可能让9.99在10.11面前取得错误的比较结果如果用BigDecimal.equals()它会额外要求小数位scale一致7.850和7.85在相等的判断上会给出false只有compareTo才是按数值大小比。第四步名次赋值对应两种竞赛规则这里用的是“同名次跳跃”1、2、2、5适合颁奖只取前三名的场景如果你需要“不跳跃的对接名次”1、2、2、3把rank i改成rank bestList.get(i - 1).getRank()即可。这个细节面试时主动讲出来比背八股文有说服力。3.3 赛程冲突检查时间重叠判断的两种写法运动会报名时最容易出现的脏数据是一个运动员同时报了两个开赛时间撞车的项目。人工检查不现实必须在报名Service里拦一道。冲突判断的核心代码只有一行量级的逻辑。public boolean hasTimeConflict(Long athleteId, LocalDateTime startTime, LocalDateTime endTime) { ListEvent events eventMapper.selectByAthleteId(athleteId); for (Event event : events) { LocalDateTime s event.getStartTime(); LocalDateTime e event.getEndTime(); if (startTime.isBefore(e) endTime.isAfter(s)) { return true; } } return false; }时间重叠判断就一句话startTime.isBefore(e) endTime.isAfter(s)。两个时间区间[x1, x2]和[y1, y2]只要满足x1 y2 x2 y1就说明有交集。用LocalDateTime时只能用isBefore/isAfter比较别犯startTime event.getStartTime()这种拿对象比大小的错。再一个常见误用是判断条件写成startTime.isAfter(s) endTime.isBefore(e)那是“完全包含”而不是“相交”你只会拦住一个项目完全包住另一个项目的情况正常错开一点点的时间冲突就漏掉了。这里你还能顺手给Service层加上Transactional报名和冲突检查在一个事务里完成。面试官问“怎么保证数据一致性”你就可以答报名写入前查冲突判断通过才插入插入失败回滚配合signup表唯一索引双重兜底。3.4 成绩列表与多表关联一条SQL看清参赛链路成绩管理页面通常要展示“哪个代表队的谁在哪个项目里跑出了多少”。这需要result、signup、athlete、team、event五张表联查下面这条SQL是这套资源里列表查询的基准写法。SELECT r.id AS result_id, a.name AS athlete_name, t.team_name, e.event_name, r.round_no, r.score_value, r.is_valid FROM result r JOIN signup s ON r.signup_id s.id JOIN athlete a ON s.athlete_id a.id JOIN team t ON a.team_id t.id JOIN event e ON r.event_id e.id WHERE r.is_valid 1 ORDER BY e.id, r.score_value ASC;这段SQL的路口在于JOIN方向result表通过signup_id关联到signup再从signup拆出athlete_id和event_id而不是让result直接存athlete_id和event_id。后一种做法虽然冗余了字段查询时少一层JOIN但会出现同一个运动员同一项目多条成绩归属混乱的问题——一旦改报名记录成绩跟着错。多一层JOIN的代价换来的是数据归属始终唯一这在管理系统里是更正确的建模方式。ORDER BY这里只写了r.score_value ASC因为径赛田赛同表排序的完整逻辑在3.2的Java层处理。如果你想在SQL层一次排好可以这样写ORDER BY CASE WHEN e.event_type TRACK THEN r.score_value END ASC, CASE WHEN e.event_type FIELD THEN r.score_value END DESC。这个写法能跑但可读性差而且一旦混合多项目赛事Java层更灵活。我的建议是列表查询用简单SQL复杂排名用Service层统一算各干各的别把SQL写成天书。4. 本地部署与运行JDK、Maven、MySQL 参数一次配齐4.1 环境版本JDK8 Maven 3.6 MySQL 5.7/8.0先确认本机环境版本不对后面全是坑。这套资源对应的环境清单如下。组件推荐版本说明JDK1.8Spring Boot 2.x对JDK8支持最稳勿用JDK17强行编2.xMaven3.6.x3.8对镜像配置更严格但默认仓库也够用MySQL5.7 或 8.0初始化脚本两边通用IDEA2020.x 以上必须给Lombok插件否则编译报找不到getterJDK从Oracle官网或Adoptium下载装好后java -version确认输出是1.8。Maven配置settings.xml时建议把本地仓库路径指到非C盘目录项目依赖下载量大默认放C:\Users\xx\.m2容易把系统盘塞满。MySQL装完先做两件事设置root密码以及把字符集默认值改成utf8mb4——Windows安装版的默认字符集可能是latin1不改成utf8mb4后面中文大概率乱码。Idea里打开项目后第一件事是装Lombok插件并开启Annotation Processing菜单在Settings - Build, Execution, Deployment - Compiler - Annotation Processors。这一步漏掉的话Data注解的实体类全部编译不过报错信息是“找不到符号getAthleteId”完全不会提示是Lombok的问题很误导人。4.2 application.yml 配置文件逐行解读数据库连接参数全部集中在src/main/resources/application.yml这是部署阶段的重点排查对象。server: port: 8080 servlet: context-path: /sports spring: datasource: url: jdbc:mysql://localhost:3306/sports_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver thymeleaf: cache: false mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: trueJDBC连接串里这五个参数缺一个就有一款报错等着你。useUnicodetruecharacterEncodingutf8管中文传输不加它页面从后台读到的中文全是问号serverTimezoneAsia/Shanghai管时区不加它MySQL 5.7以上版本直接报Server returns invalid timezoneuseSSLfalse避免本机连接时反复握手警告allowPublicKeyRetrievaltrue是MySQL 8.0的专属坑8.0默认身份插件是caching_sha2_passwordJDBC第一次连接需要向服务端取公钥这一项默认关闭不加就报Public Key Retrieval is not allowed。map-underscore-to-camel-case: true开启后数据库student_no字段自动映射到Java实体studentNo这套资源里所有实体都依赖这个配置别手贱关掉。spring.thymeleaf.cache: false开发阶段务必开着否则改完前端模板不刷新你会怀疑人生。启动后访问路径是http://localhost:8080/sports/logincontext-path配了/sports少写这个前缀会直接404。4.3 克隆到启动五条命令命令行从零启动推荐按下面顺序执行每一步都有明确作用。mvn clean install -DskipTests mysql -uroot -p123456 -e DROP DATABASE IF EXISTS sports_db; CREATE DATABASE sports_db DEFAULT CHARSET utf8mb4; mysql -uroot -p123456 sports_db src/main/resources/sql/init.sql java -jar target/sports-0.0.1-SNAPSHOT.jar第一条mvn clean install -DskipTests会清掉target目录残留的旧class并重新打包确保你跑的是最新代码。-DskipTests跳过单元测试省得测试代码如果有坑挡住打包。第二条和第三条用mysql命令行直接建库导数据比在Navicat里手动执行脚本更省事注意是输入重定向Windows的cmd和PowerShell也能用但PowerShell的编码偶尔会捣乱建议在cmd里跑。第四条启动Spring Boot应用看到Started Application in xxx seconds才算成功。启动后立刻访问/sports/login用脚本里插入的管理员账号admin / admin123登录。如果页面白屏或报404先回头看4.2的连接串如果登录成功后列表页数据为空八成是初始化脚本没执行成功去Navicat里看一眼athlete表有没有数据。这两步排查完系统就能正常演示了。4.4 启动失败的三个高频场景报错场景常见原因快速处理Port 8080 was already in use上一个Tomcat没关或其它服务占端口改server.port为8081注意context-path一并访问Access denied for user root密码不对或用户不允许localhost登录核对spring.datasource.password或用ALTER USER重置密码Invalid bound statement (not found)mapper.xml没扫描到确认mapper-locations路径与xml实际目录一致启动类加MapperScan端口占用最省事的处理方式不是去杀进程而是改server.port。但要注意改了端口后前后端联调的地址全变如果你用前端单独发起请求记得同步改请求前缀。Access denied排查顺序是先在命令行用mysql -uroot -p手动登录能进说明密码没错问题在连接串不能进就是密码本身要重置。Invalid bound statement是MyBatis老毛病九个里面八个是xml的namespace写错或目录不对逐个检查Mapper接口包名和xml的namespace是否完全一致。5. 高频踩坑与排查五个影响验收翻车的细节5.1 中文乱码页面、日志、数据库三处同时查现象登录后运动员姓名在页面显示成“???”IDEA控制台日志里的中文全是乱码数据库里存的也是问号。原因这个坑往往不是一处错而是三处没对齐。数据库连接串缺characterEncodingutf8建库字符集不是utf8mb4或者IDEA控制台用了GBK任何一环出问题中文就一路糊到底。解决三步走。第一建库语句用DEFAULT CHARSET utf8mb4已存在的库用ALTER DATABASE sports_db CHARACTER SET utf8mb4;改掉第二连接串带上characterEncodingutf8第三IDEA里File - File Encoding把Global Encoding、Project Encoding、属性文件全设成UTF-8运行配置的VM options加-Dfile.encodingUTF-8。三处统一后再重新执行init.sql。5.2 成绩字段用float或double导致排名错位现象100米决赛9.99秒的成绩排在了10.11秒后面数据库里看成绩字段变成了9.989999999。原因float和double是二进制浮点数表示不了所有十进制小数。9.99在内存里实际上是9.98999999…两个成绩比较时精度误差导致排序结果错乱。这就是从选型章一路强调DECIMAL(8,3)的原因。解决把数据库字段改成ALTER TABLE result MODIFY score_value DECIMAL(8,3);Java实体类型换成BigDecimal比较一律用compareTo。如果库里已有脏数据用UPDATE result SET score_value ROUND(score_value, 3);先清洗一遍再改字段类型。记住一条铁律成绩、金额、比例这类精确小数绝不用float。5.3 MySQL 8.0 连接报 Public Key Retrieval is not allowed现象项目启动直接报错控制台出现Public Key Retrieval is not allowed或者Unable to load authentication plugin caching_sha2_password。原因MySQL 8.0默认身份认证插件是caching_sha2_passwordJDBC驱动连接时需要先从服务端取公钥来加密密码而这个取公钥的操作默认被JDBC参数禁掉了。解决JDBC连接串加两个参数allowPublicKeyRetrievaltrue和useSSLfalse。如果你不想动代码另一个方案是登录MySQL把账号改回旧认证方式ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456; FLUSH PRIVILEGES;。两条路都能通个人建议用前者改动最小。5.4 成绩列表重复同一运动员同一项目出现多行现象查看成绩列表一个运动员的两条记录长得一模一样数据量直接翻倍但报名记录确实只有一条。原因多表JOIN时条件写松了典型是在result JOIN signup处漏了关联字段或者分组维度不对产生笛卡尔积。还有一种情况是取“最好成绩”的分组没加event_id同一个运动员报了两个项目被压成了一行或拆成了多行。解决排错先跑SELECT COUNT(*) FROM result;确认基础表行数再一步步加JOIN每加一张就查一次数量看哪一步开始翻倍。列表查询用DISTINCT兜底取最好成绩SQL记得GROUP BY signup_id, athlete_id, event_id三个字段缺一不可。5.5 改了代码重启后还是旧逻辑target和本地仓库一起清现象IDEA里改了Service层方法重启应用后页面行为完全没变甚至报类文件具有错误的版本之类的编译问题。原因最常见的两个一是IDEA增量编译没生效target目录里的旧class还在二是Maven本地仓库有旧快照mvn spring-boot:run读到的是缓存里的旧jar包。Spring Boot DevTools的热重启不是万能的改了配置文件、pom或新增类时它经常不触发。解决命令行执行mvn clean install -DskipTests强制全量清理重新编译然后java -jar启动。这一步必须走别在IDEA里点绿色三角形IDEA的编译和Maven的clean经常各管各的。如果还不行打开本地仓库路径找到项目groupId对应目录把SNAPSHOT结尾的旧文件夹删掉重来。6. 最后一步用一场模拟运动会验证系统的完整算分链路拿到源码别急着改代码先把我下面的流程走一遍。这套验证方法能确认“建库、报名、录入、排名”整条链路是通的也能帮你在答辩前发现最后的隐患。准备两支队各5名运动员建3个项目男子100米径赛单位秒男子跳远田赛单位米女子铅球田赛单位米。给其中一人故意报两个开始时间重叠的项目检验冲突拦截再故意录入两个完全相同的成绩检验并列名次处理比赛跑两轮预赛和决赛都录进去看最终排名是否取到了最好成绩。登录管理员→批量导入运动员→逐项报名→切换裁判账号录入成绩→打开排名页每一步记下页面显示的结果。然后把排名页的数据导出用Excel手工排一遍径赛升序、田赛降序并列成绩名次相同。如果页面顺序和你手算的完全一致代码核心逻辑就过关了。不一致也别慌先看是不是5.2的精度问题再看3.2的排序方向是不是写反了。顺手说一个批量录入的实用技巧这套资源支持用Excel模板导入运动员与成绩字段对应关系如下。Excel列对应字段注意点运动员学号student_no重复的整行拒绝导入姓名athlete.name首尾空格要去掉性别athlete.gender只能填M或F项目名称event.event_name必须和event表完全一致轮次result.round_no填1或2超出拒绝成绩result.score_value保留3位小数径赛与田赛单位提前说明解析Excel用Apache POI的XSSFWorkbook注意它处理的是.xlsx而不是老格式.xls。读取单元格时用getCellType()判断是数字还是字符串轮次列用BigDecimal.valueOf(cell.getNumericCellValue()).intValue()成绩列直接保留三位小数。很多同学在这里摔过跤拿cell.getStringCellValue()去读数字单元格抛异常不说数据全丢。我第一次验收课设时直接拿了老师给的现成数据跑看起来一切正常结果换了自己造的10个运动员数据后排名直接错了一半。从那以后每次拿到Java管理系统源码我都会自己造一批边界数据——空成绩、并列成绩、重名运动员、超长字符串——从头到尾完整走一遍确认排名和报表都对才敢拿去答辩。这个习惯后来帮我顶住了好几次现场演示翻车。希望帮到你。本文还有配套的精品资源点击获取
返回列表