温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片!

1. 项目背景与意义

随着高校及企事业单位体育活动的日益丰富,传统的人工记录、纸质通知、电话协调的运动会管理模式已难以满足高效、准确、透明的管理需求。运动会管理系统应运而生,旨在通过信息化手段,对运动会从报名、赛程编排、成绩录入、公告发布到数据统计的全流程进行数字化管理。

项目意义:

  • 提升效率:自动化处理报名、分组、成绩统计等繁琐工作,大幅减少人工操作和错误。
  • 增强透明度:实时发布赛程、成绩和排名,所有参与者可通过系统随时查看,过程公开公正。
  • 优化体验:为运动员提供便捷的在线报名与成绩查询,为裁判员提供高效的成绩录入工具,为管理员提供全面的数据看板。
  • 数据驱动决策:系统积累的报名、成绩等数据可用于分析参赛趋势、项目热度,为未来活动策划提供依据。

本系统采用前后端分离架构,后端使用 Spring Boot 提供稳定高效的 RESTful API 服务,前端使用 Vue.js 构建交互友好、响应迅速的用户界面,是现代化 Web 应用开发的典型实践。

2. 技术栈详解

2.1 后端技术栈 (Spring Boot)

  • 核心框架: Spring Boot 2.x
  • Web 框架: Spring MVC
  • 数据持久层: MyBatis-Plus / Spring Data JPA
  • 数据库: MySQL 8.0
  • 连接池: HikariCP
  • 权限控制: Spring Security + JWT (JSON Web Token)
  • 接口文档: Swagger2 / Knife4j
  • 项目构建: Maven
  • 其他工具: Lombok (简化代码), Hutool (工具类库)

2.2 前端技术栈 (Vue.js)

  • 核心框架: Vue 3 (Composition API) 或 Vue 2
  • 构建工具: Vite 或 Vue CLI
  • UI 组件库: Element Plus (Vue 3) 或 Element UI (Vue 2)
  • 状态管理: Pinia (Vue 3) 或 Vuex (Vue 2)
  • 路由管理: Vue Router
  • HTTP 客户端: Axios
  • 可视化图表: ECharts (用于数据统计看板)

2.3 开发与部署

  • 版本控制: Git
  • 后端部署: 可打包为 Jar 包,使用 Java 环境运行,或使用 Docker 容器化部署。
  • 前端部署: 构建为静态资源,部署至 Nginx、Tomcat 或对象存储 (如 OSS)。

3. 系统核心功能模块设计

系统主要分为三大角色:系统管理员、裁判员、运动员/观众。

3.1 管理员端

  • 用户管理: 对裁判员、运动员账号进行增删改查、权限分配。
  • 项目管理: 创建、编辑运动会项目(如100米跑、跳高),设置项目规则、名额限制。
  • 报名管理: 审核运动员的线上报名申请。
  • 赛程编排: 根据项目、场地、时间自动或手动生成比赛日程表。
  • 成绩总览: 查看所有项目的最终成绩与排名。
  • 公告管理: 发布运动会相关通知、规则变更等信息。
  • 数据统计: 可视化图表展示报名人数趋势、项目热度等。

3.2 裁判员端

  • 我的任务: 查看被分配负责的比赛项目及赛程。
  • 成绩录入: 在比赛结束后,录入或修改所负责项目的运动员成绩。
  • 成绩确认: 提交成绩前进行二次确认,确保数据准确。

3.3 运动员/观众端

  • 个人信息: 查看和修改个人资料。
  • 项目浏览与报名: 查看所有可报名的项目,在线提交报名申请。
  • 我的赛程: 查看个人已报名项目的比赛时间、地点。
  • 成绩查询: 实时查询个人或所有项目的比赛成绩与排名。
  • 公告查看: 浏览系统发布的最新公告。

4. 数据库核心表设计

以下为部分核心数据表结构:

  • 用户表 (sys_user): id, username, password, real_name, role (admin, referee, athlete), phone, status...
  • 运动会项目表 (sport_event): id, event_name, category, limit_participants, rule_description, status...
  • 运动员报名表 (registration): id, user_id, event_id, registration_time, status (pending, approved, rejected)...
  • 赛程表 (schedule): id, event_id, start_time, end_time, venue, referee_id, status...
  • 成绩表 (score): id, schedule_id, athlete_id, score_value, ranking, record_time, referee_id...
  • 公告表 (announcement): id, title, content, publisher_id, publish_time, status...

5. 核心代码示例

5.1 后端核心:Spring Boot 统一响应封装与JWT验证

统一响应体 (Result.java):

import lombok.Data;
import java.io.Serializable;
@Data
public class Result<T> implements Serializable {
private Integer code; // 状态码,如200成功,500失败
private String msg;   // 提示信息
private T data;       // 响应数据
public static &lt;T&gt; Result&lt;T&gt; success(T data) {
    Result&lt;T&gt; result = new Result&lt;&gt;();
    result.setCode(200);
    result.setMsg("操作成功");
    result.setData(data);
    return result;
}
public static &lt;T&gt; Result&lt;T&gt; error(String msg) {
Result&lt;T&gt; result = new Result&lt;&gt;();
result.setCode(500);
result.setMsg(msg);
return result;
}
}

