Spring Boot 2.x 整合 Activiti 7 工作流引擎:从零搭建一个请假审批Demo

在微服务架构盛行的今天,如何将传统的工作流引擎与现代开发框架无缝整合,成为许多企业级应用开发的关键挑战。Activiti 7作为新一代BPMN 2.0规范的实现,通过与Spring Boot 2.x的深度集成,为开发者提供了更简洁的配置方式和更强大的流程管理能力。本文将以一个真实的"员工请假-部门审批"业务场景为例,带你从零开始构建完整的解决方案。

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

1.1 创建Spring Boot项目

使用Spring Initializr快速生成项目骨架,选择以下核心依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter</artifactId>
        <version>7.1.0.M6</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

1.2 数据库配置

在application.yml中配置数据源和Activiti参数:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/activiti_demo?useSSL=false&serverTimezone=UTC
    username: root
    password: yourpassword
    driver-class-name: com.mysql.cj.jdbc.Driver

activiti:
  database-schema-update: true
  history-level: full
  async-executor-activate: false

关键配置说明:

  • database-schema-update : 设置为true时自动创建表结构
  • history-level : 控制历史记录保存级别
  • async-executor-activate : 是否启用异步任务执行

2. 流程设计与建模

2.1 使用BPMN设计请假流程

在resources/processes目录下创建leave-request.bpmn20.xml文件:

<bpmn2:definitions>
    <bpmn2:process id="leaveProcess" name="员工请假流程">
        <bpmn2:startEvent id="startEvent" />
        <bpmn2:userTask id="applyLeave" name="提交请假申请" 
            activiti:assignee="${applicant}" />
        <bpmn2:userTask id="managerApprove" name="经理审批"
            activiti:assignee="${approver}" />
        <bpmn2:exclusiveGateway id="decisionGateway" />
        <bpmn2:endEvent id="endEvent" />
        
        <!-- 流程连线定义 -->
        <bpmn2:sequenceFlow sourceRef="startEvent" targetRef="applyLeave" />
        <bpmn2:sequenceFlow sourceRef="applyLeave" targetRef="managerApprove" />
        <bpmn2:sequenceFlow sourceRef="managerApprove" targetRef="decisionGateway" />
        <bpmn2:sequenceFlow sourceRef="decisionGateway" targetRef="endEvent">
            <bpmn2:conditionExpression xsi:type="tFormalExpression">
                ${approvalResult == true}
            </bpmn2:conditionExpression>
        </bpmn2:sequenceFlow>
    </bpmn2:process>
</bpmn2:definitions>

2.2 流程变量设计

为请假流程定义关键变量:

变量名 类型 描述
applicant String 申请人ID
approver String 审批人ID
startDate Date 请假开始日期
endDate Date 请假结束日期
reason String 请假原因
approvalResult Boolean 审批结果

3. 业务逻辑实现

3.1 创建请假服务层

@Service
@RequiredArgsConstructor
public class LeaveService {
    private final RuntimeService runtimeService;
    private final TaskService taskService;
    
    public String startLeaveProcess(LeaveRequest request) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("applicant", request.getApplicant());
        variables.put("approver", request.getApprover());
        variables.put("startDate", request.getStartDate());
        variables.put("endDate", request.getEndDate());
        variables.put("reason", request.getReason());
        
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(
            "leaveProcess", variables);
        return instance.getId();
    }
    
    public List<Task> getUserTasks(String userId) {
        return taskService.createTaskQuery()
            .taskAssignee(userId)
            .list();
    }
    
    public void completeTask(String taskId, boolean approved) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("approvalResult", approved);
        taskService.complete(taskId, variables);
    }
}

3.2 构建REST API接口

@RestController
@RequestMapping("/api/leave")
@RequiredArgsConstructor
public class LeaveController {
    private final LeaveService leaveService;
    
    @PostMapping
    public ResponseEntity<String> applyLeave(@RequestBody LeaveRequest request) {
        String processId = leaveService.startLeaveProcess(request);
        return ResponseEntity.ok("流程已启动,ID: " + processId);
    }
    
    @GetMapping("/tasks")
    public ResponseEntity<List<Task>> getTasks(@RequestParam String userId) {
        return ResponseEntity.ok(leaveService.getUserTasks(userId));
    }
    
    @PostMapping("/approve")
    public ResponseEntity<String> approveTask(
            @RequestParam String taskId,
            @RequestParam boolean approved) {
        leaveService.completeTask(taskId, approved);
        return ResponseEntity.ok("任务处理完成");
    }
}

4. 流程监控与管理

4.1 历史数据查询

@Service
@RequiredArgsConstructor
public class ProcessHistoryService {
    private final HistoryService historyService;
    
    public List<HistoricProcessInstance> getCompletedProcesses() {
        return historyService.createHistoricProcessInstanceQuery()
            .finished()
            .list();
    }
    
    public List<HistoricActivityInstance> getProcessActivities(String processId) {
        return historyService.createHistoricActivityInstanceQuery()
            .processInstanceId(processId)
            .orderByHistoricActivityInstanceStartTime()
            .asc()
            .list();
    }
}

4.2 流程可视化

利用Activiti提供的REST API获取流程图:

