zoukankan      html  css  js  c++  java
  • Flowable流程引擎入门

    Flowable是一个流行的轻量级的采用Java开发的业务流程引擎。通过Flowable流程引擎,我们可以部署BPMN2.0的流程定义(一般为XML文件),通过流程定义创建流程实例,查询和访问流程相关的实例与数据,等等。

    Flowable可以灵活地添加到我们的服务、应用、架构中,可以通过引入Flowable jar包,或者直接使用Flowable的Rest API来进行业务流程引擎的操作。

    Flowable是基于Activity5.0的一个分支开发的,因此内部的很多概念都相似。

    使用

    通过创建一个简单的命令行案例了解如何创建Flowable的流程引擎,我们采用假期请假流程。

    • 员工(employee)发出请假的请求
    • 管理者(manager)同意或拒绝请假请求
    • 我们会模拟把请求注册到外部的系统,发送邮件来通知流程的结果

    1 创建项目,添加maven依赖

    <dependencies>
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-engine</artifactId>
                <version>6.4.2</version>
            </dependency>
        <!-- 可以采用MySQL存储,也可以采用H2,看自己的需要 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.17</version>
            </dependency>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <version>1.3.176</version>
            </dependency>
    </dependencies>
    

    2 创建流程的配置文件,holiday-request.bpmn20.xml

    流程对应的BPMN图像为:

     
    getting.started.bpmn.process
    <?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: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"
                 xmlns:flowable="http://flowable.org/bpmn"
                 typeLanguage="http://www.w3.org/2001/XMLSchema"
                 expressionLanguage="http://www.w3.org/1999/XPath"
                 targetNamespace="http://www.flowable.org/processdef">
    
        <!--
            每一步都需要有一个id属性,标记当前流程的步骤,name是可选的
            当流程开始执行的时候,执行过程会从startEvent开始,跟着sequenceFlow往下走
    
            startEvent -> approveTask -> approved -> externalSystemCall -> holidayApprovedTask -> assign:employee -> approveEnd
                                      -> reject -> sendRejectionMail -> rejectEnd
          -->
    
        <process id="holidayRequest" name="Holiday Request" isExecutable="true">
    
            <startEvent id="startEvent"/>
            <sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
    
            <userTask id="approveTask" name="Approve or reject request" flowable:candidateGroups="managers"/>
            <sequenceFlow sourceRef="approveTask" targetRef="decision"/>
    
            <exclusiveGateway id="decision"/>
            <sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
                <conditionExpression xsi:type="tFormalExpression">
                    <![CDATA[
                     ${approved}
                  ]]>
                </conditionExpression>
            </sequenceFlow>
            <sequenceFlow  sourceRef="decision" targetRef="sendRejectionMail">
                <conditionExpression xsi:type="tFormalExpression">
                    <![CDATA[
                     ${!approved}
                   ]]>
                </conditionExpression>
            </sequenceFlow>
    
            <serviceTask id="externalSystemCall" name="Enter holidays in external system"
                         flowable:class="me.aihe.jmxdemo.flowable.CallExternalSystemDelegate"/>
            <sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>
    
            <userTask id="holidayApprovedTask" name="Holiday approved" flowable:assignee="${employee}"/>
            <sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
    
            <serviceTask id="sendRejectionMail" name="Send out rejection email"
                         flowable:class="org.flowable.SendRejectionMail"/>
            <sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
    
            <endEvent id="approveEnd"/>
    
            <endEvent id="rejectEnd"/>
    
        </process>
    
    </definitions>
    

    3 编写代码

    
    import org.flowable.engine.*;
    import org.flowable.engine.history.HistoricActivityInstance;
    import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
    import org.flowable.engine.repository.Deployment;
    import org.flowable.engine.repository.ProcessDefinition;
    import org.flowable.engine.runtime.ProcessInstance;
    import org.flowable.task.api.Task;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Scanner;
    
    /**
     * @author he.ai aihehe123@gmail.com
     * 使用场景:
     * 功能描述:
     */
    public class HolidayRequest {
        public static void main(String[] args) {
            // 首先实例化ProcessEngine,线程安全对象,一般全局只有一个即可,从ProcessEngineConfiguration创建的话,可以调整一些
            // 配置,通常我们会从XML中创建,至少要配置一个JDBC连接
            // 如果是在Spring的配置中,使用SpringProcessEngineConfiguration
    
            ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
    //                .setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1")
    //                .setJdbcDriver("org.h2.Driver")
    //                .setJdbcUsername("sa")
                    .setJdbcPassword("")
                    .setJdbcUrl("jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8")
                    .setJdbcUsername("aihe")
                    .setJdbcPassword("123456")
                    .setJdbcDriver("com.mysql.jdbc.Driver")
    
                    // 如果数据表不存在的时候,自动创建数据表
                    .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    
            // 执行完成后,就可以开始创建我们的流程了
            ProcessEngine processEngine = cfg.buildProcessEngine();
    
            // 使用BPMN 2.0定义process。存储为XML,同时也是可以可视化的。NPMN 2.0标准可以让技术人员与业务人员都
            // 参与讨论业务流程中来
    
            // 部署流程
            RepositoryService repositoryService = processEngine.getRepositoryService();
            Deployment deployment = repositoryService.createDeployment()
                    .addClasspathResource("holiday-request.bpmn20.xml")
                    .deploy();
    
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(deployment.getId())
                    .singleResult();
            System.out.println("Found process definition : " + processDefinition.getName());
    
            // 启动process实例,需要一些初始化的变量,这里我们简单的从Scanner中获取,一般在线上会通过接口传递过来
            Scanner scanner= new Scanner(System.in);
    
            System.out.println("Who are you?");
            String employee = scanner.nextLine();
    
            System.out.println("How many holidays do you want to request?");
            Integer nrOfHolidays = Integer.valueOf(scanner.nextLine());
    
            System.out.println("Why do you need them?");
            String description = scanner.nextLine();
    
            RuntimeService runtimeService = processEngine.getRuntimeService();
    
            Map<String, Object> variables = new HashMap<String, Object>();
            variables.put("employee", employee);
            variables.put("nrOfHolidays", nrOfHolidays);
            variables.put("description", description);
    
            // 当创建实例的时候,execution就被创建了,然后放在启动的事件中,这个事件可以从数据库中获取,
            // 用户后续等待这个状态即可
            ProcessInstance processInstance =
                    runtimeService.startProcessInstanceByKey("holidayRequest", variables);
    
            // 在Flowable中数据库的事务对数据一致性起着关键性的作用。
            // 查询和完成任务
    
            TaskService taskService = processEngine.getTaskService();
            List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
            System.out.println("You have " + tasks.size() + " tasks:");
            for (int i=0; i<tasks.size(); i++) {
                System.out.println((i+1) + ") " + tasks.get(i).getName());
            }
    
    
            System.out.println("Which task would you like to complete?");
            int taskIndex = Integer.valueOf(scanner.nextLine());
            Task task = tasks.get(taskIndex - 1);
            Map<String, Object> processVariables = taskService.getVariables(task.getId());
            System.out.println(processVariables.get("employee") + " wants " +
                    processVariables.get("nrOfHolidays") + " of holidays. Do you approve this?");
    
            boolean approved = scanner.nextLine().toLowerCase().equals("y");
            variables = new HashMap<String, Object>();
            variables.put("approved", approved);
            taskService.complete(task.getId(), variables);
    
    
            HistoryService historyService = processEngine.getHistoryService();
            List<HistoricActivityInstance> activities =
                    historyService.createHistoricActivityInstanceQuery()
                            .processInstanceId(processInstance.getId())
                            .finished()
                            .orderByHistoricActivityInstanceEndTime().asc()
                            .list();
    
            for (HistoricActivityInstance activity : activities) {
                System.out.println(activity.getActivityId() + " took "
                        + activity.getDurationInMillis() + " milliseconds");
            }
        }
    }
    
    import org.flowable.engine.delegate.DelegateExecution;
    import org.flowable.engine.delegate.JavaDelegate;
    
    public class CallExternalSystemDelegate implements JavaDelegate {
    
        public void execute(DelegateExecution execution) {
            System.out.println("Calling the external system for employee "
                    + execution.getVariable("employee"));
        }
    
    }
    

    4 创建数据库

    create database flowable;
    

    5 运行应用

     
    image.png

    Flowable API

    刚才的代码中,我们涉及到了一些Flowable的API,在开发的时候经常需要与这些API打交道。

    入口点为:ProcessEngine,我们有多种方式来创建它。

    通过ProcessEngine,我们可以获取工作流的不同服务类型,ProcessEngine和服务都是线程安全的,因此我们可以用作单例对象来使用这些服务。

     
    image.png
    // 第一次会初始化和创建一个ProcessEngine,后续调用都会从缓存中直接返回,全局创建一次
    // ProcessEngines.init()与ProcessEngines.destroy(). 初始化和消耗与ProcessEngines
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
    RuntimeService runtimeService = processEngine.getRuntimeService();
    RepositoryService repositoryService = processEngine.getRepositoryService();
    TaskService taskService = processEngine.getTaskService();
    ManagementService managementService = processEngine.getManagementService();
    IdentityService identityService = processEngine.getIdentityService();
    HistoryService historyService = processEngine.getHistoryService();
    FormService formService = processEngine.getFormService();
    DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
    
    • RepositoryService: 操作和管理流程的定义和部署,deployment(部署)是ProcessEngine的基本单元
    • RuntimeService:每一个流程都可以创建许多的运行实例,RuntimeService启动流程的实例,检索和存储实例的变量信息
    • IdentityService:管理组和用户的身份认证信息
    • FormService:可选的服务
    • HistoryService:检索ProcessEngine的历史数据
    • ManagementService:检索数据库的元数据和表的信息,在编程的时候一般用不到
    • DynamicBpmnService:动态的改变流程的定义,并且不需要重新部署,在生产环境很少使用

    最后

    本次主要运行了一个Flowable的简单应用,介绍了Flowable是什么,在Activiti之上fork的流程引擎。



    作者:Real_man
    链接:https://www.jianshu.com/p/4253f6eac920
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    网页工具KOBAS进行KEGG富集分析
    Novel LncRNA的实时定量PCR引物设计教程
    Annotated LncRNA的实时定量PCR引物设计教程
    GO分析-GOseq的使用教程
    转录因子预测-oPOSSUM 3.0的使用教程
    miRNA结合位点预测软件RNAhybrid的使用教程
    关于win10用户名设置为中文导致Rstudio画图报错的解决方法
    edgeR之配对检验分析差异基因的使用教程
    51nod 1051最大子矩阵和
    51nod最大字段和(1049 1254)
  • 原文地址:https://www.cnblogs.com/javalinux/p/15210343.html
Copyright © 2011-2022 走看看