天天看點

SpringBoot內建工作流引擎

Activiti5是由Alfresco軟體在2010年5月17日釋出的業務流程管理(BPM)架構,它是覆寫了業務流程管理、工作流、服務協作等領域的一個開源的、靈活的、易擴充的可執行流程語言架構。Activiti基于Apache許可的開源BPM平台,創始人Tom Baeyens是JBoss jBPM的項目架構師,它特色是提供了eclipse插件,開發人員可以通過插件直接繪畫出業務 流程圖。.

二、Activiti插件安裝

關于activiti建議在eclipse下安裝相關插件,idea下安裝的actiBPMN有很多問題,界面也不是很友好。

下圖是eclipse下繪制的一個流程圖:

SpringBoot內建工作流引擎

一個簡單的工作流包括開始節點,流程節點和結束節點。

三、SpringBoot內建Activiti

這裡我們用的是activiti6.0版本,主要需要如下包:

<dependency>
 <groupId>org.activiti</groupId>
 <artifactId>activiti-spring-boot-starter-basic</artifactId>
 <version>6.0.0</version>
</dependency>
<!--mysql驅動-->
<dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>5.1.29</version>
</dependency>      

application.yml主要配置如下:

server:
 port: 8801
spring:
 datasource:
 url: jdbc:mysql://10.168.xx.xx:8106/uaf_activiti?Unicode=true&characterEncoding=UTF-8
 username: root
 password: xxxxx
 activiti:
 database-schema-update: true
 check-process-definitions: false      

以上為基本配置,完成上述配置後我們啟動activiti服務系統會自動初始表到我們mysql庫。

四、監聽方式配置Activiti流程

我們一般配置activiti流程的時候代理人都是寫死的方式,這樣若修改代理人時需要重新部署流程。

activiti也支援靈活的方式配置代理人,主要有兩種方式:

  1. 動态參數方式。
  2. 監聽方式。

這裡我們介紹監聽方式,配置監聽方式首先我們需要定義activiti的監聽類:

public class ActProcessListener implements TaskListener {

  /**流程監聽成員變量*/
  private FixedValue processCode;

  @Override
  public void notify(DelegateTask delegateTask) {
    //TODO 建立流程節點與審批使用者/角色關聯表,實作流程動态監聽
    String process = String.valueOf(processCode.getValue(delegateTask));
    MySlf4j.textInfo("進入{0}流程節點監聽.....", process);
    if ("leaveApply".equals(process)) {
      delegateTask.addCandidateUser("will");
    } else if ("deptManagerAppr".equals(process)) {
      delegateTask.addCandidateUser("deman");
    } else if ("hrClerkAppr".equals(process)) {
      delegateTask.addCandidateUser("petty");
    } else if ("hrManagerAppr".equals(process)) {
      delegateTask.addCandidateUser("may");
    }

  }
}      
通過監聽方式,流程可以自動判斷下一節點的受理人,我們也可以将監聽配置放到資料庫管理,實作真正意義上的動态配置。

工作流需要管理相應的監聽類,并指定監聽成員變量。如下圖:

SpringBoot內建工作流引擎

五、工作流引擎執行

工作流程引擎一般包括如下步驟:

SpringBoot內建工作流引擎

相關接口代碼如下:

/**部署流程*/
ActProcessRespVo deployProcess(ActProcessReqVo actProcessReqVo);

/**啟動流程*/
ActWorkflowRespVo startWorkflow(ActWorkflowReqVo<LabelInfo> actWorkflowReqVo);

/**簽收任務*/
boolean claimTask(ActClaimTaskReqVo actClaimTaskReqVo);

/**送出任務*/
boolean completeTask(ActCompleteTaskReqVo<LabelInfo> actCompleteTaskReqVo);

/**查詢任務是否已簽收*/
boolean checkClaimTask(ActClaimTaskReqVo actClaimTaskReqVo);

/**釋放任務*/
boolean releaseTask(String taskId);

/**查詢待辦任務*/
ActProcessTaskRespVo queryTodoTasks(ActProcessTaskReqVo actProcessTaskReqVo);      
@SpringBootTest(classes = ActivitiApplication.class)
@RunWith(SpringRunner.class)
public class ActivitiProcessTest {

  @Autowired
  private IActivitiService activitiService;
  @Autowired
  private IWorkflowService workflowService;

  /**流程檔案路徑*/
  static String filePath = System.getProperty("user.dir") + "/src/main/resources/processes/leaveProcess.bpmn";

  /**流程部署*/
  @Test
  public void testDeployProcess() throws IOException {
    byte[] b = Files.readAllBytes(Paths.get(filePath));
    ActProcessReqVo actProcessReqVo = new ActProcessReqVo();
    actProcessReqVo.setProcessId("leaveProcess");
    actProcessReqVo.setProcessName("請假流程");
    actProcessReqVo.setProcessFileType("bpmn");
    actProcessReqVo.setProcessBase64Str(Base64Utils.encode(b));
    activitiService.deployProcess(actProcessReqVo);
  }

