
简介面向Java毕业设计场景这套基于Spring Boot与Vue的工作考勤管理系统源码提供可直接运行的完整前后端工程适合需要完成课程设计或毕业设计的本科生以及想系统练习前后端分离开发的进阶学习者。443KB的rar压缩包内共251个文件77个Java文件对应考勤、员工、薪资等核心业务逻辑22个Vue组件与79个JavaScript文件共同构建管理端交互页面另有Markdown说明、JSON/XML/YAML等配置便于快速理解目录结构和启动方式。已有113人学习下载对于准备Spring BootVue技术栈的毕业设计选题具备明确的复用价值。源码按Controller、Service、Entity与前端视图分层组织覆盖考勤打卡、员工管理、薪资核算等常见模块解压后可直接运行也可在此基础二次开发用于开题、答辩演示或代码讲解都能帮助节省从零搭建框架、排查环境问题的时间。1. 从排班表到工资条SpringBoot Vue考勤系统的数据链路设计考勤管理系统在毕业设计里属于“看着简单、做起来碎”的那类项目。排班规则、请假审批、打卡时间、加班调休、工资计算每一个环节单拎出来都不难但串在一起就容易出现“考勤记录对不上工资条”的问题。这套SpringBoot Vue工作考勤管理系统源码把员工管理、考勤打卡、请假审批、薪资计算做成了完整闭环代码可以直接跑起来。对于正在做Java毕业设计、或者刚入职想了解企业级考勤业务怎么落地的开发者来说它的结构比业务本身更有参考价值。项目的后端基于Spring Boot 2.x构建前端使用Vue 2 Element UI数据库中包含员工表、考勤表、请假表、薪资表等核心表结构。从文件列表可以看到后端Controller层划分清晰SalaryController、EmployeeController、AttendanceController分模块管理Service层采用接口加实现类的方式EmployeeServiceImpl这种分包方式符合大多数中小型项目的组织习惯也方便在答辩时讲解模块职责。下面从后端业务逻辑、前端交互、部署验证三个层面把这条数据链路完整拆开。2. 后端防线Spring Security认证与迟到早退判定逻辑2.1 项目结构与认证授权模块的落地方式拿到源码后先看后端目录结构。常见的SpringBoot工程中controller、service、mapper、entity四层分包这套源码也遵循同样的规范。EmployeeController负责员工信息的增删改查AttendanceController处理打卡记录SalaryController管理薪资数据。三者通过员工ID关联形成业务闭环。认证部分使用JWTJSON Web Token方案。用户登录成功后后端生成token返回给前端前端存储并在后续请求的头信息中携带。核心配置在SecurityConfig类中下面是一个典型的JWT认证过滤器实现Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { Autowired private UserDetailsService userDetailsService; Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 1. 从请求头中获取token String authHeader request.getHeader(Authorization); if (authHeader ! null authHeader.startsWith(Bearer )) { String token authHeader.substring(7); String username JwtUtil.parseToken(token); if (username ! null SecurityContextHolder.getContext().getAuthentication() null) { // 2. 根据用户名加载用户信息重新构建认证对象 UserDetails userDetails userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); } }这段过滤器的执行逻辑是前端每次请求都会携带Authorization头过滤器从中解析出JWT校验通过后把用户信息放到SecurityContext中后续接口就能通过AuthenticationPrincipal拿到当前登录用户。需要注意JwtUtil.parseToken内部包含了签名验证和过期时间检查token有效期建议设置为2小时前端配合拦截器做自动续期。2.2 迟到与早退的计算规则考勤模块的核心是迟到、早退、缺勤的判定。这套源码中AttendanceController接收前端传来的打卡时间和打卡类型上班/下班Service层负责与排班表比对。常见的计算方式是规定上班时间9:00打卡时间在9:00到9:30之间记为迟到超过9:30记为缺勤下班时间18:00打卡时间早于17:30记为早退。这个时间阈值通常在系统配置表中维护而不是硬编码在代码里。看一下核心的判定逻辑public AttendanceResult calculateAttendance(AttendanceRecord record, ShiftConfig shift) { // 1. 解析打卡时间与排班时间 LocalDateTime punchTime record.getPunchTime(); LocalDateTime shiftStart shift.getStartTime(); // 排班上班时间 LocalDateTime shiftEnd shift.getEndTime(); // 排班下班时间 String status NORMAL; // NORMAL-正常 LATE-迟到 EARLY-早退 ABSENT-缺勤 // 2. 迟到判定晚于上班时间但不超过30分钟 if (punchTime.isAfter(shiftStart) Duration.between(shiftStart, punchTime).toMinutes() 30) { status LATE; } else if (punchTime.isAfter(shiftStart.plusMinutes(30))) { // 3. 超过30分钟视为缺勤 status ABSENT; } // 4. 早退判定早于下班时间30分钟以上 if (Duration.between(punchTime, shiftEnd).toMinutes() 30 punchTime.isBefore(shiftEnd)) { status EARLY; } return new AttendanceResult(status, Duration.between(shiftStart, punchTime).toMinutes()); }这段代码返回的结果对象中包含了最终的考勤状态和迟到分钟数SalaryController在计算工资时会直接从考勤记录中读取这些值。这里有一个容易踩坑的地方LocalDateTime直接比较时如果打卡时间跨天比如夜班需要先判断排班日期是否跨日否则判定结果会出错。源码中排班表设计为支持跨天场景但ServiceImpl中要额外判断。2.3 薪资计算模块的扩展点SalaryController和EmployeeServiceImpl之间的关系需要理清楚薪资表通过employee_id关联员工表工资项包含基本工资、岗位工资、绩效工资、考勤扣款。考勤扣款的计算逻辑在SalaryServiceImpl中考勤状态扣款规则备注迟到每次扣50元当月累计超过5次额外扣200元早退每次扣50元与迟到分开累计缺勤扣当日基本工资的1.5倍使用月基本工资/21.75计算日薪请假扣当日基本工资病假按50%发放这个规则表在面试中经常被问到“怎么设计才灵活”。常见的做法是把工资项做成字典表每个扣款项对应一条记录包含计算方式和参数。示例代码中Hardcode了扣款金额实际项目建议抽成配置避免每次调整扣款规则都要改代码重新发布。3. 前端双端适配Vue2管理台与移动端打卡页的实现细节3.1 Element UI框架下的管理后台布局前端的核心页面包括登录页、员工管理页、考勤记录页、请假审批页、薪资管理页。项目使用vue-router做路由管理页面组件放在views目录下公共组件放在components目录。员工管理页面是一个典型的CRUD表格页。Element UI的el-table配合el-dialog实现列表展示和新增编辑弹窗。分页组件使用el-pagination后端接口接收pageNum和pageSize参数返回总条数和当前页数据。这里有一个关键点删除操作要二次确认Element UI的this.$confirm方法可以弹确认框避免误删操作。路由守卫是前端权限控制的关键环节。在router/index.js中配置全局前置守卫router.beforeEach((to, from, next) { // 1. 白名单页面登录页、注册页直接放行 if (to.path /login) { next(); return; } // 2. 检查本地存储中的token const token localStorage.getItem(token); if (!token) { // 3. 没有token跳转到登录页并携带回跳地址 next(/login?redirect${to.path}); return; } // 4. 有token但访问的是管理员页面校验角色 const userRole localStorage.getItem(userRole); if (to.meta.requiresAdmin userRole ! ADMIN) { next(/403); return; } next(); });这套逻辑解决了两个问题未登录用户无法访问内部页面低权限用户无法进入管理员专属页面。路由meta字段中的requiresAdmin是自定义属性在定义路由时通过meta传入比在组件内写死判断更灵活。3.2 移动端打卡页面的时间处理考勤系统的打卡入口通常是移动端页面员工在上班和下班时各点一次按钮。前端调用navigator.geolocation获取定位信息可选同时把打卡时间戳发送给后端。打卡页面的核心逻辑是防止重复提交。常见做法是按钮点击后立即置为disabled状态同时记录一个本地标记async handlePunch(type) { // 1. 防止重复点击 if (this.submitting) return; this.submitting true; try { const timestamp new Date().getTime(); // 2. 调用后端打卡接口 const res await this.$http.post(/api/attendance/punch, { type: type, // 1-上班 2-下班 timestamp: timestamp, location: this.locationInfo }); // 3. 成功后更新页面状态 if (res.data.code 200) { this.$message.success(打卡成功); this.todayRecord res.data.data; } else { this.$message.error(res.data.msg); } } finally { // 4. 恢复按钮状态 this.submitting false; } }注意前端传入的时间戳一定要用后端时间校验不能直接信任客户端时间。用户如果修改了手机系统时间可能导致打卡记录异常。常见的做法是后端收到请求后以服务器时间为准前端时间戳仅作参考。Service层的处理逻辑应该判断服务器当前时间减去前端时间戳的差值超过5分钟就提示时间校准。3.3 请假审批的状态流转请假模块涉及两个角色员工提交申请管理员或部门经理审批。前端请假页面提交表单后记录进入PENDING状态审批页面展示待处理列表。状态流转用前端tag标签展示比较直观状态值显示标签标签颜色PENDING待审批warningAPPROVED已通过successREJECTED已驳回dangerCANCELLED已取消info审批操作后前端需要刷新列表数据。这里有一个优化点审批通过后如果该员工的请假日期和排班冲突后端Service中会自动生成一条调休记录或标记为“请假中”。这个联动逻辑在源码中有对应实现关联了请假表、考勤表和排班表体现了表设计时的外键关联关系。提交请假表单时前端要校验结束时间不能早于开始时间el-date-picker可以设置picker-options限制可选范围。4. 前后端联调Axios拦截器、导出模块和Linux部署配置4.1 统一响应包装与Axios拦截器的配合前端src/utils/request.js中通常使用axios.create()创建实例配置baseURL指向后端接口地址。实际开发中后端接口返回格式统一为{code: 200, data: {}, msg: success}前端在响应拦截器中统一处理const service axios.create({ baseURL: process.env.VUE_APP_BASE_URL, timeout: 15000 }); // 请求拦截器自动携带token service.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] Bearer token; } return config; }); // 响应拦截器统一处理错误状态 service.interceptors.response.use( response { const res response.data; if (res.code 200) { return res; // 直接返回完整响应体 } // 401表示token过期清除本地凭证并跳转登录 if (res.code 401) { localStorage.removeItem(token); window.location.href /login; return Promise.reject(unauthorized); } // 其他错误码显示消息提示 this.$message.error(res.msg || 请求失败); return Promise.reject(res); }, error { this.$message.error(网络异常请检查后端服务是否启动); return Promise.reject(error); } );这段代码解决了前端开发中80%的接口联调问题。说一个使用时的注意点this.$message在拦截器里引用时如果是在非组件上下文需要改为import { Message } from element-ui方式引入。很多新手在这里会碰到“message is undefined”的报错本质是因为this指向发生了变化。4.2 考勤报表导出Excel的实现方式后端导出Excel通常使用Apache POI或EasyExcel。这套源码中导出功能放在AttendanceController中前端通过window.open或a标签触发下载。使用EasyExcel导出考勤报表的核心代码GetMapping(/export) public void exportAttendance(HttpServletResponse response) throws IOException { // 1. 设置响应头声明下载的文件类型和文件名 response.setContentType(application/vnd.ms-excel); response.setCharacterEncoding(utf-8); String fileName URLEncoder.encode(考勤记录_ DateUtil.today(), UTF-8).replace(, %20); response.setHeader(Content-Disposition, attachment;filename*utf-8 fileName .xlsx); // 2. 查询考勤数据 ListAttendanceExcelVO list attendanceService.getExportData(); // 3. 使用EasyExcel写出 EasyExcel.write(response.getOutputStream(), AttendanceExcelVO.class) .sheet(考勤记录) .doWrite(list); }响应头中的Content-Disposition字段决定浏览器是下载还是预览filename*utf-8的写法避免中文文件名乱码。前端触发下载时注意发请求如果走Axios会得到二进制流需要声明responseType: blob或者直接使用window.open拼接接口地址利用token参数传递认证信息。源码中导出的Excel列包含工号、姓名、日期、上班打卡时间、下班打卡时间、考勤状态、备注。如果导出时遇到数据量大的情况EasyExcel支持分批写入核心思路是分页查询数据每查一页写一页到Excel适合几千条以上的场景。4.3 前后端分离项目的部署流程这套源码能直接运行前提是环境配置正确。本地开发时前端运行npm run serve启动开发服务器后端运行mvn spring-boot:run启动SpringBoot应用。前端配置了代理转发开发环境的/api请求会转发到本地的8080端口后端。生产环境部署推荐使用Nginx托管前端静态文件反向代理后端接口。Nginx配置示例server { listen 80; server_name your-domain.com; # 前端静态文件 root /usr/share/nginx/html; index index.html; # 前端路由history模式配置 location / { try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 60s; } }后端jar包部署时注意指定生产环境的数据库连接信息。常用方式是把application.yml中的配置通过外部配置文件覆盖启动命令为java -jar xxx.jar --spring.config.location/path/to/application-prod.yml。另外SpringBoot内置的Tomcat默认端口是8080生产环境建议通过server.port指定为8080或其他端口与Nginx配置保持一致。5. 代码可直接运行背后的工程细节三个容易翻车的隐藏坑5.1 跨域问题排查前后端分离开发时跨域是最常见的报错。项目启动后如果前端页面能打开但接口请求全部报CORS错误多半是后端没有配置跨域过滤器。SpringBoot的解决方案是添加一个配置类实现WebMvcConfigurer接口重写addCorsMappings方法Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }allowCredentials(true)表示允许携带Cookie但注意allowedOriginPatterns不能设为*因为浏览器规范禁止凭证认证和通配符同时使用。如果项目中使用了Spring Security还需要在SecurityConfig中允许OPTIONS请求放行否则预检请求会被拦截。5.2 时间字段的时区问题考勤系统对时间的敏感度极高。SpringBoot默认使用Jackson序列化时间字段如果实体中的LocalDateTime类型直接返回前端默认格式是2025-01-15T09:30:00中间多了一个T前端解析时容易出错。解决办法有两种一是在application.yml中配置全局时间格式spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8二是在实体字段上使用JsonFormat注解JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8) private LocalDateTime createTime;同时要注意MySQL连接串中的serverTimezone参数推荐设置为Asia/Shanghai。如果缺失数据库读取时间可能比北京时间少8小时导致打卡记录全部异常。这个坑非常隐蔽建议收到源码后先改数据库连接串再跑业务测试。5.3 数据初始化与账号配置源码能直接运行的前提是数据库中有初始数据。项目src/main/resources目录下应该有sql文件包含建表语句和初始管理员账号。导入时要注意执行顺序先建表再插入数据避免外键约束失败。默认管理员账号密码通常写在README或sql文件中运行前用Postman或直接在登录页验证一下。登录成功后先创建一个测试员工再提交请假单整个流程走通确认前端页面、后端接口、数据库表之间的链路没有断裂。对于想深入理解这个项目的开发者建议把考勤判定规则的边界条件写一个测试类覆盖一下比如跨天打卡、请假当天是否还要打卡、管理员修改考勤记录后薪资是否会重算。这些边界条件往往是答辩时评委最爱问的问题提前准备好能展示对业务的深层理解而不仅仅是把功能跑通。本文还有配套的精品资源点击获取