尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

校园台球厅管理系统源码解析:Spring Boot+Vue前后端分离实践

校园台球厅管理系统源码解析:Spring Boot+Vue前后端分离实践 简介基于Spring Boot和Vue的校园台球厅管理系统完整源码面向计算机相关专业正在准备毕业设计的学生以及需要项目实战练习的开发者可直接作为毕业设计、课程设计或期末大作业使用。压缩包内共806个文件大小约17.08MB包含Java后端源码、Vue前端组件、JS交互逻辑、CSS页面样式、SVG图标及GIF演示图片等多种类型前后端代码结构清晰相关配置文件与运行脚本齐全。该项目已有123人学习参考核心功能涵盖台球厅日常运营管理场景可作为高分毕业设计的参考范本。源码经过严格调试附带详细的运行脚本和部署配置便于本地快速启动与二次开发能够帮助学习者深入理解Spring Boot与Vue的前后端分离架构以及实际业务模块的完整实现流程。1. 校园台球厅管理系统Spring Boot 后端、Vue 前端以及那一堆 .bak 文件校园台球厅管理系统Spring Boot 后端、Vue 前端表面看是场地预约、会员充值和订单核销的 CRUD 项目。真正拆开才发现难点不在台球业务而是前后端接口约定。作为 98 分毕设这套源码的最大价值不是“能跑”而是给你一份完整骨架后端用 springboot 框架提供接口前端用 vue 框架做后台管理页面压缩包里的 .bak 备份文件恰好记录了作者改动前后的差异。适合作基于 springboot 的 java 毕设、课程设计或者想梳理 vue 路由与 Spring Boot 关系的同学。2. 从路由到接口Spring Boot 与 Vue 是怎么咬合的拿到源码先看前端不要直接双击 2-run.bat。前端目录里IndexMain.vue、IndexAsideStatic.vue、BreadCrumbs.vue、IndexHeader.vue这几个文件名已经把后台系统的布局拆开说明了主框架、侧边栏、面包屑、顶栏。IndexMain.vue是父组件里面会留一个router-view/router-view所有业务页面都挂在它下面。所谓 vue 路由参数本质就是通过路由对象把菜单点击和页面组件绑到一起。2.1 主框架 嵌套路由页面才会跟着菜单走常见的新手写法是把所有页面都写成独立页面菜单切换用 v-show 控制显隐稍微专业一点的项目会用 vue-router 的嵌套路由。这套源码更接近后者。IndexMain.vue作为布局组件children数组里每一项对应一个页面。下面是我按常见工程补出来的最小路由配置字段含义和源码里一致// router/index.js import Vue from vue import Router from vue-router import IndexMain from /views/IndexMain.vue Vue.use(Router) const router new Router({ // 用 hash 模式后面会解释为什么这样选 mode: hash, routes: [ { path: /, component: IndexMain, redirect: /home, children: [ { path: home, name: Home, component: () import(/views/Home.vue) }, { path: sys/updatePassword, name: UpdatePassword, component: () import(/views/sys/update-password.vue) } ] }, { path: /login, name: Login, component: () import(/views/Login.vue) } ] }) export default router路由配置里mode: hash这个选择在毕设答辩时很有说头。hash 模式 URL 里带#例如http://localhost:8080/#/sys/updatePassword后端不需要任何转发规则history 模式虽然看起来更干净但打包后放到 Spring Boot 的 static 目录刷新页面时后端不认识/sys/updatePassword这个路径会直接 404。下表把两者差异给老师讲清楚比背稿件有效对比项hash 模式history 模式URL 示例http://localhost:8080/#/sys/updatePasswordhttp://localhost:8080/sys/updatePassword后端部署springboot static 直接可用需要配置 forward 到 index.html刷新行为始终加载 index.html刷新时可能 404适用场景单体部署、毕设项目Nginx 接管路由的正式环境IndexMain.vue里的子组件IndexAsideStatic.vue负责渲染左侧菜单BreadCrumbs.vue读取当前路由的meta字段生成面包屑IndexHeader.vue显示用户信息。菜单点击后通常调用this.$router.push({ path: item.path })对应的嵌套路由组件就会被替换到router-view里。这个链路清晰以后再来看后端接口就不会乱。2.2 后端接口路径与前端调用的约定前端页面和接口不是“一个页面对应一个接口”的关系。一个页面可能同时调场地列表、当前时间是否可预约、会员余额三个接口反过来一个接口也可能被多个页面复用。后端只需要提供 RESTful 风格的 Controller。这套系统里常见的功能模块包括场地管理、会员管理、订单管理、台球桌计费所以 Controller 一般会按UserController、TableController、OrderController拆开。下面是一个典型的“修改密码”接口写法也呼应了压缩包里那个update-password.vue.bak备份文件RestController RequestMapping(/api/user) public class UserController { Autowired private UserMapper userMapper; PostMapping(/updatePassword) public ResultBean updatePassword(RequestBody PasswordDto dto, RequestHeader(Authorization) String token) { Integer userId JwtUtil.parseToken(token).get(userId, Integer.class); User user userMapper.selectById(userId); if (!MD5Util.verify(dto.getOldPassword(), user.getPassword())) { return ResultBean.error(旧密码不正确); } user.setPassword(MD5Util.encode(dto.getNewPassword())); userMapper.updateById(user); return ResultBean.ok(); } }RequestBody PasswordDto dto表示前端把一个 JSON 对象反序列化成 DTO 对象字段名必须和前端提交的oldPassword、newPassword一致。RequestHeader(Authorization) String token是读取请求头里的登录令牌由登录接口下发后续每个需要身份的接口都会带上。毕设项目里常用JwtUtil负责生成和解析 token用MD5Util做密码加密工具类一般放在utils包或common包自己补一个也可以。后端返回给前端的结构通常是ResultBean里面至少有三个字段code、msg、data。code为 0 表示成功非 0 表示业务错误。前端在 axios 拦截器里统一判断就不需要在每个组件里重复写if (res.data.code 0)的细节。3. 拿到源码第一步理清 .bak 文件、bat 脚本和运行顺序很多人在后台私信问“为什么源码里有一堆.bak文件是不是环境坏了”。这是误解。.bak是备份文件说明作者在改IndexMain.vue、update-password.vue之前都先保留了一份旧版本。index.html.bak是入口 HTML 的旧版.classpath表示这个工程曾经用 Eclipse 打开过。IDEA 或 VS Code 打开时会忽略.classpath不影响运行。3.1 用 diff 把 .bak 文件当成“变更记录”看如果怕改坏就把.bak复制一份改名然后对比新旧内容。在 Windows 下可以用fc在 macOS / Linux 下用diff# 对比修改密码页面新旧版本 diff update-password.vue.bak src/views/sys/update-password.vue # 对比主布局新旧版本 diff IndexMain.vue.bak src/views/IndexMain.vuediff 输出的表示左边文件有的行表示右边文件有的行。重点看三处接口地址有没有变、提交的字段名有没有变、组件引用路径有没有变。很多“项目跑起来后页面白屏”的问题其实就出现在有人直接把.bak文件拖到 src 目录文件名带.bakVue 编译器根本不会解析它。3.2 三个 bat 脚本安装、运行、构建压缩包里通常会有1-install.bat、2-run.bat、3-build.bat。下面按前后端目录结构为frontend/backend的常见工程写出示例实际目录名不同就把路径替换掉。1-install.bat负责第一次拉依赖echo off REM 首次运行安装前端依赖和后端依赖 cd frontend call npm install cd ..\backend call mvn clean install -DskipTests pausecall很关键。如果在批处理脚本里直接写npm install执行完会直接退出不会继续跑后面的mvn加上call才会回到脚本继续往下走。-DskipTests跳过测试避免拉完依赖后还要等测试编译。2-run.bat是开发模式启动脚本echo off REM 开发模式前端 8080后端 8081 cd frontend start cmd /k npm run serve cd ..\backend start cmd /k mvn spring-boot:run pausestart cmd /k会新开一个命令行窗口执行命令关闭这个窗口才停止进程。前端跑npm run serve后端跑spring-boot:run。前端页面地址是http://localhost:8080后端接口地址是http://localhost:8081。3-build.bat负责把前端打包产物塞进后端静态目录最终可以用 Spring Boot 打成单 jarecho off REM 前端打包并复制到后端 static 目录 cd frontend call npm run build xcopy /Y /E dist\* ..\backend\src\main\resources\static\ cd ..\backend call mvn clean package -DskipTests pausexcopy /Y /E的/Y表示遇到同名文件直接覆盖/E表示复制子目录。打包完成后后端src/main/resources/static下会出现index.html和js/css目录再执行java -jar xxx.jar就能用单端口访问页面和接口。这个部署方式对课程设计和毕设答辩都很友好因为现场只需要演示一个 jar。3.3 数据库配置与前端代理后端跑起来前必须改数据库连接。通常项目里会有application.yml或application.properties核心配置如下server: port: 8081 spring: datasource: url: jdbc:mysql://localhost:3306/billiard?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456注意url里的库名是billiard你本地 MySQL 里创建同名库即可。如果报名带 SQL直接导入没带 SQL 就需要根据实体类建表。serverTimezoneAsia/Shanghai是为了避免 MySQL 8 的时区报错如果你的 MySQL 配置不同改成serverTimezoneUTC也可以。前端开发模式下还需要一个代理否则页面在 8080接口在 8081跨域会拦掉请求。在vue.config.js里写module.exports { devServer: { port: 8080, proxy: { /api: { target: http://localhost:8081, changeOrigin: true } } } }changeOrigin: true会让后端以为请求来自 8081避免 Origin 校验失败。前端所有请求都写相对路径/api/user/updatePassword这样的形式由代理转发到后端不要写死http://localhost:8081不然打包部署后还得一个个改。4. 实战改造以 update-password.vue 为模板把“改密码”做成可答辩的功能改密码是一个很好的切入点。它涉及前端表单校验、后端参数校验、token 身份识别、旧密码比对四件事答辩时老师几乎必问。最怕的回答是“前端把新密码直接 post 上来就完了”那样暴露不了你的工程思维。正确的做法是前端先做交互校验后端再做一次防御校验。4.1 Vue 页面校验在前请求在后update-password.vue的页面结构一般是 el-form 加两个密码输入框Element UI 的校验规则写在data()里。下面是一个可以拿来抄的版本template div classupdate-password el-form :modelpwdForm :rulesrules refpwdForm label-width100px el-form-item label原密码 propoldPassword el-input v-modelpwdForm.oldPassword typepassword/el-input /el-form-item el-form-item label新密码 propnewPassword el-input v-modelpwdForm.newPassword typepassword/el-input /el-form-item el-form-item el-button typeprimary clicksubmit保存/el-button /el-form-item /el-form /div /template script export default { data() { return { pwdForm: { oldPassword: , newPassword: }, rules: { oldPassword: [{ required: true, message: 请输入原密码, trigger: blur }], newPassword: [ { required: true, message: 请输入新密码, trigger: blur }, { min: 6, max: 20, message: 新密码长度为 6 - 20 位, trigger: blur } ] } } }, methods: { submit() { this.$refs.pwdForm.validate((valid) { if (!valid) return this.$http.post(/api/user/updatePassword, this.pwdForm) .then(res { if (res.data.code 0) { this.$message.success(密码已更新) } else { this.$message.error(res.data.msg) } }) }) } } } /scriptthis.$refs.pwdForm.validate是 Element UI 内置的表单校验方法只有全部字段通过后才发请求。this.$http通常是 axios 挂载到 Vue 原型上的写法例如Vue.prototype.$http axios。前端字段名必须是oldPassword、newPassword不要改成old_password这种下划线风格因为后端 DTO 属性是驼峰格式Jackson 反序列化时对不上就是 null。4.2 后端 DTO 与参数校验把“接口能通”升级为“接口能防”只靠前端校验不够Postman 里绕开页面直接 POST空密码也能进来。所以后端要加javax.validation的注解。我一般会单独建一个PasswordDto而不是用 Map 接收参数public class PasswordDto { NotBlank(message 原密码不能为空) private String oldPassword; NotBlank(message 新密码不能为空) Size(min 6, max 20, message 新密码长度须在 6 到 20 位之间) private String newPassword; // getter / setter }然后在控制器方法参数上加Validpublic ResultBean updatePassword(Valid RequestBody PasswordDto dto, RequestHeader(Authorization) String token)NotBlank负责空格被当作空处理Size负责长度限制。这样即使请求里newPassword传一个空串也会在进入业务代码之前被拦截返回参数错误提示。常见校验注解如下注解作用使用位置NotBlank字符串不能为 null 且去空格后非空String 字段Size(min, max)长度范围集合、字符串、数组Valid触发对 DTO 内部字段的校验控制器参数RequestHeader从请求头取值控制器方法参数写完接口后用 curl 或者 Postman 做一次最小验证能直接暴露字段名问题curl -X POST http://localhost:8081/api/user/updatePassword \ -H Content-Type: application/json \ -H Authorization: Bearer token \ -d {oldPassword:123456,newPassword:abc123}如果后端返回 code 0说明前端页面调用也能走通如果返回参数错误先检查 DTO 字段名再检查 JSON 键名最后看后端日志里的HttpMessageNotReadableException。5. 进阶技巧用 .bak 快照对比做侧边栏接口化避免构建后布局异常5.1 从静态菜单改成接口驱动菜单IndexAsideStatic.vue.bak的名字里带 “Static”说明旧版侧边栏菜单是写在组件里的静态数组。毕设如果想加分可以把菜单改成由后端返回前端只负责渲染。操作步骤很简单把IndexAsideStatic.vue.bak复制成IndexAsideStatic.vue先恢复到一个确定能运行的状态。在data()里找到menuList原来是写死的对象数组。把mounted()里的静态赋值替换成接口请求mounted() { this.$http.get(/api/menu/list).then(res { if (res.data.code 0) { this.menuList res.data.data } }) }后端返回的数组字段必须和原来静态数组保持一致否则 el-menu 渲染不出来。比如原来每一项有path和title返回格式就是[{ path: /home, title: 场地管理 }]。点击菜单时组件内部会执行this.$router.push(item.path)如果字段名对不上会拿到 undefined页面不跳转但不报错这是最难排查的一类问题。5.2 构建后布局异常和刷新白屏的处理很多同学跑完3-build.bat后用 jar 启动发现页面能开但样式全丢了或者刷新二级页面直接白屏。这不是代码 bug而是静态资源路径问题。默认 vue-cli 构建出来的index.html会引用/js/app.js这种绝对路径Spring Boot 部署在根路径时没问题一旦加了 context-path 或部署到子目录资源就 404。解决办法是在vue.config.js里加一行module.exports { publicPath: ./ }publicPath: ./会把资源引用改成相对路径打包后index.html里的引用变成./js/app.js部署在任意二级目录都不会出现布局异常。刷新白屏则要确认路由是不是 history 模式如果确实要保留 history就需要在后端加一个转发 Controller把非接口请求转发到index.html。对于这套项目最省事的方案是mode: hashhash 刷新天然不会触发 404把这项工作放到答辩演示前一个小时再动风险最小。本文还有配套的精品资源点击获取
返回列表