
学科竞赛管理这件事表面上是发通知、收报名、交作品、打分数真做起来却是一地鸡毛。我在开发这套基于Spring Boot的学科竞赛管理系统时最深的感受是业务本身不复杂复杂的是把多角色、多流程、多状态的零散信息串成一条有序的链路。这篇文章就把这套系统的设计思路、数据库模型、核心代码、调试部署经验全部拆开讲一遍覆盖从竞赛发布、在线报名、作品提交到专家评审、成绩公示的完整闭环。无论你是要做课程设计、毕业设计还是想为公司或学校快速搭建一个竞赛管理平台都能从里面拿到可以直接落地的方案和代码思路。1. 学科竞赛管理的真实痛点为什么需要一套专门系统1.1 传统管理方式的信息孤岛问题很多高校和机构在竞赛管理上长期依赖一套原始组合拳通知靠群聊和邮件报名靠Excel表格来回传作品统一交到网盘链接评委打分是独立填表、再由一个人手工汇总。这套模式在参赛人数少的时候勉强能用一旦竞赛类别超过十个、单场报名破百人问题就会集中爆发。最典型的是信息不同步。学生报名的Excel在A老师手里作品提交记录在B老师手里评委打分表在C老师手里三方数据对不上时你需要逐个核对哪个学生报名了但没交作品、哪个评委还没提交评分、某场比赛的最终排名是怎么算出来的。这种排查过程极其消耗时间而且每届竞赛的流程稍有变化上一届的表格模板就作废了所有统计逻辑要重来一遍。另一个隐性成本是数据不可沉淀。竞赛信息和获奖记录分散在个人电脑和聊天记录里学校想做学科竞赛成果分析、学生综测加分审核或者竞赛育人成效汇报时往往要临时向多个老师要数据再手工整理成报表。没有一套统一的数据模型这些历史数据就无法被有效利用。1.2 系统要解决的四个核心问题在设计这套系统之前我明确列出了它必须要解决的四个问题。第一报名信息统一化。学生只要在线填写一次报名信息后台自动关联学号、姓名、院系和联系方式管理员不需要维护多份Excel。第二作品提交规范化。每场比赛单独设置提交起止时间、文件格式和大小上限系统自动校验并记录提交人、提交时间和文件哈希杜绝我交了你没收到的扯皮。第三评审流程透明化。多评委独立打分系统自动汇总平均分和排名学生可以在公示期内查看自己的成绩和作品状态减少人工干预和争议。第四数据沉淀可复用。所有竞赛、报名、作品、成绩数据都进入数据库后面接综测系统、做统计分析或者生成年度报告只需要写几条SQL就能拿到汇总结果。1.3 系统适用场景与目标用户这套系统面向三类使用者学生、教师或竞赛管理员、系统管理员。学生的核心诉求是快速找到感兴趣的竞赛并完成报名和作品提交教师的核心诉求是发布竞赛、管理审核报名、组织评委评审并导出成绩系统管理员的诉求是维护基础数据院系、用户、竞赛类型和系统参数。从开发角度看这个项目的复杂度也正好卡在一个甜区它包含完整的用户认证、角色权限、CRUD、文件上传下载、状态流转、统计报表技术点覆盖面广但不涉及复杂的并发和分布式问题非常适合作为Spring Boot的练手项目也够得上一篇毕业论文的体量。2. 技术选型与项目结构为什么是Spring Boot而不是其他框架2.1 技术栈全景这套系统采用了目前Java web开发最主流的组合层次技术选型主要用途后端框架Spring Boot 2.7.x提供IOC容器、自动配置、嵌入式Web容器持久层MyBatis-Plus单表CRUD无需手写SQL复杂查询用注解/XML数据库MySQL 5.7 / 8.0存储用户、竞赛、报名、作品、评审等业务数据权限安全Spring Security JWT登录认证、接口访问控制、无状态会话前端Vue 3 Element Plus或Thymeleaf管理后台界面与用户端页面构建工具Maven依赖管理与项目构建API调试Knife4jSwagger增强自动生成接口文档联调效率倍增需要特别说明一点如果你不熟悉前后端分离前端也可以直接用Thymeleaf模板引擎在Spring Boot里写页面工程结构更简单适合课程设计。我这里采用的是前后端分离方案后端只提供JSON接口前端工程独立运行在Node环境里。2.2 为什么是Spring Boot回到一个经常被学生问到的问题为什么不选SSHSpring MVC Struts Hibernate或者传统的SSM原因其实很实在。Struts和Hibernate技术已经明显过时资料少、配置繁琐、性能和维护成本都不占优。而早期SSM虽然结构清晰但需要写大量XML配置数据源、事务、MyBatis配置、Spring配置、Web配置五六个配置文件来回折腾还没开始写业务代码就先被配置劝退。Spring Boot最大的价值是约定大于配置。内嵌Tomcat应用只需一个main方法就能启动自动配置机制根据你引入的依赖自动装配Bean配合Spring Boot Starter体系引入依赖就能获得对应的能力。对于竞赛管理系统这种业务逻辑清晰、需要快速开发交付的项目Spring Boot能大幅缩短搭建时间把精力留给真正的业务代码。另一个现实因素是就业和答辩的接受度。Spring Boot已成为国内中小型Java项目的标准形态企业招聘要求里大量出现毕业设计答辩时也更容易通过。后面接Flink、对接消息队列、做微服务Spring Boot都是绕不开的基础层所以用它不会走弯路。2.3 目录结构设计的学问项目拿到手第一步不是急着写代码而是把目录结构规划好。我这里采用经典的分层架构com.example.competition ├── Controller // 接收请求参数校验返回结果 ├── Service // 业务逻辑层事务控制 │ └── impl ├── Mapper // 数据访问层MyBatis-Plus接口 ├── Entity // 数据库实体类 ├── DTO // 前端传递的数据对象如登录请求、报名请求 ├── VO // 后端返回给前端的视图对象如排名信息 ├── Config // 配置类安全配置、跨域配置、文件上传配置 ├── Common // 统一返回值、异常处理、常量、枚举 ├── Utils // 工具类文件处理、JWT工具 └── CompetitionApplication.java // 启动类这个结构的好处是职责单一、依赖方向明确。Controller层只负责参数接收和结果封装不写SQLService层处理业务规则比如报名前检查是否已报名评审前检查是否处于评审期Mapper层只做数据读写。很多初学者把业务逻辑写进Controller里短期内代码能跑但后面加需求时维护成本剧增——比如要给报名加人数上限你需要在每个调用了报名接口的地方都改一遍。另外建议把返回结果统一封装成ResultT对象包含状态码、消息和数据三个字段这样前端处理接口返回值时逻辑可以统一。不要一会儿直接返回Map一会儿返回实体类接口风格混乱会让后续联调非常痛苦。3. 核心功能模块拆解从报名到评审的全流程闭环3.1 三种角色三套视图系统按用户角色划分了三套功能视图本质上是同一套后端接口在不同权限下的过滤结果。管理员admin拥有全部权限可以维护用户、竞赛类型、院系信息审核异常报名导出成绩报表。教师teacher负责发布竞赛、设置比赛时间节点、审核报名、分配评委、发布成绩。学生student登录后能看到所有可报名的竞赛提交报名信息上传作品查看自己的评审状态和最终成绩。权限控制在后端统一实现。登录成功后服务端生成JWT令牌前端每次请求都带上令牌后端通过Spring Security的PreAuthorize(hasRole(ADMIN))这类注解做接口级控制。注意不要只在菜单上做权限隐藏接口必须同样校验否则懂技术的学生直接构造请求URL就能越权访问管理接口。3.2 竞赛管理模块发布到结束的状态流转一场竞赛的生命周期我把它设计为五个状态草稿DRAFT、报名中REGISTERING、评审中REVIEWING、已结束FINISHED、已取消CANCELED。教师在后台创建竞赛时先保存为草稿确认信息无误后发布进入报名中报名截止时间到达后系统自动或手动将竞赛置为评审中所有评委打完分并确认发布成绩后竞赛进入已结束。这个状态字段是实现整个系统流转的枢纽。所有关键操作的合法性都依赖状态判断报名接口先检查状态是否为报名中作品上传接口检查是否在作品提交时间段内打分接口检查是否处于评审中。建议用枚举类维护状态值而不是散落的魔法数字。Getter public enum CompetitionStatus { DRAFT(0, 草稿), REGISTERING(1, 报名中), REVIEWING(2, 评审中), FINISHED(3, 已结束), CANCELED(4, 已取消); private final Integer code; private final String desc; CompetitionStatus(Integer code, String desc) { this.code code; this.desc desc; } }3.3 报名与审核怎么避免重复报名和资格问题报名是并发操作最集中的环节。学生点击报名时后端不能只做简单的INSERT得先处理三个问题。第一是否重复报名。竞赛报名表对竞赛ID学生ID建唯一索引同时Service层在插入前查询一次双重保险。单纯靠代码判断有并发风险两个请求同时进来可能都查不到记录然后都执行插入唯一索引是最后的防线。第二是否还在报名时间内。系统判断当前时间是否在竞赛的报名开始和结束时间之间不在区间内直接拒绝报名并给前端返回明确提示。第三是否超过人数上限。竞赛表里维护一个max_people字段报名时先执行一条SELECT COUNT(*)如果已达上限则报名失败。更严谨的做法是使用乐观锁或UPDATE ... SET registered_count registered_count 1 WHERE id ? AND registered_count max_people的原子自增方式避免高并发下超卖。竞赛管理系统的并发量通常不高但把这个设计讲出来在答辩中会成为加分项。报名审核方面我保留了教师审核报名资格的能力。教师可以看到报名列表对不符合条件的报名执行驳回操作驳回时填写原因学生端会收到审核状态变更提示。3.4 作品提交文件上传的校验与存储作品提交是本系统最容易踩坑的模块因为文件上传涉及IO操作、路径安全、大小限制、重名覆盖等多个问题。我在作品上传接口里做了四件事校验文件格式。通过文件扩展名和MIME类型双重判断竞赛可以自行配置允许的格式列表比如论文类允许PDF、Word设计类额外允许图片和压缩包。校验文件大小。Spring Boot的spring.servlet.multipart.max-file-size配置全局上限同时针对不同竞赛类型做细分限制防止有些人传几个G的视频把服务器塞满。重命名存储文件。不使用用户上传的原始文件名而是按竞赛ID_学号_时间戳_随机数.扩展名的规则重新生成文件名避免两个学生上传同名文件互相覆盖也避免文件名包含特殊字符引发安全问题。记录文件元数据。文件本身存储到服务器指定目录数据库表只存文件路径、大小、上传时间、哈希值。这样数据库体积不会快速膨胀上传下载速度也有保障。String ext FilenameUtils.getExtension(file.getOriginalFilename()); String newFileName competitionId _ stuNo _ System.currentTimeMillis() _ RandomUtil.randomNumbers(4) . ext; File target new File(uploadDir / newFileName); file.transferTo(target);3.5 评审打分多评委独立打分与自动汇总评审阶段是最能检验系统设计水平的地方。一场竞赛通常有3-5名评委每个评委面对几十份作品打完分后系统要自动汇总排名。我采用的方案是系统为每份通过初审的作品生成评审记录关联多条评委打分子表每个评委登录后只能看到分配给自己的评审列表并打分提交。为防止评委之间互相干扰评委端不显示其他评委的打分情况。全部评委提交后系统自动计算平均分和排名教师确认无误后一键发布。发布后成绩公示列表对所有参赛学生可见学生只能看到自己的分数、排名和奖项不能看其他人的成绩。打分项可以拆成多个维度比如创新性40分、完成度30分、实用性30分每个维度独立打分后加权求和。这种细分维度在设计类竞赛里尤其常见数据库里的评审表就得多加几个字段。第4章会有详细的表结构说明。4. 数据库设计竞赛业务的数据模型怎么建4.1 六张核心表撑起整套业务数据库是整个系统的地基表字段的合理程度直接决定后面写业务代码的顺畅程度。这套系统最核心的六张表如下。表名用途关键字段sys_user用户表学生/教师/管理员id, username, password, real_name, role, department_idcompetition竞赛表id, title, type_id, status, max_people, register_start_time, register_end_time, submit_start_time, submit_end_timeregistration报名表id, competition_id, student_id, audit_status, create_timework作品表id, competition_id, student_id, work_name, file_url, file_size, submit_timereview_item评审项配置表id, competition_id, item_name, max_score, weightreview_record评委打分表id, work_id, reviewer_id, item_id, score, comment, submit_time其中需要重点关注的是评审相关的两张表。评审项配置表把一场竞赛有哪些打分维度、每个维度占多少分做成动态配置而不是写死在代码里这样不同竞赛可以使用不同的评分标准系统通用性更强。评委打分表的一条记录代表某个评委对某份作品的某个维度打了一次分同一个评委同一份作品有N条维度分记录统计平均分时按维度权重汇总即可。4.2 外键与索引设计字段定好了下一步是索引设计。很多初学者做数据库设计时不建索引数据量小的时候没感觉数据一多查询就明显变慢。我的索引设计经验总结如下唯一索引registration表的uk_competition_student(competition_id, student_id)防止重复报名sys_user表的uk_username(username)保证用户名唯一。普通索引registration表的idx_competition_id和idx_student_id用于快速查询某场竞赛的所有报名学生、某学生报名的所有竞赛review_record表的idx_work_id和idx_reviewer_id用于按作品汇总成绩和查看评委评分情况。组合索引work表的idx_competition_submit(competition_id, submit_time)按竞赛和时间范围筛选作品记录。外键我建议在逻辑层面维护而不是在数据库物理层面加太多FOREIGN KEY约束。原因是真实的项目中物理外键会带来删除数据时的连锁约束问题很多团队为了灵活性会选择不加物理外键依靠业务代码保证引用完整性。但在答辩时你要能说清楚为什么表与表之间有关联关系但在数据库里没建外键否则老师会认为你设计不严谨。4.3 设计上的三个教训第一不要过度冗余。我最初在competition表里冗余了一个register_count字段用来快速展示报名人数。初衷是减少COUNT查询但维护这个字段需要保证每次报名、退赛、审核驳回时都同步更新稍有不慎就会数据不一致。最终我保留了它但加了一道定时校验任务每天自动对账一次。如果你的场景并发不高直接用COUNT查询也完全没问题。第二状态字段用tinyint存整数不要用字符串。字符串状态容易拼写错误也无法用、做范围判断比如查询所有报名中和评审中的竞赛用status IN (1,2)就非常方便。第三所有时间字段统一用datetime不要存时间戳整数。虽然时间戳排序和比较方便但直接看数据库里的数字很难快速判断业务时间排查问题时极度痛苦。配合MyBatis-Plus的自动填充功能创建时间和更新时间在插入和更新时自动赋值不用每个Mapper手动写当前时间。5. 关键实现细节配置、权限、文件上传与状态流转5.1 配置文件中的关键参数application.yml里有几项配置直接影响系统稳定性单独拿出来说明一下。server: port: 8080 servlet: context-path: / spring: datasource: url: jdbc:mysql://localhost:3306/competition_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 50MB max-request-size: 100MB mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 jwt: secret: your-secret-key-please-change-in-production expire: 604800数据源URL里的characterEncodingutf8和serverTimezoneAsia/Shanghai是很多初学者必踩的坑。不加编码配置会导致中文乱码不加时区配置在MySQL 8.x下会报时区错误。MyBatis-Plus的map-underscore-to-camel-case: true把数据库的user_name自动映射到实体的userName避免手写大量TableField映射。逻辑删除字段是另一个建议给所有业务表加一个deleted字段用MyBatis-Plus的全局逻辑删除配置删除操作变成更新操作保留历史数据可追溯。这在论文的数据库设计部分也是一个亮点。5.2 登录鉴权与密码加密密码存储绝对不能明文。我用Spring Security自带的BCryptPasswordEncoder做密码哈希每次校验时调用matches方法即可。BCrypt的特点是自动加盐、计算成本可调即便数据库泄露攻击者也很难从哈希反推出原始密码。JWT的生成和校验逻辑封装在工具类里登录成功后服务端返回一个有效期7天的token。前端把token存在本地请求时放到请求头Authorization字段中。服务端通过一个拦截器或Spring Security过滤器链统一解析token并设置用户上下文。这里有一个容易被忽略的细节修改密码后要让旧token失效。最简单的方案是JWT里携带一个token_version字段用户表里维护版本号每次修改密码版本号加1校验token时对比版本号。因为这是毕业设计或课程设计复杂方案不上也可以但把这个话题提出来会让答辩老师觉得你考虑过安全问题。5.3 文件上传的完整链路文件上传除了第3.4节讲到的存储细节还有一个容易忽略的点下载时的鉴权。竞赛作品往往涉及隐私和防抄袭不能允许任何人凭URL直接下载。我的方案是下载接口要求携带token后端将文件以ResponseEntitybyte[]或StreamingResponseBody形式返回并设置Content-Disposition: attachment。另一个点是上传目录的分离。配置一个upload.dir参数生产环境下把上传目录放在应用外部磁盘而不是放在jar包内部或项目源码目录里。这样系统升级重新打包时历史文件不会丢失。如果你把文件放在src/main/resources下打包后文件会被写进jar包重启就可能覆盖丢失这是真实项目里一个非常严重的隐患。5.4 用状态机思路管理报名到成绩的流程业务流转用一个简单的状态机常量类维护比在每个Service里散落if (xxx) { }更清晰。状态流转规则如下当前状态允许的操作目标状态草稿发布报名中报名中报名截止/手动关闭评审中评审中全部评分完成并发布成绩已结束报名中/评审中管理员取消已取消每个操作在Service层先查竞赛状态再用Assert.state或自定义业务异常做校验不满足条件就抛出带提示信息的异常由全局异常处理器统一返回给前端。全局异常处理器的作用是兜底让用户看到的错误信息既友好又不暴露SQL异常等敏感细节。我的实现是一个RestControllerAdvice类里面定义了handleBusinessException、handleValidationException和handleException三个方法分别处理业务异常、参数校验异常和未知异常。6. 本地调试与部署从开发环境到跑通的完整链路6.1 环境准备清单项目要跑起来先确认下面几项环境组件推荐版本说明JDK1.8 或 11Spring Boot 2.7支持Java 8如果是Spring Boot 3.x则需要Java 17Maven3.6以上建议配置国内镜像源否则依赖下载慢到怀疑人生MySQL5.7或8.0注意8.0的驱动类换成了com.mysql.cj.jdbc.DriverIDEA2022社区版也可以但Ultimate版对Spring Boot的调试支持更好Node.js14前端工程运行需要Vue项目构建和依赖安装都靠它环境准备阶段最大的坑是JDK版本和Spring Boot版本的匹配。如果你用Spring Boot 3.xJDK必须是17及以上如果你用JDK 8最高能用Spring Boot 2.7.x。很多人在网上随便复制一套Spring Initializr生成的工程本机是JDK 8却引入了Spring Boot 3.2一启动就报错。我的建议是课程设计直接用Spring Boot 2.7 JDK 8的稳定组合网上资料最多、问题最容易搜到。6.2 数据库初始化的常见坑数据库脚本的执行顺序很重要。正确的顺序是先创建数据库、再创建用户相关基础表、然后插入初始管理员账号。MySQL 8.0下执行.sql脚本时最常遇到的两个问题一是默认字符集不是utf8mb4中文插入后变乱码。解决办法是建库时显式指定CREATE DATABASE competition_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;二是MySQL 8.0的认证插件改成了caching_sha2_password一些老版本驱动连不上。如果你用的是5.x的驱动jar需要执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;换回旧认证方式或者直接把驱动升级到8.x。6.3 后端接口调试的常用方法我不建议用浏览器地址栏输入URL的方式来调试POST接口信息量太少了。实际开发中我主要用两个工具。第一个是Knife4j。Spring Boot工程里引入knife4j-spring-boot-starter依赖启动后访问/doc.html就能看到所有接口的在线文档参数结构、返回示例一目了然还支持直接在线调试。它比Swagger原生UI好看很多而且中文界面更友好。第二个是Postman。用它做接口调试更灵活可以保存接口调用历史、设置环境变量、写自动化测试断言。调试文件上传接口时Body选form-data文件字段选File类型即可。调试JWT鉴权的接口时在Authorization标签页直接选择Bearer Token并粘贴token值即可。6.4 本地打包与服务器部署后端打包前先确保application.yml里所用数据库地址、账号密码无误然后执行Maven打包命令mvn clean package -DskipTests打包完成后target目录下会生成一个xxx.jar文件。本地可以用java -jar xxx.jar直接启动验证。部署到Linux服务器时我习惯写一个简单的启动脚本内容大致如下#!/bin/bash APP_NAMEcompetition-system.jar nohup java -jar /opt/app/$APP_NAME \ --spring.profiles.activeprod \ --server.port8080 \ /opt/app/logs/console.log 21 echo Application started, pid: $!这个脚本把日志输出到文件而不是直接扔到终端窗口关闭SSH连接后服务也不会停止。如果你没有生产服务器用云服务器或者虚拟机都可以注意在云服务商的安全组策略里放行8080端口否则外部访问不到。前端如果用的是Vue工程构建命令是npm run build产物在dist目录下。部署时可以用Nginx托管静态文件同时配置反向代理把/api请求转发到后端的8080端口这样前端和后端就统一到同一个域名和端口下避免跨域问题。7. 配套论文与答辩准备1万字文档怎么写才有价值7.1 论文结构的组织思路这套系统配套的论文文档除致谢和参考文献外核心章节通常按以下逻辑组织绪论写背景和意义重点说明学科竞赛信息化管理的必要性加上国内外研究现状和论文结构安排。相关技术介绍写Spring Boot、MyBatis-Plus、MySQL、Vue的核心特性注意不要大段抄官方文档要结合你项目中的应用场景来讲。系统需求分析先写可行性分析技术、经济、操作层面再画功能需求和非功能需求配合用例图说明三种角色的用例。系统设计写总体架构图、功能模块划分、数据库E-R图和表结构设计。数据库部分建议把每张表的字段都列出来并解释每个字段的用途。系统实现按模块逐一贴核心代码片段配页面截图说明关键逻辑实现。系统测试整理测试用例表包含测试项、预期结果、实际结果和是否通过。功能测试之外建议补充一段性能测试描述说明系统在并发场景下的表现。7.2 图表绘制的几个建议论文中需要配图的地方很明确下面几个图是必备的系统总体架构图展示浏览器、前端、后端、数据库的分层架构用Visio或Draw.io绘制。功能结构图把所有功能模块按树形结构画全这是功能设计部分的基础。E-R图画出实体之间的关系至少包含用户、竞赛、报名、作品、评审记录六个实体。用矩形表示实体、椭圆表示属性、菱形表示关系的标准画法。系统流程图展示学生从注册到查看成绩的完整流程。流程图绘制时注意用标准流程图形状不要自己发明符号。需要特别提醒不要从网上直接截图别人的图。答辩老师对论文里的图非常敏感如果系里能查到你的图在其他论文里出现过或者图片风格和正文排版明显不统一很容易被质疑。用Draw.io自己画一遍风格统一内容贴合你的系统反而更省心。7.3 答辩时容易被问到的几个问题答辩中最常见的问题基本集中在设计决策上这里提前给大家准备好回答思路。问题一为什么选择Spring Boot而不是Spring Cloud回答要点系统规模较小、并发量适中单体应用足以支撑Spring Cloud引入注册中心、网关等组件会显著增加部署和运维成本对当前项目属于过度设计。问题二数据库为什么不用外键回答要点物理外键会在插入、更新、删除时带来额外的约束检查开销一旦出现误删还会连锁影响关联数据。为了系统扩展性和灵活度采用逻辑外键配合业务代码保证数据一致性。问题三并发报名时你怎么防超报回答要点一是报名表唯一索引防止重复报名二是采用原子UPDATE自增报名人数并判断是否达到上限三是利用MySQL事务隔离级别保证数据一致性。问题四如果评委人数很多系统要怎么扩展回答要点当前设计评审记录按作品和评委存储横向扩展可以按竞赛拆分数据库表或引入消息队列异步处理但当前规模下单体架构足够。7.4 论文写作的避坑建议写论文最容易出现的问题就是需求分析写得像技术文档大段描述系统支持XXX功能但缺少分析的过程。正确写法是先描述问题场景再说明为什么需要这个功能最后给出解决思路。比如报名模块应该先写传统报名方式存在数据分散、无法实时统计的问题再提出设计在线报名功能支持学生填写信息、教师审核、系统自动计数。另外一个重点是字数控制。1万字以上的论文中实现部分的代码不要贴太多每段代码后面都要有文字解释代码背后的思路。如果一段代码占半页却没有一句解释答辩老师会认为你是凑代码量。数据库设计部分同样需要配合字段说明表不要只丢一张建表SQL就完事。最后提醒一点所有图片、表名前要有编号和图题正文中要通过如图X所示如表X所示来引用这是论文格式的基本要求很多学生因为这个小细节被扣分。我个人在实际开发这类管理系统时的体会是业务逻辑其实不难真正影响体验的往往是那些看不见的细节比如文件上传路径的规划、状态流转的严谨性、接口返回结构的统一性。这套学科竞赛管理系统做完之后最大的收获不是实现了多少功能而是建立了一种先设计状态和数据结构、再写业务代码的思维方式。后续你想把它扩展成支持多轮评审、对接综测加分系统、甚至接入数据分析展示竞赛成果趋势都会顺畅很多。如果你正在做类似的项目建议先把数据库表和状态流转画明白再动手写代码能少走不少弯路。