flowable入门教程

1.1. 先决条件 Prerequisites

这个教程假设你已经运行了Flowable演示配置,并使用独立的H2服务器。编辑db.properties并设置jdbc.url=jdbc:h2:tcp://localhost/flowable,然后按照H2文档的介绍运行独立服务器。

1.2. 目标 Goal

这个教程的目标是学习Flowable以及BPMN 2.0的一些基础概念。最后成果是一个简单的Java SE程序,部署了一个流程定义,并通过Flowable引擎API与流程进行交互。当然,在这个教程里学到的东西,也可以基于你的业务流程,用于构建你自己的web应用程序。

1.3. 用例 Use case

用例很直接:有一个公司,叫做BPMCorp。在BPMCorp中,每月需要为投资人撰写一份金融报告,由会计部门负责。在报告完成后,需要上层经理中的一位进行审核,然后才能发给所有投资人。

1.4. 流程图 Process diagram

上面描述的业务流程,可以使用Flowable Designer可视地画出。但是在这个教程里,我们自己写XML,这样可以学习更多。这个流程的图形化BPMN 2.0注记像是这样

flowable入门教程_第1张图片

我们看到的是一个空启动事件 none Start Event(左边的圆圈),接下来是两个用户任务 User Tasks:'Write monthly financial report(撰写月度金融报告)''Verify monthly financial report(审核月度金融报告)'。最后是空结束事件 none end event(右边的粗线条圆圈)。

1.5. XML表现 XML representation

这个业务流程的XML版本(FinancialReportProcess.bpmn20.xml)像下面显示的一样。很容易认出流程的主要元素(点击链接可以跳转到BPMN 2.0结构的详细章节):

  • (空)开始事件 (none) start event是流程的入口点(entry point)

  • 用户任务 User Tasks的声明表示了流程中的人工任务。请注意第一个任务分配给accountancy组,而第二个任务分配给management组。查看用户任务分配章节 the section on user task assignment了解关于用户与组如何分配用户任务的更多信息。

  • 流程在到达空结束事件 none end event时结束。

  • 各元素间通过顺序流 sequence flows链接。顺序流用source 与target定义顺序流的流向(direction)

 
       



	

	  

	  

	  
	    
	      Write monthly financial report for publication to shareholders.
	    
	    
	      
	        accountancy
	      
	    
	  

	  

	  
	    
	      Verify monthly financial report composed by the accountancy department.
	      This financial report is going to be sent to all the company shareholders.
	    
	    
	      
	        management
	      
	    
	  

	   
     

1.6. 启动流程实例 Starting a process instance

现在我们已经创建了业务流程的流程定义。使用这样的流程定义,可以创建流程实例。在这个例子中,一个流程实例将对应一个特定月份的一次财经报告创建与审核工作。所有月份的流程实例共享相同的流程定义。

要用给定的流程定义创建流程实例,需要首先部署(deploy)流程定义。部署流程定义意味着两件事:

  • 流程定义将会存储在Flowable引擎配置的持久化数据库中。因此通过部署业务流程,保证了引擎在重启后也能找到流程定义。

  • BPMN 2.0流程XML会解析为内存中的对象模型。这个模型可以通过Flowable API操纵。

更多关于部署的信息可以在部署专门章节中找到。

与该章节的描述一样,部署有很多种方式。一种是通过下面展示的API。请注意所有与Flowable引擎的交互都要通过它的服务(services)

Deployment deployment = repositoryService.createDeployment() .addClasspathResource("FinancialReportProcess.bpmn20.xml") .deploy();

现在可以使用在流程定义中定义的id(参见XML中的process元素)启动新流程实例。请注意这个id在Flowable术语中被称作key

ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("financialReport");

这会创建流程实例,并首先通过开始事件。在开始事件后,会沿着所有出口顺序流(在这个例子中只有一个)继续,并到达第一个任务(撰写月度金融报告 write monthly financial report)。这时,Flowable引擎会在持久化数据库中存储一个任务。同时,会解析这个任务附加的分配用户或组,也保存在数据库中。请注意,Flowable引擎会持续执行流程步骤,直到到达等待状态 wait state,例如用户任务。在这种等待状态时,流程实例的当前状态会存储在数据库中,并保持这个状态,直到用户决定完成任务。这时,引擎会继续执行,直到遇到新的等待状态,或者流程结束。如果在这期间引擎重启或崩溃,流程的状态也仍在数据库中安全的保存。

在任务创建后,startProcessInstanceByKey方法会返回,因为用户任务活动是一个等待状态。在这个例子里,这个任务分配给一个组。这意味着这个组的每一个成员都是处理这个任务的候选人 candidate

现在可以将这些整合起来,创建一个简单的Java程序。创建一个新的Eclipse项目,在它的classpath中添加Flowable jar与依赖(可以在Flowable发行版的libs目录下找到)。在能够调用Flowable服务前,需要首先构建ProcessEngine (流程引擎),用于访问服务。这里我们使用'独立(standalone)'配置,这个配置会构建ProcessEngine,并使用与演示配置中相同的数据库。

可以从这里下载流程定义XML。这个文件包含了上面展示的XML,同时包含了必要的BPMN图形交互信息 diagram interchange information,用于在Flowable的工具中可视化展示流程。

