简介这份资源面向计算机专业毕业设计、课程设计与Java实战学习者使用Spring Boot、MySQL与Vue技术栈构建校园竞赛管理系统。系统覆盖用户管理、竞赛发布、参赛报名、成绩管理、成绩统计与自动分析等完整业务环节学校可便捷发布各类竞赛信息并管理参赛学生学生可查看赛事、在线报名并实时查询个人成绩。压缩包整体约27.36MB内含项目源代码、SQL初始化脚本与毕业论文参考文档目录结构按后端、前端、数据库等模块划分便于按需阅读、运行和二次开发。开发环境配置简便项目可正常运行配套论文为撰写毕业设计报告提供理论支撑与章节参考。目前已有54人学习下载适合用于毕设成果展示也适合初学Spring Boot和Vue的开发者作为完整课设项目练习在现有代码基础上扩展更多个性化功能。1. 这套SpringBootVue校园竞赛管理系统不只是一份能交差的毕设套件拿下一份SpringBootVue的毕设源码第一件事不是打开论文而是把后端跑起来。校园竞赛管理系统这类课设项目基本盘就三块竞赛发布、在线报名、评委打分再加一套后台管理页面。听起来不难真从零写要耗掉大量时间在前后端联调上。这份资源里源码、SQL、毕业论文都齐适合毕业设计、课程设计和大作业场景。我拆完后的判断是它能让你绕开从空项目搭建到联调的大部分弯路直接进入业务改造阶段这是它最值钱的地方。2. 后端骨架把SpringBoot的分层结构和MyBatis写法摸清楚我接手别人的SpringBoot项目第一步从来不是急着跑而是先看目录和配置。这套竞管系统的后端是标准SpringBoot分层结构controller / service / mapper / entity绝大多数课设项目都长这样。你拿到压缩包解压后先找application.yml把数据源改成自己的账号密码再建库导SQL启动类一跑后端就算活了。springboot配置看着繁琐其实关键就五个参数端口、数据源、驱动、MyBatis映射路径、编码。2.1 工程结构先分清哪些文件是“要看的”后端目录长这样competition-backend/ ├── src/main/java/com/example/competition/ │ ├── controller/ # 接口层接收前端请求 │ ├── service/ # 业务逻辑层写事务和判断 │ ├── mapper/ # MyBatis接口只写方法签名 │ ├── entity/ # 数据库实体字段对应表 │ ├── config/ # 拦截器、跨域配置 │ ├── common/ # Result封装、JwtUtil等工具 │ └── CompetitionApplication.java # 启动入口 ├── src/main/resources/ │ ├── mapper/ # MyBatis XMLSQL全在这里 │ └── application.yml # 核心配置 └── sql/ └── competition.sql # 建库建表脚本含基础数据这个结构里你最该先读的是application.yml和sql目录下的脚本。controller层只是转发真正的业务判断在serviceSQL在XML里。很多学弟学妹拿到源码喜欢直接找controller看着一堆接口不知道从哪入手——正确顺序是先看数据库表知道系统里有哪些数据再看mapper XML知道每个接口怎么查数据最后回来看controller把接口和前端页面一一对应。这套顺序对于课设项目足够用毕竟表数量一般不超过十张。2.2 application.yml数据源配置的几个关键参数大多数毕设项目用的是MySQL 8.x Spring Boot 2.x。常见的配置长这样server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/competition?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.competition.entity注意serverTimezoneAsia/Shanghai这个参数。MySQL 8.x 对时区敏感不写会直接报时区错误useSSLfalse是本地开发关闭SSL证书校验不然控制台会刷一堆证书警告。驱动类名必须是com.mysql.cj.jdbc.DriverMySQL 5.x 时代用的com.mysql.jdbc.Driver在8.x下会直接失灵。password一定要换成你自己的数据库密码这地方是启动报错的第一高发点。如果你学校要求的是SQL Server而不是MySQL改法是驱动类换成com.microsoft.sqlserver.jdbc.SQLServerDriverurl换成jdbc:sqlserver://localhost:1433;DatabaseNamecompetition分页和自增ID写法要跟着改这是后话课设场景里MySQL占了绝大多数。2.3 MyBatis XML里的两个细节where标签和物理分页这套项目里的SQL基本都写在resources/mapper目录下。拿竞赛列表查询举例典型写法是select idselectPageByCondition resultTypecom.example.competition.entity.Competition SELECT id, title, description, signup_start_time, signup_end_time, status, max_people FROM competition where if testtitle ! null and title ! AND title LIKE CONCAT(%, #{title}, %) /if if teststatus ! null AND status #{status} /if /where ORDER BY create_time DESC LIMIT #{offset}, #{pageSize} /selectwhere标签会自动去掉第一个条件前面的AND不用自己拼字符串这是避免SQL拼接错误的最稳做法。LIKE CONCAT(%, #{title}, %)用CONCAT拼接模糊查询参数防止SQL注入比直接字符串拼接安全得多。LIMIT #{offset}, #{pageSize}是MySQL的物理分页offset是偏移量pageSize是每页条数计算规则在service层完成。这套手写XML的方案和MyBatis-Plus的selectPage相比优势是SQL完全可见答辩时老师问“这个查询怎么实现的”你能指着XML一行行讲清楚。缺点是每张表都要写count和list两个方法。很多毕业设计项目直接在service层调selectList不做分页数据少时没问题数据一多页面就卡。建议自己项目里至少把公告、竞赛、报名这三块高频列表做成物理分页。2.4 Service层的分页计算与Result封装Override public Result getCompetitionPage(int page, int size, String title) { int offset (page - 1) * size; ListCompetition list competitionMapper.selectPageByCondition(title, offset, size); int total competitionMapper.countByCondition(title); return Result.ok(list, total); }分页计算就一行公式offset (page - 1) * size。前端传过来的page从1开始数据库里的offset从0开始不换算的话第一页永远查不到数据。countByCondition单独写一个查询统计总数是为了给前端的分页组件用——前端要拿到total才能渲染总页数。我见过一些项目把count和list写在一条SQL里用子查询课设场景没必要拆开写逻辑更清晰。Result封装建议统一为code / message / data / total四个字段前后端对接时少很多争吵。3. 前端链路Vue2工程从安装依赖到接口联调的完整复现后端跑通只是第一步课设项目真正耗时间的是前端。这套系统前端是Vue2 Element-UIvue安装及环境配置本身就有不少坑更别提node版本和依赖安装的兼容性问题。3.1 环境准备Node版本、npm换源、依赖安装拿到前端工程先看package.json确认vue和element-ui的版本再决定用哪个Node版本。常见做法是node -v npm config get registry npm config set registry https://registry.npmmirror.com npm install npm run serve第一行确认Node版本Vue CLI 4.x建议用Node 14Vue CLI 5.x用Node 16或者18也能跑。如果你直接拿Node 20去跑老项目大概率会在node-sass这一步报错原因是node-sass需要下载对应Node版本的二进制文件新版本Node没有预编译包。第二行看registry是不是默认源国内环境强烈建议换成npmmirror否则npm install会卡在等待上。安装完成后跑npm run serve默认端口8081浏览器打开就能看到登录页。这里有个常被忽略的点npm install弹出的警告里高优先级要留意node-sass和sass-loader的版本匹配。如果装的是node-sass建议直接换成sasssass-loader10代码里写法几乎一样但兼容性好很多这是省时间的做法。3.2 vue.config.js代理转发解决跨域前端页面在8081端口后端接口在8080端口端口不同就有跨域问题。单页应用开发期最省事的方案是代理转发// vue.config.js module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } }意思是前端所有以/api开头的请求都转发到后端的8080端口pathRewrite把/api前缀剥掉。举个实际例子前端请求/api/competition/list经过这个配置后端收到的实际地址是/competition/list。如果后端项目的controller里定义了RequestMapping(/api/competition)那这里就不需要pathRewrite直接透传。联调时接口404八成就是前端路径和后端路径没对齐。你自己改项目的时候建议统一用/api做前缀后面接模块名这样代理和后端都一目了然。3.3 axios封装请求拦截器帮你带上token前端状态管理对课设来说不需要vuex也行但axios请求封装强烈建议保留。它负责两件事请求发出去之前带上token收到错误响应时统一处理。// request.js import axios from axios const service axios.create({ baseURL: /api, timeout: 10000 }) service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config }) service.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { localStorage.removeItem(token) window.location.href /login } return Promise.reject(error) } )baseURL: /api和vue.config.js里的代理前缀是配套的timeout: 10000表示10秒内没拿到响应就判定超时。请求拦截器做成每一处axios.get调用时自动拼接登录态不用每个接口手动传header。401统一跳登录页是常见约定后端拦截器返回401时前端能自动清理失效的登录态。这套封装在几个管理类毕业设计之间是通用的你把它复制到另一个Vue项目里只需要改baseURL和登录跳转路径。3.4 vue router路由meta控制页面访问权限路由配置建议加meta字段后续做权限控制都在这里展开// router/index.js const routes [ { path: /login, component: () import(/views/Login.vue) }, { path: /, component: () import(/layout/Layout.vue), redirect: /dashboard, children: [ { path: competition, component: () import(/views/competition/CompetitionList.vue), meta: { title: 竞赛管理, requireAuth: true, roles: [admin, teacher] } } ] } ]component: () import(...)是路由懒加载页面被访问时才加载对应js文件首屏会快很多。meta里塞了两个自定义字段requireAuth表示这个页面需要登录才能看roles表示哪些角色可以看。路由参数通过this.$route.query或者this.$route.params读取这两者是vue-router面试题里的高频考点query对应?id1刷新页面参数还在params对应/detail/1配合动态路由path: detail/:id使用刷新也不会丢。竞赛详情页这种需要传ID的场景建议用动态路由params。4. 登录与权限JWT拦截器和前端路由守卫怎么配合登录模块是答辩时老师最爱问的部分。先明确一个底层逻辑后端拦截器保证接口安全前端路由守卫只负责体验优化——真正的权限控制永远在后端。现在springboot源码里JWT方案很常见核心就两块后端签发和校验token前端存token并在请求头带上。4.1 后端JWT工具类签发与验签的参数怎么定JWT的常见实现依赖io.jsonwebtoken这个库工具类核心代码长这样public class JwtUtil { // 实际项目中请改成你自己的随机字符串至少32位 private static final String SECRET competition-demo-secret-key; private static final long EXPIRE 1000L * 60 * 60 * 24; public static String createToken(Integer userId, String role) { return Jwts.builder() .claim(userId, userId) .claim(role, role) .setExpiration(new Date(System.currentTimeMillis() EXPIRE)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody(); } }EXPIRE设置成24小时是管理系统的常见选择太短会让评委体验中断太长有安全风险。claim(role, role)把角色塞进token前端路由守卫里判断roles时读取的就是这里的值。signWith(SignatureAlgorithm.HS256, SECRET)指定签名算法是HS256SECRET是服务端私钥泄露了别人就能伪造token。答辩如果被问到“token被人偷了怎么办”可答合理设置过期时间后端可以维护token黑名单课设里写到这层已经足够。有了工具类拦截器负责校验public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token null || token.isEmpty()) { response.setStatus(401); return false; } try { Claims claims JwtUtil.parseToken(token); request.setAttribute(userId, claims.get(userId)); request.setAttribute(role, claims.get(role)); return true; } catch (Exception e) { response.setStatus(401); return false; } } }拦截器从请求头取Authorization字段前端axios封装里设置的header名必须和这里一致否则token传了也验不到。验签成功把userId和role塞进request属性后续controller里直接取不用再解析一次。注册拦截器时登录接口、验证码接口要排除掉配置放行的路径一般长这样registry.addInterceptor(new AuthInterceptor()) .addPathPatterns(/api/**) .excludePathPatterns(/api/auth/login, /api/auth/register);4.2 前端路由守卫和按钮权限体验层的最后一道闸后端接口安全有保障后前端要解决“未登录用户看不到页面”和“不同角色看到不同按钮”两个问题。第一个用路由守卫router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requireAuth !token) { next(/login) } else if (to.path /login token) { next(/) } else { next() } })这段逻辑是目标页面要求登录但本地没token踢回登录页已经登录了还反复点登录页直接送去首页。注意不是每个路由都要写requireAuth登录页、404页面不需要。按钮级别的控制更简单在模板里根据登录时存下来的角色判断el-button v-ifuserInfo.role admin typedanger删除竞赛/el-button这个v-if是纯前端展示逻辑删不了也没关系——因为后端接口还有拦截器校验身份。答辩时建议把这个链路讲清楚登录成功后后端返回token和userInfotoken存localStorageuserInfo存vuex或sessionStorage每次请求axios带上token后端拦截器验token前端路由守卫加一层页面跳转。一条线讲下来老师基本挑不出毛病。5. 避坑合集环境版本、跨域、SQL导入的五条翻车记录这部分我把自己在跑同类毕设项目时踩过、也见过学弟学妹反复踩的坑集中列出来。每条都是现象、原因、解决三连对应环境配置、数据库、联调三个阶段。5.1 环境三连坑JDK版本、Node版本、MySQL版本现象1后端启动直接报错日志显示java.lang.UnsupportedClassVersionError。原因是本机JDK版本太高项目编译版本是JDK 8你拿JDK 17去跑class文件版本不认识。解决装一个JDK 8或者用IDE里切换Project SDK如果是命令行启动改JAVA_HOME环境变量不要用SDKMAN之类的工具来回切。这类毕设源码十有八九是JDK 8编译的直接装JDK 8最省事。现象2前端npm install报node-sass安装失败一串红色错误。原因是node-sass要从GitHub下载对应Node版本的二进制文件国内网络经常失败而且新版Node根本没有对应版本。解决把package.json里的node-sass替换成sasssass-loader版本降到10.x然后删掉node_modules和package-lock.json重新install。如果不想动代码就用nvm把Node切换成14.x再装两条路都行。现象3后端启动报Access denied for user rootlocalhost。原因太直白application.yml里的密码和本机MySQL不一致。解决改配置文件里的password为你自己的密码如果MySQL确实没设密码把password留空字符串password:即可。别小看这条十个提问里有三个是卡在这里。5.2 数据库导入的坑编码、外键和时区现象4SQL脚本导入后网页上中文全是乱码。原因是SQL文件本身是UTF-8编码但导入时数据库连接或表默认字符集不是UTF-8。解决建库时显式指定create database competition default charset utf8mb4 collate utf8mb4_general_ci;。Navicat导入时工具栏里选择“UTF-8”编码再执行。utf8mb4比utf8多支持emoji和生僻字现在MySQL 8.x的默认字符集已经是utf8mb4老脚本里如果写的是utf8建议顺手改成utf8mb4。现象5数据导入时报外键约束错误或者某张表导不进去。原因是脚本里表之间有关联比如报名表引用竞赛表ID、成绩表引用用户ID你一股脑全选执行外键引用不到父表就报错。解决拆分执行顺序先导基础表用户、角色再导业务表竞赛、公告最后导关联表报名、评分。如果脚本里用了SET FOREIGN_KEY_CHECKS0导入前手动执行这一句也能临时关闭外键检查但要有意识知道数据完整性可能受影响。5.3 联调阶段的跨域和路径问题现象6前端启动后登录页能打开点登录按钮浏览器控制台报跨域错误CORS。原因是前端的8081页面请求后端的8080接口浏览器同源策略拦截了响应。解决有两种优先在vue.config.js里配代理前端代码里所有请求走/api前缀后端也可以加CorsFilter允许跨域但课设项目建议用代理方案改动小且能顺路解决后续的cookie携带问题。两者不要同时用代理还报跨域说明请求没有走devServer可能baseURL写死了http://localhost:8080把它改回/api就行。现象7本地测试一切正常打包部署到服务器后刷新页面404。原因是vue-router默认的history模式需要服务器把所有路由都重写到index.htmlNginx上写try_files $uri $uri/ /index.html;才能解决。不想折腾服务器配置的话把路由模式改成hash地址栏带个#符号刷新不会404但URL看起来不够干净。毕业设计演示通常都在本地用hash模式是最稳的演示到一半页面刷新不丢路由这个细节很加分。6. 答辩前的最后一把初始化数据与演示顺序的实用技巧顺利跑通项目只是开始答辩演示时手忙脚乱才是真正的翻车点。这里分享两个我固定使用的技巧。6.1 准备一份“重置数据”脚本到答辩前系统里可能已经被你测试时灌满了乱七八糟的数据竞赛名称叫“测试”和“111”。我习惯在sql目录里额外保留一份reset_demo_data.sql-- 重置管理员密码为你自己设置的密码防止演示时忘记了 UPDATE sys_user SET password $2a$10$... WHERE username admin; -- 清理测试垃圾数据保留几条结构完整的演示数据 DELETE FROM score WHERE id 20; DELETE FROM competition_signup WHERE id 30; DELETE FROM competition WHERE id 5; -- 把竞赛状态重置为“报名中”演示报名流程时不会报已截止 UPDATE competition SET status 1 WHERE status 2;演示前执行一遍系统回到一个体面的初始状态。密码字段里如果是BCrypt或MD5直接UPDATE新值需要先算出加密结果稳妥做法是从注册接口注册一个新账号把那条记录的密码哈希复制过来。别把测试数据留给评委看第一印象差很多。6.2 演示顺序从登录到闭环讲清角色流现场演示建议按“管理员创建竞赛 → 学生报名 → 评委打分 → 查看排名”这条线走一条线覆盖你系统的全部核心功能。真正值得反复练的是切换角色时的讲解词——退出登录重新登录一定要说清楚“这是因为不同角色看到的功能不一样”这句话能把权限设计的亮点自然带出来。从那以后我每次经手带答辩的项目都会强制走一遍这条流程重置数据、切三个角色完整跑一遍流程、刷新一次页面确认路由没垮、最后关掉后端重启确认没有依赖本地状态。项目能跑不算完能经得起现场任何一次点击才算稳。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
HG680-LC刷机实战:S905L3B安卓9线刷教程与避坑指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:35:48
小米相机包移植指南:徕卡/原生相机Magisk模块挂载与签名处理 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:35:48
Xiuno Light v3.3 主题安装与优化:从部署到移动端适配 简介:Xiuno Light(修罗轻鸿)v3.3 是修罗论坛推出的最新升级版主题程序,定位为面向论坛站长与管理员的高性价比建站方案。该版本围绕功能定制、性能优化、安全加固和移动端体验提升展开,适合希望增强论坛互动性、扩展性… · 2026/9/25 1:35:48
坚瓷建材性价比怎么样 装修过房子的人,大概都记得这样的时刻:瓷砖铺完了,缝隙却成了心病。浅色美缝用了半年,阳台一晒就泛黄;师傅施工到一半,发现一组料只能打十几米,耗材一加再加;出了问题想找厂家,电话那头却始终无… · 2026/9/25 2:50:50
百托帮GEO服务在全国市场的表现如何 顺应流量迁徙趋势,锚定行业发展使命随着数字经济的深度渗透,线上获客已经成为企业经营发展的核心命题。从早期的搜索引擎营销,到短视频时代的内容种草,再到当下AI搜索的异军突起,用户获取信息与商业服务的路径正在发生… · 2026/9/25 2:50:50
2026人才测评工具免费权威合集TOP10(收藏备用) 一、为什么企业选型越来越看重测评工具人才决策的容错空间正在收窄。业务节奏加快,岗位需求变化频繁,仅凭面试印象和履历判断,很难稳定识别高潜力人才。测评工具的核心价值在于把隐性特质显性化——动机、价值观、行为倾向、风险因素… · 2026/9/25 2:50:50
jc 解析器 proc_mtrr:把 /proc/mtrr 的 MTRR 内存类型信息结构化输出为 JSON 开发工具 【免费下载链接】jc CLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.… · 2026/9/25 2:50:50
长沙雨花跨境电商招商公司推荐 广受信赖服务商合作实力参考 在长沙雨花想做跨境电商创业,不少新手创业者都会纠结几个核心问题,比如本地有没有靠谱的跨境电商招商公司可以合作?怎么判断一家跨境电商招商服务商的实力够不够?想要做跨境电商零基础入门,找专业陪跑孵化服务商到底有没有必要?接下来我们… · 2026/9/25 2:50:44
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37