@GetMapping(value = "/diagram/{processId}", produces = MediaType.IMAGE_PNG_VALUE)
public byte[] getProcessDiagram(@PathVariable String processId) throws IOException {
    ProcessInstance pi = runtimeService.createProcessInstanceQuery()
        .processInstanceId(processId)
        .singleResult();
    
    BpmnModel model = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
    InputStream diagram = new DefaultProcessDiagramGenerator()
        .generateDiagram(model, "png", runtimeService.getActiveActivityIds(pi.getId()));
    
    return IOUtils.toByteArray(diagram);
}

5. 高级配置与优化

5.1 自定义用户任务监听器

@Component
public class LeaveTaskListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        if ("managerApprove".equals(delegateTask.getTaskDefinitionKey())) {
            // 发送审批通知
            String message = String.format(
                "您有一条来自%s的请假申请待审批",
                delegateTask.getVariable("applicant"));
            System.out.println(message);
        }
    }
}

5.2 异步执行器配置

在application.yml中启用异步执行:

activiti:
  async-executor-activate: true
  async-executor-core-pool-size: 5
  async-executor-max-pool-size: 10
  async-executor-queue-capacity: 100

5.3 性能优化建议

  1. 流程实例缓存 :配置流程引擎缓存策略

    @Bean
    public ProcessEngineConfiguration processEngineConfiguration(
            DataSource dataSource, PlatformTransactionManager transactionManager) {
        SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
        config.setDataSource(dataSource);
        config.setTransactionManager(transactionManager);
        config.setDatabaseSchemaUpdate("true");
        config.setAsyncExecutorActivate(true);
        config.setProcessDefinitionCacheLimit(100);
        return config;
    }
    
  2. 批量操作 :对于大量任务处理使用批量API

    taskService.createTaskQuery()
        .taskAssignee("user1")
        .listPage(0, 100)
        .forEach(task -> taskService.complete(task.getId()));
    
  3. 历史数据归档 :定期归档历史数据减少主表压力

6. 常见问题排查

6.1 流程无法启动

检查步骤:

  1. 确认流程定义已正确部署
    repositoryService.createProcessDefinitionQuery()
        .processDefinitionKey("leaveProcess")
        .list();
    
  2. 验证必要流程变量是否设置
  3. 检查Activiti自动配置日志

6.2 任务分配异常

典型解决方案:

  • 确保assignee变量已正确设置
  • 实现自定义任务分配逻辑
    taskService.setAssignee(taskId, newAssignee);
    

6.3 性能瓶颈处理

监控指标:

ManagementService managementService = processEngine.getManagementService();
TablePage tablePage = managementService.createTablePageQuery()
    .tableName("ACT_RU_TASK")
    .listPage(0, 100);

优化方向:

  • 增加异步执行器线程池
  • 优化数据库索引
  • 拆分复杂流程为子流程

7. 安全与权限控制

7.1 集成Spring Security

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/api/leave/**").authenticated()
            .and()
            .httpBasic();
    }
}

7.2 流程数据权限过滤

taskService.createTaskQuery()
    .taskCandidateOrAssigned(userId)
    .list();

7.3 敏感数据保护

对流程变量进行加密处理:

variables.put("reason", encryptService.encrypt(reason));

8. 测试策略

8.1 单元测试配置

@SpringBootTest
@ActivitiTest
public class LeaveProcessTest {
    @Autowired
    private RuntimeService runtimeService;
    
    @Test
    public void testLeaveProcess() {
        // 测试流程启动和任务分配
        Map<String, Object> vars = new HashMap<>();
        vars.put("applicant", "user1");
        vars.put("approver", "manager1");
        
        ProcessInstance instance = runtimeService
            .startProcessInstanceByKey("leaveProcess", vars);
        assertNotNull(instance);
    }
}

8.2 集成测试要点

测试场景覆盖:

  1. 正常审批流程
  2. 审批拒绝路径
  3. 多实例并发处理
  4. 超时自动处理

8.3 性能测试建议

使用JMeter模拟:

  • 并发流程启动
  • 批量任务处理
  • 长时间运行流程监控

9. 部署与运维

9.1 Docker容器化部署

示例Dockerfile:

FROM openjdk:11-jre
COPY target/leave-app.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

9.2 数据库迁移策略

使用Liquibase管理数据库变更:

<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
</dependency>

9.3 监控端点配置

启用Actuator端点:

management:
  endpoints:
    web:
      exposure:
        include: health,info,activiti

10. 扩展与定制

10.1 自定义表单集成

集成方案选择:

  • 直接使用流程变量
  • 关联外部表单数据
  • 实现动态表单引擎

10.2 多租户支持

配置多数据源策略:

@Bean
public MultiTenantProcessEngineConfiguration processEngineConfiguration() {
    MultiTenantProcessEngineConfiguration config = new MultiTenantProcessEngineConfiguration();
    config.setTenantConfigurator(new CustomTenantConfigurator());
    return config;
}

10.3 移动端适配

构建轻量级API:

@GetMapping("/mobile/tasks")
public List<MobileTask> getMobileTasks(@RequestParam String userId) {
    return taskService.createTaskQuery()
        .taskAssignee(userId)
        .list()
        .stream()
        .map(this::convertToMobileTask)
        .collect(Collectors.toList());
}
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