flowable的多人會簽和一票否決


項目結構:

接下來代碼:

Duorenhuiqian.bpmn20.xml:

<?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:flowable="http://flowable.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.flowable.org/processdef">
  <process id="countersign" name="Duorenhuiqian" isExecutable="true">
    <startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
    <userTask id="UserTask1" name="U1" flowable:assignee="${assignee}" flowable:formFieldValidation="true">
      <extensionElements>
        <!--<flowable:executionListener event="start" class="com.cars.ngtdms.cooperation.flowable.listener.CountersignListener"></flowable:executionListener>-->
        <flowable:executionListener event="start" delegateExpression="${countersignListener}"></flowable:executionListener>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
      <multiInstanceLoopCharacteristics isSequential="false" flowable:collection="assigneeList" flowable:elementVariable="assignee">
        <completionCondition>${multiInstance.accessCondition(execution)}</completionCondition>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <sequenceFlow id="sid-50622098-77B0-4413-A1D4-088B47DEC95F" sourceRef="startEvent1" targetRef="UserTask1"></sequenceFlow>
    <userTask id="UserTask2" name="U2" flowable:assignee="WXF" flowable:formFieldValidation="true">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <endEvent id="sid-814B8939-308D-4003-8B35-B750DC8F8A5C"></endEvent>
    <exclusiveGateway id="getWay" name="getWay"></exclusiveGateway>
    <userTask id="UserTask3" name="U3" flowable:assignee="PXY" flowable:formFieldValidation="true">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <endEvent id="sid-4C2BFAF2-08AC-4F89-A964-046EA583F0B5"></endEvent>
    <sequenceFlow id="sid-CE25CF8A-5BF2-4227-A747-98F6A053283E" sourceRef="UserTask3" targetRef="sid-4C2BFAF2-08AC-4F89-A964-046EA583F0B5"></sequenceFlow>
    <sequenceFlow id="sid-0F397F15-5685-4DF0-B7E0-75C3AB43F6D8" sourceRef="UserTask2" targetRef="sid-814B8939-308D-4003-8B35-B750DC8F8A5C"></sequenceFlow>
    <sequenceFlow id="sid-74E664CC-0FC9-49A6-A47C-BCFA1198F074" sourceRef="UserTask1" targetRef="getWay"></sequenceFlow>
    <sequenceFlow id="repply" name="通過" sourceRef="getWay" targetRef="UserTask2">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通過'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="reject" name="否決" sourceRef="getWay" targetRef="UserTask3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='否決'}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_countersign">
    <bpmndi:BPMNPlane bpmnElement="countersign" id="BPMNPlane_countersign">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="135.0" y="290.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="UserTask1" id="BPMNShape_UserTask1">
        <omgdc:Bounds height="80.0" width="100.0" x="255.0" y="265.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="UserTask2" id="BPMNShape_UserTask2">
        <omgdc:Bounds height="80.0" width="100.0" x="495.0" y="120.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-814B8939-308D-4003-8B35-B750DC8F8A5C" id="BPMNShape_sid-814B8939-308D-4003-8B35-B750DC8F8A5C">
        <omgdc:Bounds height="28.0" width="28.0" x="750.0" y="146.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="getWay" id="BPMNShape_getWay">
        <omgdc:Bounds height="40.0" width="40.0" x="525.0" y="285.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="UserTask3" id="BPMNShape_UserTask3">
        <omgdc:Bounds height="80.0" width="100.0" x="495.0" y="405.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-4C2BFAF2-08AC-4F89-A964-046EA583F0B5" id="BPMNShape_sid-4C2BFAF2-08AC-4F89-A964-046EA583F0B5">
        <omgdc:Bounds height="28.0" width="28.0" x="645.0" y="431.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-50622098-77B0-4413-A1D4-088B47DEC95F" id="BPMNEdge_sid-50622098-77B0-4413-A1D4-088B47DEC95F">
        <omgdi:waypoint x="164.94999923927443" y="305.0"></omgdi:waypoint>
        <omgdi:waypoint x="255.0" y="305.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-74E664CC-0FC9-49A6-A47C-BCFA1198F074" id="BPMNEdge_sid-74E664CC-0FC9-49A6-A47C-BCFA1198F074">
        <omgdi:waypoint x="354.9499999999567" y="305.10384615384606"></omgdi:waypoint>
        <omgdi:waypoint x="525.4583333333242" y="305.4583333333333"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="reject" id="BPMNEdge_reject">
        <omgdi:waypoint x="545.431654676259" y="324.51130481667866"></omgdi:waypoint>
        <omgdi:waypoint x="545.1431899641577" y="405.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-0F397F15-5685-4DF0-B7E0-75C3AB43F6D8" id="BPMNEdge_sid-0F397F15-5685-4DF0-B7E0-75C3AB43F6D8">
        <omgdi:waypoint x="594.9499999999925" y="160.0"></omgdi:waypoint>
        <omgdi:waypoint x="750.0" y="160.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="repply" id="BPMNEdge_repply">
        <omgdi:waypoint x="545.4310344827586" y="285.4310344827586"></omgdi:waypoint>
        <omgdi:waypoint x="545.1372852233677" y="199.95"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-CE25CF8A-5BF2-4227-A747-98F6A053283E" id="BPMNEdge_sid-CE25CF8A-5BF2-4227-A747-98F6A053283E">
        <omgdi:waypoint x="594.9499999997366" y="445.0"></omgdi:waypoint>
        <omgdi:waypoint x="645.0" y="445.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
