高校请假管理系统这类课题,在 Java 毕业设计和课程设计里出现频率一直很高。071 编号通常说明它来自一套毕设课题库,核心定位是“前后端分离 + 流程审批 + 角色权限”,技术栈从标题就能看出来:SpringBoot 提供后端接口服务,Vue3 构建前端业务页面。这类项目真正值得关注的地方不是某个高深算法,而是能不能把一张请假单从学生申请、逐级审批、销假归档的完整链路跑通,同时把 SpringBoot、Vue3、MySQL 之间的工程化连接讲清楚。
这篇文章不会只停留在概念层面。我会从核心功能、角色边界、数据库表结构设计、后端启动方式、前端开发代理、接口联调、功能验收用例到常见问题排查,完整拆开这套高校请假管理系统。如果你正准备做同类型毕设,或者想找一个“前端 Vue3 + 后端 SpringBoot”的业务管理系统来练手,这篇内容可以直接当部署和开发路线图用。为了避免误导,所有代码和配置都采用工程模板形式,实际项目中的表名、字段、接口路径需要以你自己拿到的源码工程为准。
1. 高校请假管理系统核心能力速览
先看这个项目能做什么、门槛在哪里。高校请假管理系统的业务范围并不宽,核心是让几类用户在一个 Web 系统里完成请假流程闭环。下面表格把这套系统的主要能力列出来:
| 能力项 | 说明 |
|---|---|
| 项目类型 | 前后端分离的 Java Web 业务管理系统 |
| 后端技术 | SpringBoot、Spring MVC、MyBatis/MyBatis-Plus、MySQL |
| 前端技术 | Vue3、Vite、Vue Router、Pinia、Element Plus 等 |
| 核心角色 | 学生、教师/辅导员、院系或系统管理员 |
| 核心功能 | 请假申请、审批流、销假归档、请假类型管理、统计导出 |
| 部署模式 | 后端独立服务 + 前端独立开发服务器,通过 HTTP 接口联调 |
| 接口风格 | RESTful JSON,最常见的路径前缀为 /api |
| 登录鉴权 | Token 方式比较普遍,常见做法是 JWT 或 Sa-Token |
| 批量能力 | 业务上以单条流程为主,可扩展批量导入导出 |
| 适合场景 | 毕业设计、课程设计、前后端分离入门训练 |
| 学习门槛 | 需要掌握 SpringBoot 基础、Vue3 基础、MySQL 查询 |
这个项目本质上是一个典型的“RBAC 权限模型 + 状态机流转”系统。学生在页面发起请假申请,单据进入待审批列表;教师或者辅导员看到待办后可以同意、驳回或者补充意见;学生销假后,流程进入归档状态。管理员主要维护请假类型、查看学院请假统计。整套流程覆盖了一个业务管理系统的多数通用组件:用户认证、角色权限、增删改查、流程状态管理、Excel 导出、图表统计。因此它不只是“请假系统”,更是理解 SpringBoot 和 Vue3 怎么配合工作的极好样例。
对于硬性门槛,可以放心:项目不依赖高配服务器,普通的 Windows 笔记本、8GB 内存、本地安装 JDK、Maven、Node.js、MySQL 就能跑起来。如果使用 SpringBoot 3.x,JDK 要用 17 以上;如果使用 SpringBoot 2.7.x,JDK 1.8 也可以。具体以项目 pom 文件和 package.json 里的 engines 为准,这是配置环境前第一步要看的东西。
2. 适用场景、功能模块与业务边界
2.1 适合谁使用
高校请假管理系统的定位很明确。第一类用户是计算机相关专业学生,需要完成毕业设计或者课程设计,课题形式是“请假管理”“OA 系统”“教学管理系统”的变体。第二类用户是想以项目带学习的前端开发者,想搞清楚 Vue3 的登录态、路由守卫、Axios 请求封装和后端接口到底怎么配合。第三类用户是高校内做流程演示或者教学实验的师生,希望在本地搭建一套可运行的流程演示系统。
从答辩和演示角度看,这套系统最大的优势是业务好讲。不需要解释复杂的算法逻辑,只需要按着“学生提交假期申请 -> 教师审批 -> 学生销假 -> 管理员查统计”这条主线走一遍,评审老师就能理解系统价值。对于学习者来说,流程状态字段的取值变化就是最重要的业务逻辑主线。
2.2 功能模块拆解
一个常见的高校请假管理系统会分成三个端,但从工程角度看,可以拆成“认证中心”“请假业务”“权限管理”“统计导出”四个模块。
学生端功能包括:登录、修改个人信息、创建请假申请、查看我的申请记录、查看审批进度、撤销未审批的申请、填写销假信息。教师端功能包括:登录、查看待审批列表、审批学生的请假申请、填写审批意见、查看已审批记录、按时间段导出所带班级请假明细。管理端功能比教师端多一些,包括:学生和教师账号管理、角色权限分配、请假类型字典维护、学期和校历配置、全院请假统计图表展示。
2.3 请假业务状态机
状态机是高校请假系统里最关键的部分。一个请假单从创建到完全结束,通常会经历这些状态:
| 状态 | 含义 | 产生方式 |
|---|---|---|
| 待审批 | 学生已提交,等待教师处理 | 学生提交申请后自动进入 |
| 已批准 | 教师同意请假 | 教师点击通过 |
| 已驳回 | 教师拒绝请假 | 教师点击驳回并填写原因 |
| 已撤销 | 学生取消申请 | 待审批状态下学生主动撤销 |
| 已销假 | 学生返校或结束休假后确认销假 | 学生提交销假信息,流程终结 |
这里不建议把审批流程设计得过于复杂。高校普通请假场景采用“学生提交 -> 辅导员审批 -> 销假归档”即可。如果强行引入多级审批、会签、加签,反而会提高开发成本和演示出错概率。如果后续要做扩展,可以引入 Flowable 工作流引擎,但业务量不高的请假系统用状态字段加审批记录表已经足够,这也是大多数毕设项目更稳的做法。
2.4 业务边界与合规提醒
这个系统适合校园内部流程演示和教学训练,不代表可以直接不加改造成商业级 SaaS。真实生产环境还需要考虑消息通知、移动端、人脸核验、与教务系统对接等问题。作者或拿到源码的人如果要把系统部署到真实校园环境,需要注意:系统会保存学生姓名、学号、班级、联系方式等个人数据,必须遵守个人信息保护相关要求;测试阶段尽量使用模拟数据,不要拿真实学生信息直接填入系统;导出到本地的 Excel 文件也要限制访问范围,避免无关人员拿到全量学生数据。部署上只允许校园网访问,前端页面不应暴露过多系统管理接口。
3. 技术栈选型与前后端项目结构
3.1 后端技术栈
从项目命名和热词都能看出,后端主框架是 SpringBoot。围绕它展开的常用组件包括:
- Spring Web:提供 RESTful Controller 和 Tomcat 内嵌服务器。
- Spring Security 或拦截器 + JWT:处理登录认证和接口权限。
- MyBatis 或 MyBatis-Plus:操作数据库。如果使用 MyBatis-Plus,写 CRUD 会更省时间,答辩时也能解释“LambdaQueryWrapper 如何构造条件查询”。
- MySQL:保存用户、请假单、审批记录等结构化数据。
- Knife4j 或 SpringDoc:生成 Swagger 接口文档,方便前后端联调。
- Lombok:简化实体类代码。
在常见的毕设工程里,后端目录结构会采用 controller、service、mapper(dao)、entity(pojo)、config、common 分包。这种分包不是唯一范式,但容易理解,也便于答辩时说明分层职责:
src/main/java/com/example/leave ├── controller # 接口入口,接收前端请求 ├── service # 业务逻辑层,处理审批状态流转 ├── mapper # 数据访问层,对接数据库 ├── entity # 数据库实体类 ├── dto / vo # 参数接收与视图返回对象 ├── config # 跨域、拦截器、MyBatis 配置 └── common # 全局异常、统一返回值3.2 前端技术栈
前端使用 Vue3,配合 Vite 做构建工具。这种组合比 Vue2 + Webpack 的项目启动更快、配置也更直观。和 Vue3 配合的常用生态如下:
- Vue Router:负责页面路由,例如 /login、/student/leave/my、/teacher/audit/list。
- Pinia:全局状态管理,保存登录用户信息、Token、角色标识。
- Axios:发起 HTTP 请求。一般会在拦截器里统一注入 Authorization 请求头。
- Element Plus:表格、表单、日期选择器、弹窗、上传组件。
- ECharts:在管理端统计页面画柱状图和饼图。
前端典型目录结构如下,这种“页面组件 + API 模块”的组织方式在维护期能省不少精力:
src ├── api # 按业务模块封装的请求方法 ├── assets ├── components ├── layout # 不同角色使用的布局 ├── router # 路由配置与守卫 ├── stores # Pinia 状态 ├── views │ ├── login │ ├── student # 学生端页面 │ ├── teacher # 教师端页面 │ └── admin # 管理端页面 ├── App.vue └── main.js4. 数据库表设计建议
数据库设计质量直接决定后端代码写起来顺不顺手。请假管理系统的核心表不需要太多,建议至少包含:用户表、角色表、用户角色关联表、请假类型表、请假申请表、审批记录表。下面这套 SQL 以“学生和教师统一放在用户表,用角色字段区分”为设计思路,适合作为初始化脚本参考。实际表名如果和源码不一致,按照源码中的 SQL 脚本为准。
CREATE DATABASE IF NOT EXISTS college_leave DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE college_leave; -- 用户表 CREATE TABLE sys_user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE COMMENT '登录账号', password VARCHAR(100) NOT NULL COMMENT '加密密码', real_name VARCHAR(50) NOT NULL COMMENT '姓名', role_code VARCHAR(30) NOT NULL COMMENT '角色编码: student/teacher/admin', college VARCHAR(100) COMMENT '所属学院', phone VARCHAR(20) COMMENT '手机号', status TINYINT NOT NULL DEFAULT 1 COMMENT '是否禁用', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT '系统用户表'; -- 请假类型表 CREATE TABLE leave_type ( id BIGINT AUTO_INCREMENT PRIMARY KEY, type_name VARCHAR(50) NOT NULL COMMENT '请假类型名称', max_days INT COMMENT '单次最大天数,不限制可填空', enabled TINYINT NOT NULL DEFAULT 1 ) COMMENT '请假类型表'; -- 请假申请表 CREATE TABLE leave_application ( id BIGINT AUTO_INCREMENT PRIMARY KEY, student_id BIGINT NOT NULL COMMENT '学生用户ID', type_id BIGINT COMMENT '请假类型ID', start_time DATETIME NOT NULL COMMENT '请假开始时间', end_time DATETIME NOT NULL COMMENT '请假结束时间', leave_days DECIMAL(5,1) COMMENT '请假天数', reason VARCHAR(1000) COMMENT '请假事由', attachment_url VARCHAR(255) COMMENT '附件路径', status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '状态: PENDING/PROVED/REJECTED/CANCELED/FINISHED', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) COMMENT '请假申请表'; -- 审批记录表 CREATE TABLE leave_approval_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY, leave_id BIGINT NOT NULL COMMENT '请假申请ID', approver_id BIGINT NOT NULL COMMENT '审批人用户ID', action VARCHAR(20) NOT NULL COMMENT '审批动作: PROVED/REJECTED', opinion VARCHAR(500) COMMENT '审批意见', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT '审批记录表';这套设计的要点在于:请假主表只保存当前状态,审批历史单独放在记录表。这样做的好处是即使多次驳回后再次审核,也能保留完整时间线和审批痕迹。请假时长的计算建议在后端完成,不要信任前端直接传过来的天数,因为前后端容易因为日期格式和时区不同产生偏差。
5. 后端本地部署:数据库初始化与 SpringBoot 启动
5.1 环境准备
后端启动前需要检查 JDK、Maven、MySQL 是否就位。可以打开命令行执行检查:
java -version mvn -v mysql --version如果项目使用 SpringBoot 3.x,JDK 需要 17 及以上;如果使用 SpringBoot 2.7.x,JDK 1.8 就可以。很多“启动报错”并不是代码问题,而是 JDK 版本和 SpringBoot 版本不匹配。检查到版本后,再对比项目 pom.xml 里的 spring-boot-starter-parent 标签确认。
数据库部分先创建数据库并导入 SQL 初始化脚本。MySQL 8 连接时要注意驱动名和时区配置,常见的 JDBC 连接串模板如下:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/college_leave?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 servlet: multipart: max-file-size: 10MB max-request-size: 20MB mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: map-underscore-to-camel-case: true springdoc: api-docs: enabled: true配置文件里的数据源用户名、密码、数据库名,一定要与你本机 MySQL 实际环境保持一致。如果项目里用了 MyBatis-Plus,日志级别可以临时打开 SQL 输出,方便排查接口查不到数据的问题,在 application.yml 中补充:
logging: level: com.example.leave.mapper: debug5.2 启动后端服务
后端启动有调试和打包两种常见方式。开发阶段直接在 IDE 里运行主类,类名通常是XxxApplication。如果想用命令行方式验证,可以先在项目根目录执行 Maven 打包:
mvn clean package -DskipTests cd target java -jar college-leave-0.0.1-SNAPSHOT.jar需要注意,target目录下 jar 包的名字取决于 pom.xml 的 artifactId 和 version。实际执行时按包名调整。启动成功后,控制台会出现 SpringBoot 的启动日志,默认端口 8080。如果 8080 被占用,可以在 application.yml 里更换端口,也可以启动时手动指定:
java -jar college-leave-0.0.1-SNAPSHOT.jar --server.port=8081后端服务启动后,先不要急着去点前端页面。先用浏览器访问 Swagger 接口文档地址。如果项目集成了 Knife4j,地址一般是http://localhost:8080/doc.html;如果用的是 SpringDoc 原生文档,则是http://localhost:8080/swagger-ui/index.html。不同项目的接法有差异,但能打开接口文档基本能确认后端服务正常运行。
5.3 常见认证配置
登录鉴权是这个系统绕不开的部分。常见做法是基于拦截器或 Spring Security 的过滤器校验 Token。学生在前端输入用户名密码,后端验证通过后返回一个 JWT 字符串,后续请求在 Authorization 请求头携带该 Token。为了不干扰接口调试,Swagger 相关的路径通常需要放行,这也是热词中“springboot jwt 放开 swagger”对应的实际问题。一个通用的安全配置思路是:登录接口和静态文档路径匿名可访问,其余/api/**接口进入 Token 校验,同时用角色编码限制管理员接口和教师接口的访问范围。
如果前端调用接口时发现 401,第一步要检查 Token 有没有传过去;如果前端一登录成功马上请求数据还是 401,可能是 Token 时间过短或者 Redis 中 Session 配置不一致。这些排查放在后面统一说。
6. 前端本地部署:Vue3 请假管理界面搭建
6.1 环境准备
前端部分依赖 Node.js。Vue3 + Vite 项目通常要求 Node 18 以上,但不同版本的 Vite 对 Node 版本要求不同,更稳妥的判断是以项目 package.json 中 engines 字段为准。安装依赖前先切换镜像源会遇到很多网络问题,可以使用以下命令提高下载稳定性:
npm config set registry https://registry.npmmirror.com npm install安装依赖需要时间。如果项目使用 pnpm,也可以用pnpm install,执行速度一般更快。安装好之后启动开发服务器:
npm run dev启动后 Vite 默认监听 5173 端口,终端会输出访问地址。如果你的 5173 被占用,Vite 通常会自动跳到 5174,不需要手动处理,但要注意前端代理配置是否只代理到了固定端口,避免代理错位。
6.2 开发代理配置
本地开发阶段,前端开发服务器和后端服务在不同端口,直接发请求会产生跨域问题。最常见的方案不是在后端代码里配置 CorsFilter,而是在 Vite 开发服务器中配置代理,把/api开头的请求转发到后端 8080 端口。这样浏览器看到的请求是同源的,不涉及跨域拦截。
一个典型的 vite.config.js 配置如下:
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], server: { host: '0.0.0.0', port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } })配置好之后,前端请求/api/auth/login会被 Vite 转发到http://localhost:8080/api/auth/login。如果你的后端接口前缀不是/api,而是/admin或其他路径,需要同步修改代理 key。这里最容易出现的错误是:前端请求路径写成了http://localhost:8080/api/xxx,同时又配置了代理,导致请求没有走代理,跨域问题依然存在。建议在封装 Axios 时统一使用相对路径/api/xxx,把后端地址完全交给代理配置管理。
6.3 前端请求封装与登录态
前端需要统一封装 Axios,否则每个页面都写一遍token注入会很零散。一个简化版封装思路如下:
import axios from 'axios' import router from '@/router' import { useUserStore } from '@/stores/user' const service = axios.create({ baseURL: '/api', timeout: 10000 }) service.interceptors.request.use(config => { const userStore = useUserStore() if (userStore.token) { config.headers.Authorization = `Bearer ${userStore.token}` } return config }) service.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { // 按后端统一返回结构来处理错误 return Promise.reject(new Error(res.message)) } return res.data }, error => { if (error.response && error.response.status === 401) { router.push('/login') } return Promise.reject(error) } ) export default service使用 Vue3 组合式 API 时,页面组件中导入上面封装好的 service 发起请求,业务代码会更干净。比如学生提交请假申请时,只需要调用http.post('/leave/submit', formData)就能拿到后端返回的申请单 ID。注意,这里请求地址对应后端 Controller 的@RequestMapping值,必须前后端约定一致,否则会出现 404。
6.4 路由守卫和角色页面
请假管理系统通常有学生、教师、管理员三类角色,前端不会直接使用后端那样的细粒度权限拦截,而是通过路由配置控制菜单和页面入口。在 Vue Router 中,可以在路由 meta 里记录允许访问的角色,然后在全局前置守卫中做判断:
router.beforeEach((to, from, next) => { const userStore = useUserStore() if (to.path !== '/login' && !userStore.token) { next('/login') return } if (to.meta.roles && !to.meta.roles.includes(userStore.role)) { next('/403') return } next() })这样学生账号访问教师审批页面时会被拦截。但要注意:前端路由守卫只是用户体验层面的限制,真正的权限控制必须在后端接口再做一次校验,否则别人直接调用接口就能绕过前端限制。这也是很多毕设答辩被问倒的地方,建议在代码里明确区分“页面权限”和“接口权限”两层。
7. 接口设计与前后端联调
7.1 统一返回结构
后端所有接口建议返回统一 JSON 结构。这样前端响应拦截器只需要处理一种格式,减少联调中因字段命名不统一带来的麻烦。一个常见的返回对象如下:
public class R<T> { private Integer code; private String message; private T data; public static <T> R<T> ok(T data) { R<T> r = new R<>(); r.code = 200; r.message = "success"; r.data = data; return r; } public static <T> R<T> fail(Integer code, String message) { R<T> r = new R<>(); r.code = code; r.message = message; return r; } }这里的code只表达业务执行结果,不要和 HTTP 状态码混为一谈。HTTP 200 不代表系统业务成功,比如后端拿到一个无效的请假时间段,可以返回 HTTP 200,但业务 JSON 中 code 为错误码,message 提示“结束时间不能早于开始时间”。这种设计能让前端更容易针对业务错误弹出提示。
7.2 请假接口模块模板
后端 Controller 的接口设计,可以按业务动作拆成几个 RESTful 风格接口。下面是一个简化示例,它展示了接口路径和入参位置,实际逻辑需要调用 Service 层完成:
@RestController @RequestMapping("/api/leave") public class LeaveController { @PostMapping("/submit") public R<Long> submit(@RequestBody LeaveSubmitVO vo) { // 实际业务:校验假期时间、插入主表状态、生成审批待办 return R.ok(10001L); } @GetMapping("/my") public R<List<LeaveVO>> myList(@RequestParam Long studentId) { // 查询当前学生的申请列表 return R.ok(new ArrayList<>()); } @GetMapping("/todo") public R<List<LeaveVO>> todoList(@RequestParam Long approverId) { // 查询当前审批人的待办 return R.ok(new ArrayList<>()); } @PostMapping("/approve") public R<Void> approve(@RequestBody ApproveVO vo) { // 审批通过或驳回,写入审批记录并更新主表状态 return R.ok(null); } @PostMapping("/finish") public R<Void> finish(@RequestBody FinishVO vo) { // 学生销假,状态变更为 FINISHED return R.ok(null); } }这里只是接口框架,不代表真实工程的完整签名。实际联调时两个最容易出问题的点:第一,前端传的 JSON 字段名和后端@RequestBody对应的 DTO 字段名不一致;第二,日期字段传的是字符串,后端用 LocalDateTime 接收时格式不匹配。建议前端统一发送2025-01-10 08:00:00这类格式,并在后端 DTO 中配合@JsonFormat注解。
7.3 用 curl 验证后端服务
不打开前端页面也可以先验证后端登录接口是否能通。假设登录接口是/api/auth/login,请求体如下:
curl -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{ "username": "student01", "password": "123456" }'如果用户名和密码正确,返回结果中会携带 Token。把这个 Token 放在后续请求头中,再调用请假列表接口即可。如果登录接口路径、请求体字段或密码加密方式和示例不一致,这里需要按实际源码调整,否则只会看到 404 或者 500。curl 调试的价值在于能快速判断“接口本身有没有问题”,帮助把问题边界从前后端联调中剥离出来。
7.4 用 Swagger 做接口自测
后端运行期间,强烈建议优先使用 Swagger/Knife4j 页面做接口自测。原因很简单:Swagger 页面能看到每个接口的请求参数类型、必填项和响应结构,不用反复看前端代码。管理员相关接口需要登录鉴权时,在 Swagger 页面全局配置一个 Token 即可。
如果前端登录失败,但 Swagger 里手动调用同一个登录接口成功,那问题大概率出在前端参数传递或者代理配置。如果 Swagger 里登录接口也失败,则要检查数据库是否有种子用户、密码是否加密过、后端是否能正常连上 MySQL。这种“先接口后页面”的自测顺序,能节省大量排查时间。
8. 功能验收流程与问题排查
8.1 功能验收用例
拿到源码并启动前后端后,不要只登录看一眼页面就结束。建议按下面的用例把主要业务流程走一遍。每通过一项,在验收表中打钩,能很快定位系统哪一部分还没有跑通。
| 验收场景 | 操作步骤 | 预期结果 | 通过标准 |
|---|---|---|---|
| 登录认证 | 使用学生账号登录 | 跳转到学生首页 | 页面能获取到用户信息 |
| 提交请假申请 | 填写开始结束时间、事由并提交 | 生成请假单,状态为待审批 | 列表出现记录,后端数据库有数据 |
| 教师审批 | 使用教师账号查看待办并同意 | 学生端看到已批准状态 | 审批记录表插入一条记录 |
| 教师驳回 | 对待审批申请点击驳回 | 学生端看到驳回意见 | 状态变为已驳回 |
| 撤销申请 | 学生撤销待审批申请 | 申请单变为已撤销 | 状态不再参与待办 |
| 销假归档 | 对已批准的申请提交销假 | 状态变为已销假 | 流程完成 |
| 类型管理 | 管理员新增“事假”类型 | 前端下拉框可选新类型 | 页面刷新后仍存在 |
| 统计导出 | 管理员按学期导出请假明细 | 浏览器下载 Excel 文件 | 文件行数与列表匹配 |
| 权限校验 | 用学生账号访问教师审批接口 | 返回无权限提示 | 后端拒绝访问 |
这套用例覆盖了系统的主流程和权限边界。如果某个环节失败,优先判断是前端路由问题、后端逻辑问题还是数据库状态被写脏。例如学生提交后教师看不到待办,极有可能不是教师端代码问题,而是leave_application.student_id与教师班级没有建立关联,或者查询条件里多了班级过滤字段。
8.2 常见问题排查
以下表格汇总了启动和联调阶段最常出现的问题:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 后端启动报数据库连接失败 | MySQL 未启动、密码错误、数据库不存在 | 查看控制台异常信息,用 Navicat/命令行连接数据库 | 修改 application.yml 中 url、username、password |
| 前端 npm install 卡住或失败 | 默认源下载慢 | 查看终端报错提示 | 切换 npmmirror 源后重新执行 |
| 前端启动后页面 404 | 路由路径错误或 history 路由没有 fallback | 打开浏览器 Network 查看请求路径 | 检查路由配置,部署环境需配置 history fallback |
| 接口调用报 401 | 没有携带 Token、Token 过期 | 查看请求头中的 Authorization | 检查 Axios 拦截器,刷新登录状态 |
| 接口调用报 403 | 当前角色没有该接口权限 | 查看后端日志中权限校验点 | 给用户分配正确角色,或调整接口权限配置 |
| 接口调用报 500 | 后端空指针、SQL 异常、参数转换失败 | 查看后端控制台堆栈日志 | 按异常信息修复代码或调整参数格式 |
| 日期时间差 13 或 14 小时 | 数据库连接时区配置不一致 | 对比数据库时间和页面时间 | 在连接串增加 serverTimezone=Asia/Shanghai |
| 文件上传失败 | 上传大小超过 Spring 限制 | 查看是否返回 MaxUploadSizeExceededException | 增加 multipart 配置项 |
| 刷新前端页面后 404 | 后端未配置前端 history 路由回退 | 检查刷新时的 URL 路径 | 部署模式下让后端转发到 index.html |
| Maven 打包失败 | JDK 版本和 SpringBoot 版本不匹配 | 查看编译错误提示 | 按 pom.xml 要求切换 JDK |
| 教师看不到学生申请 | 班级、学院关联条件过滤了数据 | 打印 SQL,查看查询条件 | 检查当前教师账号和学生的归属字段是否匹配 |
这个排查过程的核心思路是先拆边界:是前端问题、后端问题还是数据库问题。不要一上来就改代码,先看 Network 请求是否到达后端;再看后端日志有没有异常;最后看 SQL 语句查出来什么数据。按这个顺序排查,大多数环境类问题都能在半小时内解决。
8.3 前后端联调常见错误
程序层面之外,最容易让新手卡住的是前后端 API 约定不一致。前端请求的 URL 写的是/api/leave/list,后端映射是/leave/list,即使代理正确也会 404。更隐蔽的问题是后端接口方法注解是@RequestParam(required = true),前端却用@RequestBodyJSON 传参,导致参数解析不到。联调阶段的建议是:先打开浏览器 F12,观察请求 URL、请求方法、请求体格式是否和后端 Swagger 定义一致;再用 Postman 或 curl 手动调一次后端,确认后端本身没问题;最后回来看前端代码传参。
9. 最佳实践与合规要求
9.1 工程化最佳实践
如果是拿这套高校请假管理系统作为毕设或练手项目,建议从一开始就按照工程化习惯整理代码。第一,数据库脚本必须纳入版本管理,不要只在 Navicat 里手动执行却没有存档。最好项目根目录建一个 sql 文件夹,保存schema.sql和data.sql,这样别人克隆代码后能一键初始化数据库。第二,后端生成的 Excel 导出文件、学生上传的证明材料附件,统一保存到指定目录或者对象存储,避免把文件散落在系统临时目录中。第三,请假状态不要用魔法数字,建议在 Java 中定义枚举类或者在 MySQL 中使用注释清晰的可读字符串,这样后续扩展多级审批会容易很多。
在接口设计上,建议新增、删除、修改操作都返回操作结果而不是直接返回 null。审批操作属于写操作,还必须校验单据当前状态,防止学生撤销后教师还能审批成功。真实项目中常见的一个低级错误就是审批时不检查当前状态,导致同一条申请被重复通过。完整的状态校验是每条写接口都应该做的事。
在批量处理方面,请假系统往往需要按学期、按学院导出统计表。Excel 导出不能直接在浏览器端拼接数据,更稳的做法是后端根据查询条件生成 Excel 后返回文件下载链接,或者直接让后端接口返回二进制流。前端导出请求要设置responseType: 'blob',否则下载下来的文件可能是一段 JSON 错误信息。对于包含大量审批记录的历史数据查询,可以在数据库层面对leave_application表和leave_approval_record表建立合适的索引,避免页面越翻越慢。
9.2 安全与合规要求
高校请假系统存放的是真实校园业务数据,不能因为是“毕设”就忽略安全问题。测试环境建议把密码统一设置为复杂测试数据,前后端联调时用模拟学号和学生姓名,不要使用真实在校学生信息。所有用户密码不准明文入库,至少要使用 BCrypt 这类哈希算法。系统对外提供接口时,查询接口不要无条件返回全字段,学生手机号、家庭住址之类的敏感字段应该按角色做脱敏或裁剪。导出文件如果包含大量个人信息,要在管理端增加操作日志和导出权限控制。
从开发角度看,后端 CORS 配置不要把允许来源写成*,本地开发用 Vite 代理就可以规避跨域。部署到实际服务器后,建议给 Tomcat 配置 HTTPS 证书,避免登录密码和 Token 在传输中被截获。管理员账号要单独设置,不直接使用学生账号分配超管权限。
9.3 部署后的运行观察
本地开发环境和服务部署环境的资源观察重点不同。本地开发阶段,启动后端、MySQL、Redis(如果项目使用)后,注意观察内存占用和端口占用。如果电脑内存只有 8GB,不要同时启动太多工具,否则系统会明显卡顿。观察资源占用时,在 Windows 任务管理器或 macOS 活动监视器里查看java、node、mysqld三个进程即可。部署到 Linux 服务器时,可以使用free -h查看内存,使用top查看进程 CPU 占用,使用journalctl -u your-service查看服务日志。负载不大时,不需要做复杂压测,重点确认应用重启后能自动拉起即可。
如果后续想把这个系统扩展到真实环境,可以考虑引入消息通知能力:审批通过后给学生发送短信或站内信,学生请假超时未销假时给辅导员发送提醒。技术实现上可以结合 SpringBoot 的定时任务或者消息队列,但前提是业务流程已经稳定。对于一个高校请假管理系统来说,先把状态机、审批记录和权限边界管好,比急着堆新技术更值得投入。
这套系统最值得动手验证的就是一条完整请假链路:学生提交、教师审批、学生销假、管理员导出。最容易踩的坑不是前端组件不会写,而是数据库连接出错、跨域代理没配置、接口参数前后端不一致这三类问题。按照上面顺序把环境跑通后,再去看源码里的状态流转和权限控制,整个 SpringBoot + Vue3 前后端分离项目就不会再是黑盒了。