springboot intègre la configuration parallèle série de tâches Activiti-multi-instance

Ce billet de blog fait référence à la
tâche multi-instance d'activité de blogueur suivante
[nèng - Activiti6] Premiers pas avec Activiti6 (7) - Tâche multi-instance
Activiti combat réel (5) : contresigne

La différence entre multi-instance série et parallèle

  1. Parallèle signifie procéder en même temps. Par exemple, si une tâche est assignée à n personnes pour traitement, ces n personnes recevront la tâche en même temps et pourront la traiter en même temps sans être affectées par chacune d'elles.
    Le nœud act_ru_task configuré avec plusieurs instances aura plusieurs données de tâches.

  2. En série signifie qu'une fois le travail ou la tâche terminé par une personne, il est traité par une autre personne jusqu'à ce qu'il soit complètement terminé, et chaque tâche dépend de l'achèvement de la tâche précédente.
    Le nœud act_ru_task configuré avec plusieurs instances n'a toujours qu'une seule donnée pour ce nœud.

Une configuration parallèle bpmn

Un processus simple pour configurer le parallélisme dans les tâches utilisateur. (Je ne parlerai pas de série, si vous comprenez le parallèle, vous comprenez aussi la série)

diagramme bpmn

insérer la description de l'image ici

XML de l'instance de flux de travail

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
  <process id="cq" name="产权工作流" isExecutable="true">
    <documentation>产权会签</documentation>
    <startEvent id="sid-start" name="开始会签"/>
    <userTask id="sid-task2" name="村民表决" activiti:assignee="${assignee}">
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="assigneeList" activiti:elementVariable="assignee">
        <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.5 || pass == true}</completionCondition>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <userTask id="sid-task3" name="镇街审核" activiti:assignee="${assignee}"/>
    <endEvent id="sid-end" name="结束"/>
    <sequenceFlow id="sid-45a0cbe9-6112-4a07-b95c-62545a0171fa" sourceRef="sid-task3" targetRef="sid-end"/>
    <userTask id="sid-task1" name="填写申请资料" activiti:assignee="${assignee}"/>
    <sequenceFlow id="sid-661add14-02b3-4794-b440-edf1798c82a8" sourceRef="sid-start" targetRef="sid-task1"/>
    <sequenceFlow id="sid-19cfbdbf-01f9-4c8d-9614-31300dbe461a" sourceRef="sid-task1" targetRef="sid-task2"/>
    <exclusiveGateway id="sid-gateway"/>
    <sequenceFlow id="sid-c8eeefa1-2f24-4daf-9e15-90d462529992" sourceRef="sid-task2" targetRef="sid-gateway"/>
    <sequenceFlow id="sid-d054bb13-bf87-46e2-9649-5044b9416f6d" sourceRef="sid-gateway" targetRef="sid-task3" name="通过">
      <conditionExpression xsi:type="tFormalExpression">${pass==true}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="sid-92a9d1a2-f73c-46de-b493-44a0b56e3e21" sourceRef="sid-gateway" targetRef="sid-task1" name="拒绝">
      <conditionExpression xsi:type="tFormalExpression">${pass=false}</conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_cq">
    <bpmndi:BPMNPlane bpmnElement="cq" id="BPMNPlane_cq">
      <bpmndi:BPMNShape id="shape-85388f7c-e845-43d0-b84b-6679cefb3110" bpmnElement="sid-start">
        <omgdc:Bounds x="-110.0" y="-15.0" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-3fab3d96-c577-44b1-a1b3-f6a6249a14bc" bpmnElement="sid-task2">
        <omgdc:Bounds x="195.0" y="-40.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-08995250-1075-40e2-b92c-a5dd140fbcd5" bpmnElement="sid-task3">
        <omgdc:Bounds x="475.0" y="-40.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-d8775c65-537f-49d1-a05a-b65fef4d4ee8" bpmnElement="sid-end">
        <omgdc:Bounds x="650.0" y="-15.0" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-2d6eaf90-8343-4483-92c6-716781168133" bpmnElement="sid-45a0cbe9-6112-4a07-b95c-62545a0171fa">
        <omgdi:waypoint x="575.0" y="0.0"/>
        <omgdi:waypoint x="650.0" y="0.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-ed57a314-acc1-410e-8cd0-e6cc1c022668" bpmnElement="sid-task1">
        <omgdc:Bounds x="0.0" y="-40.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-62841ec0-6a53-44ff-a21f-529024508c08" bpmnElement="sid-661add14-02b3-4794-b440-edf1798c82a8">
        <omgdi:waypoint x="-80.0" y="0.0"/>
        <omgdi:waypoint x="0.0" y="0.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-92c7b154-d003-40cd-b8b4-cd1a25fbc533" bpmnElement="sid-19cfbdbf-01f9-4c8d-9614-31300dbe461a">
        <omgdi:waypoint x="100.0" y="0.0"/>
        <omgdi:waypoint x="195.0" y="0.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-3a522932-3abf-4cf8-977f-e6dd0a5abdac" bpmnElement="sid-gateway">
        <omgdc:Bounds x="365.0" y="-20.0" width="40.0" height="40.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-f35924a4-0134-4585-8933-81aa7e821c26" bpmnElement="sid-c8eeefa1-2f24-4daf-9e15-90d462529992">
        <omgdi:waypoint x="295.0" y="0.0"/>
        <omgdi:waypoint x="365.0" y="0.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-1ea70a14-127d-4ddd-8339-b389d61b3654" bpmnElement="sid-d054bb13-bf87-46e2-9649-5044b9416f6d">
        <omgdi:waypoint x="405.0" y="0.0"/>
        <omgdi:waypoint x="475.0" y="0.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-3cc368c6-0af2-4635-a4d4-27358568222b" bpmnElement="sid-92a9d1a2-f73c-46de-b493-44a0b56e3e21">
        <omgdi:waypoint x="385.0" y="-20.0"/>
        <omgdi:waypoint x="385.0" y="-127.50001"/>
        <omgdi:waypoint x="55.0" y="-127.500015"/>
        <omgdi:waypoint x="55.0" y="-40.0"/>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Instructions de configuration multi-instance