application.yml:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/foujueflowable?characterEncoding=UTF-8
    password: root
    username: root
    driver-class-name: com.mysql.jdbc.Driver
flowable:
  #關閉定時任務job
  async-executor-activate: false
scale: 0.5
 
assignee: person1,person2,person3,person4
 
yipiaofoujueren: pxy
ExpenseController:
package com.cars.ngtdms.cooperation.controller;
 
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
import java.util.*;
 
@Controller
 
@RequestMapping(value = "expense")
@ResponseBody
public class ExpenseController {
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessEngine processEngine;
 
    @Value("#{'${yipiaofoujueren}'.split(',')}")
    private List yipiaofoujueren;
 
 
    /**
     * 開啟
     * @return
     */
    @RequestMapping(value = "add")
    public String StartTask(){
        runtimeService.startProcessInstanceByKey("countersign");
        return "OK";
    }
 
 
 
    /**
     * 執行
     * @return
     */
    @RequestMapping(value = "do")
    public List<String> DoTask(String name){
       // List<Task> tasks = taskService.createTaskQuery().taskCandidateUser(name).list();
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(name).list();
        List<String> list = new ArrayList<>();
        System.out.println("[");
        for (Task task:tasks
             ) {
 
            System.out.println(task.getId());
            list.add("id:"+task.getId()+"   name:"+task.getName()+"    Assignee:"+task.getAssignee());
 
        }
        System.out.println("]");
        return list;
    }
 
 
    /**
     * 完成
     * @return
     */
    @RequestMapping(value = "done")
    @Transactional
    public String DoneTask(String name,String taskId,String flg){
        List<Task> list = taskService.createTaskQuery().taskAssignee(name).list();
        List<String> taskList= new ArrayList<>();
        String taskId1="";
        for (Task task : list) {
            taskList.add("id:"+task.getId()+"name"+task.getName()+"審批人:"+task.getAssignee());
            taskId1 = task.getId();
            System.out.println(taskId);
        }
        System.out.println("完成前"+taskList);
       if ("n".equals(flg)){
            if (yipiaofoujueren.contains(name)){
                Map<String,Object> map = new HashMap<>();
                Integer reject = (int)taskService.getVariable(taskId1,"reject");
                map.put("reject",reject+1);
                taskService.complete(taskId,map);
            }else {
                Map<String,Object> map = new HashMap<>();
                Integer rejectPeson = (int)taskService.getVariable(taskId1,"rejectPeson");
                map.put("rejectPeson",rejectPeson+1);
                taskService.complete(taskId,map);
 
            }
        } else if ("y".equals(flg)){
           Map<String,Object> map = new HashMap<>();
           Integer agreePeson = (int)taskService.getVariable(taskId1,"agreePeson");
           map.put("agreePeson",agreePeson+1);
           taskService.complete(taskId,map);
       }
 
        List<Task> list1 = taskService.createTaskQuery().taskAssignee(name).list();
        List<String> taskList1= new ArrayList<>();
        for (Task task : list1) {
            taskList1.add("id:"+task.getId()+"name"+task.getName()+"審批人:"+task.getAssignee());
        }
        System.out.println("完成后"+taskList1);
        return "通過";
    }
 
 
    /**
     * 查看當前任務名
     * @return
     */
    @RequestMapping(value = "select")
    public List<String> SelectTask(){
        List<Task> list = taskService.createTaskQuery().list();
        List<String> taskList=new ArrayList<>();
        for (Task task : list) {
            taskList.add(task.getId()+"-----------"+task.getName());
 
        }
 
        return taskList;
    }
 
 
 
}
CountersignListener:
package com.cars.ngtdms.cooperation.flowable.listener;
 
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
 
import java.util.HashMap;
import java.util.List;
@Component
public class CountersignListener implements ExecutionListener {
    @Value("#{'${assignee}'.split(',')}")
    private List list;
    @Override
    public void notify(DelegateExecution delegateExecution) {
        System.out.println("讀取的審批人是:"+list);
            HashMap<String, Object> map = new HashMap<>();
            //定義的人員列表4人
            //String[] person = { "person1", "person2", "person3","pxy" };
            //map.put("assigneeList", Arrays.asList(person));
            map.put("assigneeList", list);
            map.put("reject", 0);
            map.put("rejectPeson", 0);
            map.put("agreePeson", 0);
            delegateExecution.setVariables(map);
 
    }
}
ApplicationPxy:
package com.cars.ngtdms.cooperation;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
 
