SpringBoot+Vue考勤管理系统开发实践
1. 项目概述考勤管理是企业日常运营中不可或缺的一环传统的人工考勤方式效率低下且容易出错。这个基于SpringBoot的考勤管理系统正是为了解决这些问题而设计的。系统采用B/S架构实现了员工信息管理、考勤记录、请假审批、数据统计等核心功能模块。我在开发这个系统时特别注重实际业务场景的适配性。比如针对制造业常见的三班倒考勤需求系统支持灵活设置班次规则针对外勤人员开发了基于地理位置的移动端签到功能。整个系统采用前后端分离架构前端使用Vue.jsElementUI后端基于SpringBootMyBatisPlus数据库选用MySQL 8.0。2. 技术架构解析2.1 后端技术栈SpringBoot 2.7作为基础框架其自动配置特性大大简化了项目搭建过程。我特别使用了以下关键配置SpringBootApplication(exclude { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }) public class AttendanceApplication { public static void main(String[] args) { SpringApplication.run(AttendanceApplication.class, args); } }这种排除自动配置的方式是为了实现多数据源的灵活切换。系统支持同时连接考勤机数据库和业务数据库通过自定义的DynamicDataSource类实现数据源路由public class DynamicDataSource extends AbstractRoutingDataSource { Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceType(); } }2.2 前端技术方案Vue3组合式API的使用让前端代码更易维护。考勤统计模块使用了ECharts实现可视化展示关键配置如下const initChart () { const chartDom document.getElementById(attendance-chart); const myChart echarts.init(chartDom); const option { tooltip: { trigger: axis }, legend: { data: [正常, 迟到, 早退, 缺勤] }, xAxis: { type: category, data: dates }, yAxis: { type: value }, series: [ { name: 正常, type: bar, data: normalData }, { name: 迟到, type: bar, data: lateData } ] }; myChart.setOption(option); };2.3 数据库设计数据库设计遵循第三范式主要表结构包括员工表(employee): 存储员工基本信息考勤记录表(attendance): 记录每日考勤状态请假表(leave_application): 管理请假审批流程部门表(department): 组织结构管理特别设计了考勤规则表(attendance_rule)来支持灵活的考勤策略CREATE TABLE attendance_rule ( id bigint NOT NULL AUTO_INCREMENT, rule_name varchar(50) NOT NULL COMMENT 规则名称, work_start_time time NOT NULL COMMENT 上班时间, work_end_time time NOT NULL COMMENT 下班时间, late_minutes int DEFAULT 30 COMMENT 迟到分钟数阈值, early_minutes int DEFAULT 30 COMMENT 早退分钟数阈值, flexible_time int DEFAULT 0 COMMENT 弹性时间(分钟), department_id bigint DEFAULT NULL COMMENT 适用部门, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3. 核心功能实现3.1 考勤打卡流程系统支持多种打卡方式Web端打卡适用于办公室人员移动端GPS打卡适用于外勤人员考勤机对接通过TCP协议与中控考勤机通信打卡业务逻辑处理流程public AttendanceRecord handleCheckIn(CheckInDTO dto) { // 1. 验证员工状态 Employee employee employeeService.getById(dto.getEmployeeId()); if (employee null || employee.getStatus() ! 1) { throw new BusinessException(员工不存在或已离职); } // 2. 获取当日考勤规则 AttendanceRule rule ruleService.getRuleByEmployee(employee.getId()); // 3. 计算考勤状态 AttendanceStatus status calculateStatus(dto.getCheckTime(), rule); // 4. 保存记录 AttendanceRecord record new AttendanceRecord(); record.setEmployeeId(employee.getId()); record.setCheckTime(dto.getCheckTime()); record.setStatus(status.getValue()); record.setLocation(dto.getLocation()); attendanceMapper.insert(record); return record; }3.2 请假审批工作流使用Activiti引擎实现多级审批流程关键配置process idleaveApproval name请假审批流程 startEvent idstartEvent/ userTask iddeptLeaderAudit name部门领导审批/ userTask idhrAudit name人事审批 activiti:candidateGroupshr/ exclusiveGateway idexclusiveGw/ endEvent idendEvent/ sequenceFlow idflow1 sourceRefstartEvent targetRefdeptLeaderAudit/ sequenceFlow idflow2 sourceRefdeptLeaderAudit targetRefhrAudit/ sequenceFlow idflow3 sourceRefhrAudit targetRefexclusiveGw/ sequenceFlow idflow4 sourceRefexclusiveGw targetRefendEvent conditionExpression xsi:typetFormalExpression ![CDATA[${approved}]] /conditionExpression /sequenceFlow /process3.3 考勤统计报表使用JasperReport生成PDF报表核心SQLSELECT e.employee_name, d.department_name, COUNT(CASE WHEN a.status 1 THEN 1 END) AS normal_days, COUNT(CASE WHEN a.status 2 THEN 1 END) AS late_days, COUNT(CASE WHEN a.status 3 THEN 1 END) AS early_days, COUNT(CASE WHEN a.status 4 THEN 1 END) AS absent_days FROM attendance a JOIN employee e ON a.employee_id e.id JOIN department d ON e.department_id d.id WHERE a.check_time BETWEEN :startDate AND :endDate GROUP BY e.employee_name, d.department_name4. 系统部署方案4.1 开发环境配置推荐使用以下开发环境JDK 17IntelliJ IDEA 2023Node.js 16MySQL 8.0Redis 6.2Maven依赖管理特别注意这些核心依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency dependency groupIdorg.activiti/groupId artifactIdactiviti-spring-boot-starter/artifactId version7.1.0.M6/version /dependency4.2 生产环境部署采用Docker容器化部署方案docker-compose.yml关键配置version: 3 services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - ./mysql/data:/var/lib/mysql ports: - 3306:3306 redis: image: redis:6.2-alpine ports: - 6379:6379 app: build: . ports: - 8080:8080 depends_on: - mysql - redis environment: - SPRING_PROFILES_ACTIVEprodNginx配置示例实现前后端分离部署server { listen 80; server_name attendance.example.com; location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://app:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }5. 开发经验与优化建议5.1 性能优化实践考勤数据缓存策略Cacheable(value attendance, key #employeeId-#date) public AttendanceRecord getDailyRecord(Long employeeId, LocalDate date) { return attendanceMapper.selectByEmployeeAndDate(employeeId, date); }批量导入优化使用MyBatis的批量插入功能Transactional public void batchImport(ListAttendanceRecord records) { SqlSession session sqlSessionFactory.openSession(ExecutorType.BATCH); AttendanceMapper mapper session.getMapper(AttendanceMapper.class); records.forEach(mapper::insert); session.commit(); session.close(); }5.2 安全防护措施JWT认证实现public String generateToken(UserDetails userDetails) { MapString, Object claims new HashMap(); claims.put(roles, userDetails.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toList())); return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() expiration)) .signWith(SignatureAlgorithm.HS512, secret) .compact(); }SQL注入防护始终使用预编译语句select idselectByCondition resultTypeAttendanceRecord SELECT * FROM attendance WHERE employee_id #{employeeId} if teststartDate ! null AND check_time #{startDate} /if if testendDate ! null AND check_time #{endDate} /if /select5.3 常见问题排查考勤机连接超时问题检查网络连通性telnet 考勤机IP 端口确认考勤机协议版本验证心跳包发送间隔建议30秒移动端定位不准解决方案增加GPS信号强度检测使用高德/百度地图API进行坐标纠偏设置合理的位置误差范围建议300米内并发打卡冲突处理Transactional(isolation Isolation.SERIALIZABLE) public AttendanceRecord handleConcurrentCheckIn(CheckInDTO dto) { // 检查是否已打卡 AttendanceRecord existing getDailyRecord(dto.getEmployeeId(), LocalDate.now()); if (existing ! null) { throw new BusinessException(今日已打卡); } return handleCheckIn(dto); }6. 论文文档要点论文文档包含以下核心章节系统需求分析技术方案选型系统架构设计数据库设计核心功能实现系统测试方案部署与维护指南特别在系统测试章节提供了详细的测试用例考勤打卡功能测试用例表请假审批流程测试场景性能压力测试结果支持500并发用户安全测试报告包括OWASP Top 10防护措施论文最后附有完整的系统界面截图展示主要功能页面登录界面员工考勤看板请假申请表单考勤统计报表系统管理后台