Spring Boot application integration Activiti workflow engine

Integrating the Activiti workflow engine into a Spring Boot application generally requires the following steps:

Add the following dependencies to the pom.xml file

<dependency>
  <groupId>org.activiti</groupId>
  <artifactId>activiti-spring-boot-starter-basic</artifactId>
  <version>${activiti.version}</version>
</dependency>

<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>${mybatis.version}</version>
</dependency>

Configure data sources. For example:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456

Configure Activiti, for example:

activiti:
  database-schema-update: true
  database-reduce-time-to-live: true
  async-executor-activate: true
  history-level: full
  check-process-definitions: true
  process-definitions:
    deploy-resources: classpath*:/processes/*.bpmn20.xml
    allow-multiple: true
  id-generator: org.activiti.engine.impl.persistence.StrongUuidGenerator
  jdbc-batch-processing: true
  job-execution:
    activate: true
    max-jobs-per-acquisition: 5
    wait-time-in-millis: 5000
  mail:
    enabled: false

Load a BPMN file and deploy a process definition, for example:

  @PostConstruct
  private void initProcessDefinitions() {
    final Set<String> deploymentResourceNames = resourceResolver.getResourcesAsStream("/processes/*.bpmn20.xml")
                                          .map(resource -> resource.getFilename())
                                          .collect(Collectors.toSet());
    deploymentResourceNames.forEach(resourceName -> {
      final String processDefinitionId = repositoryService.createDeployment()
                    .addClasspathResource("processes/" + resourceName)
                    .name(resourceName)
                    .deploy()
                    .getId();
      log.info("ProcessDefinition <{}> deployed with id: <{}>", resourceName, processDefinitionId);
    });
  }

Write Activiti related service code, for example:

@Service
public class MyWorkflowService {
  private final ProcessEngine processEngine;

  @Autowired
  public MyWorkflowService(final ProcessEngine processEngine) {
    this.processEngine = processEngine;
  }

  public Execution startWorkflow() {
    return processEngine.getRuntimeService().startProcessInstanceByKey("myProcessKey");
  }

  public List<Task> getTasksByUser(final String user) {
    return processEngine.getTaskService().createTaskQuery()
              .taskAssignee(user)
              .list();
  }

  public void completeTask(final String taskId) {
    processEngine.getTaskService().complete(taskId);
  }
}

Activiti is more suitable for larger, complex business processes.

In the Activiti workflow engine, the specific implementation of rejecting a task may vary, but generally the following two solutions can be used:

Historical task restart: re-import the execution history of the current task into the process instance, thereby restarting the process. It can be achieved by the following code:

TaskEntity currentTask = (TaskEntity) taskService.createTaskQuery()
                            .taskId(taskId)
                            .singleResult();
String processInstanceId = currentTask.getProcessInstanceId();
HistoricTaskInstanceEntity historicTask = (HistoricTaskInstanceEntity) historyService.createHistoricTaskInstanceQuery()
                                                        .processInstanceId(processInstanceId)
                                                        .taskId(taskId)
                                                        .singleResult();
List<HistoricTaskInstanceEntity> toRollbackTasks = historyService.createHistoricTaskInstanceQuery()
                                                      .processInstanceId(processInstanceId)
                                                      .taskDefinitionKey(historicTask.getTaskDefinitionKey())
                                                      .orderByTaskCreateTime()
                                                      .asc()
                                                      .list();
String activityId = toRollbackTasks.get(0).getTaskDefinitionKey();
runtimeService.createProcessInstanceModification(processInstanceId)
              .cancelAllForActivity(activityId)
              .startBeforeActivity(activityId)
              .processInstanceVariable("taskRejectReason", rejectReason)
              .execute(true, true);

Transfer to the previous task node: transfer the current task to the previous task node, and set the approval status of the current task to rejected. It can be achieved by the following code:

Task currentTask = taskService.createTaskQuery()
                         .taskId(taskId)
                         .singleResult();
String currentActivityId = currentTask.getTaskDefinitionKey();
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
                                                            .processInstanceId(currentTask.getProcessInstanceId())
                                                            .activityType("userTask")
                                                            .finished()
                                                            .orderByHistoricActivityInstanceEndTime()
                                                            .desc()
                                                            .list();
if (historicActivityInstances.size() > 1) {
  String previousActivityId = historicActivityInstances.get(0).getActivityId();
  taskService.addComment(taskId, processInsId, comment);
  taskService.complete(taskId, Map.of("status", "rejected", "destination", previousActivityId));
}

It should be noted that the code provided here is just a sample code, and the specific implementation process and details may be different. Developers need to make corresponding modifications and adjustments according to their actual situation. At the same time, it should be noted that the rejection operation may affect the normal flow of workflow, so it needs to be used with caution in actual operation.

Guess you like

Origin blog.csdn.net/u013558123/article/details/131260981