@SpringBootApplication
//@EnableDiscoveryClient
public class ApplicationPxy {
 
    public static void main(String[] args) {
        SpringApplication.run(ApplicationPxy.class,args);
    }
}
MultiInstanceCompleteTask:
package com.cars.ngtdms.cooperation;
 
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
import java.io.Serializable;
 
@Component(value = "multiInstance")
public class MultiInstanceCompleteTask implements Serializable{
    /**
     * 評估結果判定條件
     * @param execution 分配執行實例
     */
    @Value("${scale}")
    private String scaleStr;
 
 
    public boolean accessCondition(DelegateExecution execution) {
        Double scale = Double.valueOf(scaleStr);
        System.out.println("比例是:"+scale);
        System.out.println("I am running!!!!!!");
        System.out.println("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT");
        //已完成的實例數
        int completedInstance = (int) execution.getVariable("nrOfCompletedInstances");
        System.out.println("此時已完成的實例數為:"+completedInstance);
        //否決判斷,一票否決
        if (execution.getVariable("reject") != null) {
            int rejectCount = (int) execution.getVariable("reject");
            System.out.println("reject:"+rejectCount);
            if (rejectCount > 0) {
                //輸出方向為拒絕
                execution.setVariable("outcome", "否決");
                //一票否決其他實例沒必要做,結束
                return true;
            }
        }
        //獲取所有的實例數
        int AllInstance = (int)execution.getVariable("nrOfInstances");
        System.out.println("總實例數目:"+AllInstance);
        //獲取不同意的次數
        int rejectPeson = (int)execution.getVariable("rejectPeson");
        System.out.println("不同意的人的個數為:"+rejectPeson);
        //獲取同意人的次數
        int agreePeson = (int)execution.getVariable("agreePeson");
        System.out.println("同意的人的個數為:"+agreePeson);
 
 
        //所有實例任務未全部做完則繼續其他實例任務
        if (completedInstance != AllInstance) {
            //加入不同意的人數大於設置比例*總人數
            if (rejectPeson*1.00/AllInstance>(1-scale)){
                execution.setVariable("outcome", "否決");
                return true;
            }
            if (agreePeson*1.00/AllInstance>=scale){
                execution.setVariable("outcome", "通過");
                return true;
            }
 
            return false;
        } else {
            //輸出方向為贊同
            execution.setVariable("outcome", "通過");
            //所有都做完了沒被否決,結束
            return true;
        }
 
 
 
    }
}
依賴:

 <!--flowable工作流依賴-->
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter</artifactId>
            <version>6.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>

 

好了 這樣就可以直接運行了,數據庫的名字要設置對

 

然后開始解釋:

多人會簽意思是這一個任務需要很多人來進行審批,同意總數超過或者未超過多少比例的時候會執行對應的某個任務。

還有個就是一票否決,指定某個人,它反對就直接相當於全部反對

代碼解釋:

首先配置文件application:

然后xml文件:

標簽的具體工作原理這里不再贅述,可以自行百度

然后就是監聽器CountersignListener:

然后就是執行器的配置內容了MultiInstanceCompleteTask:

有點長久分開截屏寫了

箭頭指向的地方就是一票否決,在監聽器里邊對reject進行了初始化,這里通過獲取reject來判斷它的值如果大於零就直接否決,

我這里為了能體現否決和同意,我一共設置了三個任務,第一個任務是會簽,第二個任務和第三個任務一個是同意一個是否決對應的任務,他們是通過路由進行相關聯的,路由判斷outcome是"否決"還是"通過"然后路由到第二個任務或者第三個任務

他這個方法呢 如果是返回的true,那么就直接結束第一個會簽任務,如果返回的是false那么會繼續執行第一個會簽任務

接下來繼續:

這里有個小BUG  如果一票否決的人還沒有執行,那么但凡執行了上邊的那個通過,那這個任務就直接跳過去了,他就不能一票否決了,其實這里可以進行判斷,如果這里一票否決的人沒有執行就讓它返回false。

然后繼續來看ExpenseController類:

好的 接下來第一個方法,根據審批人的ID來獲取任務的ID:

第二個方法,根據審批人的名字、任務的id、flg來進行執行任務

這里要注意了!!!!這里是flg不是flag

審批人的名字就不用說了,任務id就是第一個方法獲取的任務的id,flg呢就是來判斷是否同意的,n代表不同意,y代表同意

這里比較簡單,代碼上也有注釋,就解釋一下邏輯處理這一點好了:

很好,然后第三個方法!:

它就是來查看當前xml就是這個flowable的當前任務,專業術語我忘記怎么說了,emmm  當前實例?不行 不行 忘記了

執行它可以到執行到哪個任務了

好了 沒了 就這樣了 emmmm  這里寫的是審批人是相當於直接塞進去的,也可以手動的塞進去,就是add的那個方法,在進行加載xml的時候,創建一個map,然后序列化一下,放到那個方法的第二個參數的位置就行了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM