news 2026/5/2 4:20:24

Spring Boot 2.5 + Activiti 7.1 实战:从零搭建一个请假审批工作流(附完整源码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot 2.5 + Activiti 7.1 实战:从零搭建一个请假审批工作流(附完整源码)

Spring Boot 2.5 + Activiti 7.1 实战:从零搭建一个请假审批工作流(附完整源码)

在当今企业级应用开发中,业务流程自动化已成为提升效率的关键。想象一下,当员工提交请假申请后,系统能自动流转至部门主管、HR等环节审批,整个过程无需人工干预——这正是工作流引擎的魔力所在。本文将带你用Spring Boot 2.5和Activiti 7.1构建一个真实的请假审批系统,从流程图设计到API集成,完整呈现业务与工作流引擎的深度结合。

1. 环境准备与项目初始化

1.1 技术栈选型说明

  • 核心框架:Spring Boot 2.5.0(长期支持版本)
  • 工作流引擎:Activiti 7.1.0.M5(支持BPMN 2.0最新特性)
  • 数据库:MySQL 8.0(兼容Activiti所有表结构)
  • 辅助工具
    • Lombok(简化实体类编写)
    • MyBatis-Plus 3.3.1(数据访问层增强)
    • Swagger(API文档生成)

1.2 初始化项目依赖

<!-- Activiti核心依赖 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter</artifactId> <version>7.1.0.M5</version> <exclusions> <exclusion> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> </exclusion> </exclusions> </dependency> <!-- 流程设计器UI组件 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-image-generator</artifactId> <version>7.1.0.M5</version> </dependency> <!-- 业务系统常用依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1</version> </dependency>

注意:Activiti 7.x默认使用MyBatis,若项目已使用MyBatis-Plus需排除冲突包

1.3 数据库配置示例

spring: datasource: url: jdbc:mysql://localhost:3306/activiti_demo?useSSL=false&serverTimezone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver activiti: database-schema-update: true # 自动创建表结构 history-level: full # 记录完整历史数据

2. 可视化流程设计实战

2.1 集成Activiti Modeler设计器

  1. 从官方GitHub获取Modeler资源文件
  2. editor目录复制到resources/static
  3. 添加汉化文件zh-CN.json

访问设计器的典型URL结构:

http://localhost:8080/editor/#/processes?modelId=10001

2.2 设计请假审批流程图

使用BPMN 2.0符号构建包含以下节点的流程:

  • 开始事件:员工提交申请
  • 用户任务
    • 部门审批(组长)
    • 人事备案(HR)
  • 排他网关:根据请假天数分流
    • ≤3天:直接归档
    • >3天:需总监审批
  • 结束事件:流程终止
// 通过代码创建初始流程模型 Model model = repositoryService.newModel(); ObjectNode modelNode = objectMapper.createObjectNode(); modelNode.put("name", "请假流程"); modelNode.put("description", "员工请假审批流程"); model.setMetaInfo(modelNode.toString()); repositoryService.saveModel(model);

2.3 流程变量设计

定义审批过程需要传递的关键变量:

变量名类型作用
applicantString申请人工号
leaveDaysInteger请假天数
reasonString请假原因
approvalOpinionString审批意见

3. 业务系统深度集成

3.1 请假单实体设计

@Data @TableName("t_leave_application") public class LeaveApplication { @TableId(type = IdType.ASSIGN_ID) private Long id; private String employeeId; private LocalDate startDate; private LocalDate endDate; private Integer days; private String reason; private Integer status; // 0-待审批 1-已通过 2-已拒绝 private String processInstanceId; // 关联流程实例 }

3.2 核心API实现

3.2.1 提交请假申请
@PostMapping("/leave/apply") public Result applyLeave(@RequestBody LeaveApplication application) { // 1. 保存业务数据 leaveService.save(application); // 2. 启动流程实例 Map<String, Object> variables = new HashMap<>(); variables.put("applicant", application.getEmployeeId()); variables.put("leaveDays", application.getDays()); RuntimeService runtimeService = activitiRuntimeService; ProcessInstance instance = runtimeService.startProcessInstanceByKey( "leaveProcess", variables ); // 3. 关联业务与流程 application.setProcessInstanceId(instance.getId()); leaveService.updateById(application); return Result.success(instance.getId()); }
3.2.2 审批任务处理
@PostMapping("/approve/{taskId}") public Result approveTask(@PathVariable String taskId, @RequestParam Boolean approved, @RequestParam String comment) { TaskService taskService = activitiTaskService; // 1. 完成任务 Map<String, Object> variables = new HashMap<>(); variables.put("approved", approved); variables.put("approvalOpinion", comment); taskService.complete(taskId, variables); // 2. 更新业务状态 Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); LeaveApplication application = leaveService.lambdaQuery() .eq(LeaveApplication::getProcessInstanceId, task.getProcessInstanceId()) .one(); application.setStatus(approved ? 1 : 2); leaveService.updateById(application); return Result.success(); }

3.3 待办任务查询优化

-- 联合查询业务数据和流程状态 SELECT t.*, l.* FROM ACT_RU_TASK t JOIN t_leave_application l ON t.PROC_INST_ID_ = l.process_instance_id WHERE t.ASSIGNEE_ = #{userId}

4. 高级功能实现

4.1 动态审批人配置

通过监听器实现审批人动态分配:

@Component public class LeaveTaskListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { String eventName = delegateTask.getEventName(); if ("create".equals(eventName)) { String taskKey = delegateTask.getTaskDefinitionKey(); String applicant = (String) delegateTask.getVariable("applicant"); switch (taskKey) { case "deptAudit": String leader = userService.getDeptLeader(applicant); delegateTask.setAssignee(leader); break; case "hrRecord": delegateTask.setAssignee("hr001"); break; } } } }

4.2 流程版本控制策略

当流程定义变更时,采用语义化版本管理:

  1. 小版本更新(v1.0 → v1.1):不影响运行中实例
  2. 大版本更新(v1.x → v2.0):新申请用新流程
repositoryService.createDeployment() .name("请假流程v2") .addClasspathResource("processes/leave-v2.bpmn20.xml") .key("leaveProcess") .enableDuplicateFiltering() .deploy();

4.3 审批超时自动处理

配置边界定时事件实现超时自动通过:

<boundaryEvent id="timeoutEvent" attachedToRef="deptAudit"> <timerEventDefinition> <timeDuration>PT24H</timeDuration> </timerEventDefinition> </boundaryEvent>

5. 系统监控与优化

5.1 流程效率分析

HistoryService historyService = activitiHistoryService; HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery() .processDefinitionKey("leaveProcess"); // 计算平均处理时长 double avgDuration = query.averageDurationInMillis() / (1000 * 60 * 60); log.info("平均审批时长:{}小时", avgDuration); // 各环节耗时统计 List<HistoricActivityInstance> activities = historyService .createHistoricActivityInstanceQuery() .processDefinitionId(processDefinitionId) .orderByHistoricActivityInstanceDuration().asc() .list();

5.2 数据库表优化建议

针对Activiti核心表的优化策略:

表名索引建议清理策略
ACT_RU_TASKASSIGNEE_, PROC_INST_ID_流程结束立即删除
ACT_HI_TASKINSTEND_TIME_, DURATION_定期归档历史数据
ACT_RU_EXECUTIONPROC_INST_ID_, BUSINESS_KEY_保留最近3个月运行实例

5.3 性能压测指标

使用JMeter测试典型场景表现:

场景吞吐量(req/s)平均响应时间(ms)
提交申请120045
审批操作150032
待办列表查询80068

6. 完整源码解析

项目采用分层架构设计:

src/main/java ├── config │ ├── ActivitiConfig # 引擎配置 │ └── SwaggerConfig # 接口文档 ├── controller │ ├── LeaveController # 请假业务接口 │ └── TaskController # 任务处理接口 ├── entity │ ├── LeaveApplication # 请假单实体 │ └── ApproveHistory # 审批记录 ├── listener │ └── LeaveTaskListener # 流程监听器 └── service ├── LeaveService # 业务逻辑 └── ProcessService # 流程服务

关键代码片段说明:

// 历史审批记录查询 public List<ApproveHistory> getHistory(String processInstanceId) { return historyService.createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId) .orderByHistoricTaskInstanceEndTime().asc() .list() .stream() .map(task -> { ApproveHistory history = new ApproveHistory(); history.setTaskName(task.getName()); history.setApprover(task.getAssignee()); history.setComment(taskService.getTaskComments(task.getId()).get(0)); return history; }).collect(Collectors.toList()); }

在调试过程中发现一个典型问题:当并行网关分支设置不当时,可能导致流程实例"挂起"。解决方案是在网关出口添加明确的条件表达式:

<sequenceFlow id="flow1" sourceRef="parallelGateway" targetRef="approval1"> <conditionExpression xsi:type="tFormalExpression"> <![CDATA[${days > 3}]]> </conditionExpression> </sequenceFlow>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/2 4:13:22

别再手动改代码了!用VS Code插件+脚本自动化完成STM32到GD32的工程迁移

极客式工程迁移&#xff1a;用自动化工具链实现STM32到GD32的无缝转换 每次接手老旧STM32项目向GD32平台迁移的任务时&#xff0c;你是否也厌倦了重复修改时钟配置、调整Flash等待周期的机械劳动&#xff1f;作为经历过数十次移植的老手&#xff0c;我总结出一套基于VS Code生态…

作者头像 李华
网站建设 2026/5/2 3:54:23

create-chrome-ext 终极指南:10分钟快速搭建Chrome扩展开发环境

create-chrome-ext 终极指南&#xff1a;10分钟快速搭建Chrome扩展开发环境 【免费下载链接】create-chrome-ext &#x1f37a; Scaffolding your Chrome extension! Boilerplates: react \ vue \ svelte \ solid \ preact \ alpine \ lit \ stencil \ inferno \ vanilla 项目…

作者头像 李华
网站建设 2026/5/2 3:50:09

如何解决F3D中Quake MDL模型背面剔除问题:完整指南

如何解决F3D中Quake MDL模型背面剔除问题&#xff1a;完整指南 【免费下载链接】f3d Fast and minimalist 3D viewer. 项目地址: https://gitcode.com/GitHub_Trending/f3/f3d F3D作为一款快速简洁的3D查看器&#xff0c;在处理Quake MDL模型时可能会遇到背面剔除导致模…

作者头像 李华