JWT工具类 (JwtUtil.java) 核心方法:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
private static final String SECRET_KEY = "your-secret-key"; // 应配置在application.yml中
private static final long EXPIRATION = 86400000L; // 24小时
// 生成Token
public static String generateToken(String username, String role) {
    Map&lt;String, Object&gt; claims = new HashMap&lt;&gt;();
    claims.put("username", username);
    claims.put("role", role);
    return Jwts.builder()
            .setClaims(claims)
            .setSubject(username)
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
            .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
            .compact();
}
// 解析并验证Token
public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}

5.2 后端核心:Spring Security 配置与登录接口

Spring Security 配置类核心片段:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 关闭csrf,因为使用JWT无状态认证
.csrf().disable()
// 允许跨域
.cors().and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// 登录接口允许匿名访问
.antMatchers("/api/auth/login").anonymous()
// 静态资源、Swagger文档等放行
.antMatchers("/swagger-ui.html", "/webjars/", "/swagger-resources/", "/v2/api-docs").permitAll()
// 其他所有请求都需要认证
.anyRequest().authenticated();
// 添加JWT过滤器
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
// 密码编码器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

登录控制器 (AuthController.java):

@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Result&lt;String&gt; login(@RequestBody LoginRequest request) {
// 1. 验证用户名密码
User user = userService.findByUsername(request.getUsername());
if (user == null || !passwordEncoder.matches(request.getPassword(), user.getPassword())) {
return Result.error("用户名或密码错误");
}
// 2. 生成JWT Token
String token = JwtUtil.generateToken(user.getUsername(), user.getRole());
// 3. 返回Token
return Result.success(token);
}
}

5.3 前端核心:Vue3 + Pinia 状态管理与API调用

Pinia Store (userStore.js) 用于管理用户登录状态:

import { defineStore } from 'pinia'
import { ref } from 'vue'
import { loginApi, getUserInfo } from '@/api/user'
export const useUserStore = defineStore('user', () => {
const token = ref(localStorage.getItem('token') || '')
const userInfo = ref({})
// 登录动作
const login = async (loginForm) => {
const res = await loginApi(loginForm)
if (res.code === 200) {
token.value = res.data
localStorage.setItem('token', token.value)
// 登录成功后获取用户信息
await getUserInfo()
return Promise.resolve()
} else {
return Promise.reject(new Error(res.msg))
}
}
// 获取用户信息
const getUserInfo = async () => {
const res = await getUserInfoApi()
if (res.code === 200) {
userInfo.value = res.data
}
}
// 退出登录
const logout = () => {
token.value = ''
userInfo.value = {}
localStorage.removeItem('token')
}
return { token, userInfo, login, logout, getUserInfo }
})

Axios 请求拦截器 (设置JWT Token):

import axios from 'axios'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 5000
})
// 请求拦截器
service.interceptors.request.use(
(config) => {
const userStore = useUserStore()
if (userStore.token) {
config.headers['Authorization'] = Bearer ${userStore.token}
}
return config
},
(error) => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
(response) => {
const res = response.data
if (res.code !== 200) {
ElMessage.error(res.msg || 'Error')
return Promise.reject(new Error(res.msg || 'Error'))
} else {
return res
}
},
(error) => {
ElMessage.error(error.message || '请求失败')
return Promise.reject(error)
}
)
export default service

5.4 前端核心:运动员报名页面组件示例 (Vue3 + Element Plus)

<template>
  <div class="registration-page">
    <el-card>
      <template #header>
        <span>运动会项目报名</span>
      </template>
      <el-table :data="eventList" style="width: 100%">
        <el-table-column prop="eventName" label="项目名称" />
        <el-table-column prop="category" label="类别" />
        <el-table-column prop="limitParticipants" label="名额限制" />
        <el-table-column prop="currentParticipants" label="已报名" />
        <el-table-column label="操作">
          <template #default="scope">
            <el-button
              type="primary"
              size="small"
              @click="handleRegistration(scope.row)"
              :disabled="scope.row.status !== 'OPEN' || scope.row.currentParticipants >= scope.row.limitParticipants"
            >
              {{ scope.row.status === 'OPEN' ? '立即报名' : '已截止' }}
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getEventListApi, submitRegistrationApi } from '@/api/event'
const eventList = ref([])
// 获取项目列表
const fetchEventList = async () => {
const res = await getEventListApi()
if (res.code === 200) {
eventList.value = res.data
}
}
// 处理报名
const handleRegistration = async (row) => {
try {
await ElMessageBox.confirm(确认报名【${row.eventName}】项目吗?, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
const res = await submitRegistrationApi({ eventId: row.id })
if (res.code === 200) {
ElMessage.success('报名成功,等待管理员审核!')
fetchEventList() // 刷新列表
}
} catch (error) {
console.log('报名取消或失败', error)
}
}
onMounted(() => {
fetchEventList()
})
</script>

6. 总结与展望

本文详细阐述了基于 Spring Boot 和 Vue.js 的运动会管理系统的设计与实现,涵盖了项目背景、技术栈选型、功能模块、数据库设计以及前后端核心代码示例。该系统通过现代化的技术栈,实现了运动会管理的信息化、自动化,具有良好的可扩展性和维护性。

未来可扩展方向:

  • 移动端适配: 开发微信小程序或 Uni-app 跨端应用,方便运动员随时查看。
  • 实时通知: 集成 WebSocket 或消息队列,实现成绩发布、赛程变更的实时推送。
  • 智能编排: 引入算法优化赛程,避免运动员项目冲突,合理分配场地资源。
  • 数据分析大屏: 使用更强大的可视化工具,为管理者提供实时数据决策支持。
Logo

一站式 AI 云服务平台

更多推荐