  /**啟動流程*/
  @Test
  public void testStartWorkflow() {
    ActWorkflowReqVo<LabelInfo> actWorkflowReqVo = new ActWorkflowReqVo<>();
    actWorkflowReqVo.setBusinessId("201912020001");
    actWorkflowReqVo.setProcessId("leaveProcess");

    List<LabelInfo> labelInfos = new ArrayList<>();
    LabelInfo labelInfo1 = new LabelInfo();
    labelInfo1.setLabName("userName");
    labelInfo1.setLabType("S");
    labelInfo1.setLabValue("will");
    labelInfos.add(labelInfo1);
    actWorkflowReqVo.setLabels(labelInfos);

    ActWorkflowRespVo actWorkflowRespVo = workflowService.startWorkflow(actWorkflowReqVo);
    MySlf4j.textInfo("啟動流程輸出:{0}", JsonUtils.toJson(actWorkflowRespVo));
  }

  /** 送出任務-請假申請*/
  @Test
  public void testCompleteTask1() {
    ActCompleteTaskReqVo actCompleteTaskReqVo = new ActCompleteTaskReqVo();
    actCompleteTaskReqVo.setComment("個人事務請假1天.....");
    actCompleteTaskReqVo.setProcessInstanceId("5001");
    actCompleteTaskReqVo.setUserId("will");
    actCompleteTaskReqVo.setProcessId("leaveProcess");
    boolean res = workflowService.completeTask(actCompleteTaskReqVo);
    MySlf4j.textInfo("簽收任務流程輸出:{0}", res);
  }

  /** 送出任務-部門主管審批*/
  @Test
  public void testCompleteTask2() {
    ActCompleteTaskReqVo<LabelInfo> actCompleteTaskReqVo = new ActCompleteTaskReqVo<>();
    actCompleteTaskReqVo.setComment("同意");
    actCompleteTaskReqVo.setProcessInstanceId("2501");
    actCompleteTaskReqVo.setUserId("deman");
    actCompleteTaskReqVo.setProcessId("leaveProcess");

    List<LabelInfo> labelInfos = new ArrayList<>();
    LabelInfo labelInfo1 = new LabelInfo();
    labelInfo1.setLabName("opinion");
    labelInfo1.setLabType("S");
    labelInfo1.setLabValue("TH");

    LabelInfo labelInfo2 = new LabelInfo();
    labelInfo2.setLabName("days");
    labelInfo2.setLabType("I");
    labelInfo2.setLabValue("1");

    labelInfos.add(labelInfo1);
    labelInfos.add(labelInfo2);
    actCompleteTaskReqVo.setLabels(labelInfos);

    boolean res = workflowService.completeTask(actCompleteTaskReqVo);
    MySlf4j.textInfo("簽收任務流程輸出:{0}", res);
  }

  /** 送出任務-HR審批*/
  @Test
  public void testCompleteTask3() {
    ActCompleteTaskReqVo actCompleteTaskReqVo = new ActCompleteTaskReqVo();
    actCompleteTaskReqVo.setComment("同意");
    actCompleteTaskReqVo.setProcessInstanceId("2501");
    actCompleteTaskReqVo.setUserId("petty");
    actCompleteTaskReqVo.setProcessId("leaveProcess");

    List<LabelInfo> labelInfos = new ArrayList<>();
    LabelInfo labelInfo1 = new LabelInfo();
    labelInfo1.setLabName("opinion");
    labelInfo1.setLabType("S");
    labelInfo1.setLabValue("TH");

    labelInfos.add(labelInfo1);
    actCompleteTaskReqVo.setLabels(labelInfos);

    boolean res = workflowService.completeTask(actCompleteTaskReqVo);
    MySlf4j.textInfo("簽收任務流程輸出:{0}", res);
  }

  /** 檢視任務是否簽收*/
  @Test
  public void testCheckClaimTask() {
    ActClaimTaskReqVo actClaimTaskReqVo = new ActClaimTaskReqVo();
    actClaimTaskReqVo.setUserId("will");
    actClaimTaskReqVo.setTaskId("2507");
    boolean res = workflowService.checkClaimTask(actClaimTaskReqVo);
    MySlf4j.textInfo("檢視任務是否簽收輸出:{0}", res);
  }

  /** 檢視待辦任務*/
  @Test
  public void testQueryTodoTasks() {
    ActProcessTaskReqVo actProcessTaskReqVo = new ActProcessTaskReqVo();
    actProcessTaskReqVo.setProcessId("leaveProcess");
    actProcessTaskReqVo.setUserId("will");
    actProcessTaskReqVo.setStartNum(0);
    actProcessTaskReqVo.setRecNum(10);
    ActProcessTaskRespVo actProcessTaskRespVo = workflowService.queryTodoTasks(actProcessTaskReqVo);
    MySlf4j.textInfo("查詢待辦任務輸出:{0}", JsonUtils.toJson(actProcessTaskRespVo));
  }