<userTask id="sid-task2" name="村民表决" activiti:assignee="${assignee}">
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="assigneeList" activiti:elementVariable="assignee">
        <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.5 || pass == true}</completionCondition>
      </multiInstanceLoopCharacteristics>
</userTask>
  1. isSequential false est parallèle, true est série
  2. CompletionCondition est le jugement conditionnel de plusieurs instances
  3. pass est ma variable personnalisée, les autres sont des variables intégrées

Description de la variable intégrée de l'attribut multi-instance, les variables de l'élément Completondition sont essentiellement intégrées et vous n'avez pas besoin de transmettre de paramètres, sauf que la passe est personnalisée par moi, vous devez donc transmettre des paramètres

1.nrOfActiveInstances Le nombre d'instances actuellement actives, c'est-à-dire le nombre d'instances qui ne sont pas encore terminées. Nombre d'instances actuellement actives, toujours 1 pour l'exécution séquentielle (série) de plusieurs instances.

2.loopCounter a des temps en boucle

3. nrOfInstances nombre total d'instances

4.nrOfCompletedInstances Nombre d'instances terminées

Ainsi, le code suivant signifie que plus de la moitié du nombre total de participants peuvent passer et circuler vers le nœud suivant

<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.5 || pass == true}

Hors sujet : loopCardinality boucle deux fois avant de passer au nœud suivant, généralement il ne sera pas écrit à mort

<multiInstanceLoopCharacteristics isSequential="true">
  <loopCardinality>2</loopCardinality>
</multiInstanceLoopCharacteristics>

Je n'ai pas utilisé loopCardinality
insérer la description de l'image ici

2. Démarrage du processus

1. Processus de déploiement

//使用RepositoryService进行部署
 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
 RepositoryService repositoryService = processEngine.getRepositoryService();
 //使用RepositoryService进行部署
 DeploymentBuilder builder = repositoryService.createDeployment();
 Deployment deployment = builder
                             .addClasspathResource("bpmn/cq/cq.bpmn20.xml")
                             .addClasspathResource("bpmn/cq/cq.png")
                             .name("产权工作流").deploy();


 //输出部署信息
 System.out.println("流程部署id:" + deployment.getId());
 System.out.println("流程部署名称:" + deployment.getName());

Une fois le déploiement réussi, vous pouvez voir les données dans le tableau suivant, le noyau est act_re_procdef (définition du processus déployé

act_ge_bytearray (définition de processus générique et table de ressources de processus)
insérer la description de l'image ici

act_re_deployment (informations sur l'unité de déploiement)
insérer la description de l'image ici

act_re_procdef (définition de processus déployé)
insérer la description de l'image ici

2. Processus de démarrage

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();

Map<String, Object> variables = new HashMap<>();
variables.put("assignee","小强");
//根据流程定义Id启动流程
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("cq",variables);

//输出实例信息
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("当前活动Id:" + processInstance.getActivityId());

3. Configuration dynamique

Description du paramètre :

activiti:assignee="${assignee}"
activiti:elementVariable="assignee" #多实例任务依赖上面的配置${
    
    assignee}
activiti:collection="assigneeList" #你需要传参的变量

exemple

<userTask id="sid-task2" name="村民表决" activiti:assignee="${assignee}">
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="assigneeList" activiti:elementVariable="assignee">
        <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.5 || pass == true}</completionCondition>
      </multiInstanceLoopCharacteristics>
</userTask>

effectuer des tâches

 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        TaskService taskService = processEngine.getTaskService();
        //根据流程key和任务的负责人查询任务并选择其中的一个任务处理,这里用的
        //是singleResult返回一条,真实环境中是通过步骤5中查询出所有的任务,然后在页面上选择一个任务进行处理.
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("cq") //流程Key
                .taskAssignee("小强")  //要查询的负责人
                .singleResult();

        if(task!=null){
    
    
            Map<String, Object> variables = new HashMap<>();
            List<String> list = Arrays.asList("小红", "小张", "小李");
            variables.put("assigneeList", list);
            //完成任务,参数:任务id
            taskService.complete(task.getId(),variables);

            System.out.println("任务执行成功");

        }else {
    
    
            System.out.println("无任务执行");
        }

Parce que j'ai configuré en parallèle et défini Xiaohong, Xiaozhang et Xiaoli, donc lorsque le flux va vers le nœud multi-instance, vous verrez les données de trois tâches. S'il est en série, vous ne verrez toujours qu'une seule donnée, etc. il exécute, d'autres données de tâche apparaîtront.

insérer la description de l'image ici

Lorsque le flux est transféré vers un nœud multi-instance, vous pouvez le tester vous-même. Lorsque plus de la moitié des utilisateurs sont exécutés ou pass=true, vous passerez au nœud suivant

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        TaskService taskService = processEngine.getTaskService();
        //根据流程key和任务的负责人查询任务并选择其中的一个任务处理,这里用的
        //是singleResult返回一条,真实环境中是通过步骤5中查询出所有的任务,然后在页面上选择一个任务进行处理.
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("cq") //流程Key
                .taskAssignee("小张")  //要查询的负责人
                .singleResult();

        if(task!=null){
    
    
            //Map<String, Object> variables = new HashMap<>();

            //variables.put("pass", true);

            //完成任务,参数:任务id
            //taskService.complete(task.getId(),variables);

            taskService.complete(task.getId());

            System.out.println("任务执行成功");

        }else {
    
    
            System.out.println("无任务执行");
        }

Quatre. Résumé

ps : S'il y a des dizaines, des centaines ou des milliers de personnes qui signeront, il n'est pas recommandé de l'utiliser, sinon il sera difficile de dépanner en cas de problème.
Le programme ci-dessus a résolu des problèmes couramment utilisés concernant la contre-signature, l'inscription, la réduction de signature, la déconnexion, la configuration du poids, la configuration des conditions de réussite personnalisées (condition de réussite personnalisée)

<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.25}</completionCondition> 完成条件的配置。

Si vous utilisez le mode série pour opérer, la variable nrOfActiveInstances est toujours 1, car l'opération +1 ne sera effectuée qu'en parallèle.

Je suppose que tu aimes

Origine blog.csdn.net/qq407995680/article/details/132597980
conseillé
Classement