public static void main(String[] args) {  //创建Flowable流程引擎 Create Flowable process engine  ProcessEngine processEngine = ProcessEngineConfiguration .createStandaloneProcessEngineConfiguration()  .buildProcessEngine();  //获取Flowable服务 Get Flowable services  RepositoryService repositoryService = processEngine.getRepositoryService();  RuntimeService runtimeService = processEngine.getRuntimeService();  //部署流程定义 Deploy the process definition  repositoryService.createDeployment()   .addClasspathResource("FinancialReportProcess.bpmn20.xml") .deploy();   //启动流程实例 Start a process instance  runtimeService.startProcessInstanceByKey("financialReport"); }

1.7. 任务列表 Task lists

现在可以通过添加下列逻辑,获取这个任务:

List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list();

请注意传递给这个操作的用户需要是accountancy组的成员,因为在流程定义中是这么声明的:

      accountancy  

也可以使用任务查询API,用组名查得相同结果。可以在代码中添加下列逻辑:

  TaskService taskService = processEngine.getTaskService(); List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();

因为我们将ProcessEngine配置为使用与演示配置中相同的数据库,因此现在就可以登入Flowable IDM。作为admin/test登入,并创建2个新用户kermitfozzie,并将Access the workflow application(访问工作流应用)权限授予他们。然后创建两个组,命名为accountancymanagement,并将fozzie添加至accountancy组,将kermit添加至management组。现在以fozzie登入Flowable task应用,就可以选择Task 应用,再选择其Processes页面,选择'Monthly financial report (月度金融报告)',这样就可以启动我们的业务流程。

1.8. 申领任务 Claiming the task

会计师(accountancy组的成员)现在需要申领任务。申领任务后,这个用户会成为任务的执行人 (assignee),这个任务也会从accountancy组的其他成员的任务列表中消失。申领任务通过编程方式如下实现:

  taskService.claim(task.getId(), "fozzie");

这个任务现在在申领任务者的个人任务列表中

List<Task> tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();

在Flowable Task应用中,点击claim按钮会执行相同操作。这个任务会转移到登录用户的个人任务列表中。也可以看到任务执行人变更为当前登录用户。

1.9. 完成任务 Completing the task

会计师(accountancy组的成员)现在需要开始撰写金融报告了。一旦报告完成,他就可以完成任务。这意味着这个任务的所有工作都已经完成。

taskService.complete(task.getId());

对于Flowable引擎来说,这是个外部信号,指示流程实例可以继续执行。任务本身会从运行时数据中移除,并沿着这个任务唯一的出口转移线(outgoing transition),将执行移至第二个任务('verification of the report 审核月度报告')。与上面介绍的第一个任务使用的相同的机制,会用于为第二个任务分配执行人。有一点小区别,这个任务会分配给management组。

在演示设置中,完成任务可以通过点击任务列表中的complete按钮。因为Fozzie不是经理,我们需要登出Flowable Task应用,并用kermit(他是经理)登录。第二个任务现在可以在未分配任务列表中看到。

1.10. 结束流程 Ending the process

与之前完全相同的方式,可以获取并申领审核任务。完成这个第二个任务,会将流程执行移至结束事件,并结束流程实例。这个流程实例与所有相关的运行时执行数据都会从数据库中移除。

也可以通过编程方式,使用historyService验证流程已经结束

HistoryService historyService = processEngine.getHistoryService(); HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult(); System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());

1.11. 代码总结 Code overview

将之前章节的所有代码片段整合起来,会得到类似这样的代码。这段代码考虑到了你可能已经使用Flowable UI应用启动了一些流程实例。代码中总是获取任务列表而不是一个任务,因此总能正确执行:

public class TenMinuteTutorial {

  public static void main(String[] args) {

    // 创建Flowable流程引擎 Create Flowable process engine
    ProcessEngine processEngine = ProcessEngineConfiguration
      .createStandaloneProcessEngineConfiguration()
      .buildProcessEngine();

    // 获取Flowable服务 Get Flowable services
    RepositoryService repositoryService = processEngine.getRepositoryService();
    RuntimeService runtimeService = processEngine.getRuntimeService();

    // 部署流程定义 Deploy the process definition
    repositoryService.createDeployment()
      .addClasspathResource("FinancialReportProcess.bpmn20.xml")
      .deploy();

    // 启动流程实例 Start a process instance
    String procId = runtimeService.startProcessInstanceByKey("financialReport").getId();

    // 获取第一个任务 Get the first task
    TaskService taskService = processEngine.getTaskService();
    List tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
    for (Task task : tasks) {
      System.out.println("Following task is available for accountancy group: " + task.getName());

      // 申领 claim it
      taskService.claim(task.getId(), "fozzie");
    }

    // 验证Fozzie获取了任务 Verify Fozzie can now retrieve the task
    tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
    for (Task task : tasks) {
      System.out.println("Task for fozzie: " + task.getName());

      // 完成任务 Complete the task
      taskService.complete(task.getId());
    }

    System.out.println("Number of tasks for fozzie: "
            + taskService.createTaskQuery().taskAssignee("fozzie").count());

    // 获取并申领第二个任务 Retrieve and claim the second task
    tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
    for (Task task : tasks) {
      System.out.println("Following task is available for management group: " + task.getName());
      taskService.claim(task.getId(), "kermit");
    }

    // 完成第二个任务并结束流程 Completing the second task ends the process
    for (Task task : tasks) {
      taskService.complete(task.getId());
    }

    // 验证流程已经结束 verify that the process is actually finished
    HistoryService historyService = processEngine.getHistoryService();
    HistoricProcessInstance historicProcessInstance =
      historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
    System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
  }

}

1.12. 继续提高 Future enhancements

可以看出这个业务流程太简单了,不能实际使用。然而,随着继续浏览Flowable中可用的BPMN 2.0结构,可以增强业务流程通过:

  • 定义网关(gateway)使经理可以选择,驳回金融报告,并重新为会计师创建任务;或者接受报告。

  • 定义并使用变量(variables)存储或引用报告,并可以在表单中显示它。

  • 在流程结束处定义服务任务(service task),将报告发送给每一个投资人。

  • 等等。



你可能感兴趣的:(flowable入门教程)