• flowable


    介绍

    • 定义

      为开发人员、系统管理员和业务用户提供紧凑且高效的工作流程和业务流程管理 (BPM) 平台。
      一个用 Java 编写的闪电般快速、经过尝试和测试的 BPMN 2 流程引擎。它是 Apache 2.0 许可的开源软件,拥有忠诚的社区。
      可以嵌入在 Java 应用程序中运行,也可以作为服务器、集群和云中的服务运行。它与 Spring 完美结合。凭借丰富的 Java 和 REST API,它是编排人类或系统活动的理想引擎

    • 其它
      文档:https: //www.flowable.org/
      jdk:支持java8-17+

    本文以flowable 7.0.0 版本介绍

    表介绍

    Flowable 的数据库名称均以ACT_开头。第二部分是表用例的双字符标识。此用例也将大致匹配服务 API。

    ACT_RE_ *:“RE”代表存储库。带有此前缀的表包含“静态”信息,例如流程定义和流程资源(图像、规则等)。

    ACT_RU_ *:“RU”代表运行时。这些是运行时表,包含流程实例、用户任务、变量、作业等的运行时数据。Flowable仅在流程实例执行期间存储运行时数据,并在流程实例结束时删除记录。这使得运行时表小而快。

    ACT_HI_ *:“HI”代表历史。这些表包含历史数据,例如过去的流程实例、变量、任务等。

    ACT_GE_ *:通用数据,用于各种用例

    在这里插入图片描述
    在这里插入图片描述

    实战

    • 依赖
      
            <dependency>
                <groupId>com.mysqlgroupId>
                <artifactId>mysql-connector-jartifactId>
                <scope>runtimescope>
            dependency>
          
            <dependency>
                <groupId>org.flowablegroupId>
                <artifactId>flowable-spring-boot-starterartifactId>
                <version>7.0.0version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • bpmn.xml
    
    <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 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="Expense" name="ExpenseProcess" isExecutable="true">
            <documentation>报销流程documentation>
            <startEvent id="start" name="开始">startEvent>
            <userTask id="fillTask" name="出差报销" flowable:assignee="${taskUser}">
                <extensionElements>
                    <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler">
                        modeler:initiator-can-complete>
                extensionElements>
            userTask>
            <exclusiveGateway id="judgeTask">exclusiveGateway>
            <userTask id="directorTak" name="经理审批">
                <extensionElements>
                    <flowable:taskListener event="create"
                                           class="com.gz.jelly.security.flowable.listener.ManagerTaskHandler">flowable:taskListener>
                extensionElements>
            userTask>
            <userTask id="bossTask" name="老板审批">
                <extensionElements>
                    <flowable:taskListener event="create"
                                           class="com.gz.jelly.security.flowable.listener.BossTaskHandler">flowable:taskListener>
                extensionElements>
            userTask>
            <endEvent id="end" name="结束">endEvent>
            <sequenceFlow id="directorNotPassFlow" name="驳回" sourceRef="directorTak" targetRef="fillTask">
                <conditionExpression xsi:type="tFormalExpression">conditionExpression>
            sequenceFlow>
            <sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="fillTask">
                <conditionExpression xsi:type="tFormalExpression">conditionExpression>
            sequenceFlow>
            <sequenceFlow id="flow1" sourceRef="start" targetRef="fillTask">sequenceFlow>
            <sequenceFlow id="flow2" sourceRef="fillTask" targetRef="judgeTask">sequenceFlow>
            <sequenceFlow id="judgeMore" name="大于500元" sourceRef="judgeTask" targetRef="bossTask">
                <conditionExpression xsi:type="tFormalExpression"> 500}]]>conditionExpression>
            sequenceFlow>
            <sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
                <conditionExpression xsi:type="tFormalExpression">conditionExpression>
            sequenceFlow>
            <sequenceFlow id="directorPassFlow" name="通过" sourceRef="directorTak" targetRef="end">
                <conditionExpression xsi:type="tFormalExpression">conditionExpression>
            sequenceFlow>
            <sequenceFlow id="judgeLess" name="小于500元" sourceRef="judgeTask" targetRef="directorTak">
                <conditionExpression xsi:type="tFormalExpression">conditionExpression>
            sequenceFlow>
        process>
        <bpmndi:BPMNDiagram id="BPMNDiagram_Expense">
            <bpmndi:BPMNPlane bpmnElement="Expense" id="BPMNPlane_Expense">
                <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
                    <omgdc:Bounds height="30.0" width="30.0" x="285.0" y="135.0">omgdc:Bounds>
                bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="fillTask" id="BPMNShape_fillTask">
                    <omgdc:Bounds height="80.0" width="100.0" x="405.0" y="110.0">omgdc:Bounds>
                bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
                    <omgdc:Bounds height="40.0" width="40.0" x="585.0" y="130.0">omgdc:Bounds>
                bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="directorTak" id="BPMNShape_directorTak">
                    <omgdc:Bounds height="80.0" width="100.0" x="735.0" y="110.0">omgdc:Bounds>
                bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="bossTask" id="BPMNShape_bossTask">
                    <omgdc:Bounds height="80.0" width="100.0" x="555.0" y="255.0">omgdc:Bounds>
                bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
                    <omgdc:Bounds height="28.0" width="28.0" x="771.0" y="281.0">omgdc:Bounds>
                bpmndi:BPMNShape>
                <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
                    <omgdi:waypoint x="315.0" y="150.0">omgdi:waypoint>
                    <omgdi:waypoint x="405.0" y="150.0">omgdi:waypoint>
                bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
                    <omgdi:waypoint x="505.0" y="150.16611295681062">omgdi:waypoint>
                    <omgdi:waypoint x="585.4333333333333" y="150.43333333333334">omgdi:waypoint>
                bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
                    <omgdi:waypoint x="624.5530726256983" y="150.44692737430168">omgdi:waypoint>
                    <omgdi:waypoint x="735.0" y="150.1392757660167">omgdi:waypoint>
                bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="directorNotPassFlow" id="BPMNEdge_directorNotPassFlow">
                    <omgdi:waypoint x="785.0" y="110.0">omgdi:waypoint>
                    <omgdi:waypoint x="785.0" y="37.0">omgdi:waypoint>
                    <omgdi:waypoint x="455.0" y="37.0">omgdi:waypoint>
                    <omgdi:waypoint x="455.0" y="110.0">omgdi:waypoint>
                bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="bossPassFlow" id="BPMNEdge_bossPassFlow">
                    <omgdi:waypoint x="655.0" y="295.0">omgdi:waypoint>
                    <omgdi:waypoint x="771.0" y="295.0">omgdi:waypoint>
                bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
                    <omgdi:waypoint x="605.4340277777778" y="169.56597222222223">omgdi:waypoint>
                    <omgdi:waypoint x="605.1384083044983" y="255.0">omgdi:waypoint>
                bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="directorPassFlow" id="BPMNEdge_directorPassFlow">
                    <omgdi:waypoint x="785.0" y="190.0">omgdi:waypoint>
                    <omgdi:waypoint x="785.0" y="281.0">omgdi:waypoint>
                bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="bossNotPassFlow" id="BPMNEdge_bossNotPassFlow">
                    <omgdi:waypoint x="555.0" y="295.0">omgdi:waypoint>
                    <omgdi:waypoint x="455.0" y="295.0">omgdi:waypoint>
                    <omgdi:waypoint x="455.0" y="190.0">omgdi:waypoint>
                bpmndi:BPMNEdge>
            bpmndi:BPMNPlane>
        bpmndi:BPMNDiagram>
    definitions>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • listener
    public class BossTaskHandler implements TaskListener {
        @Override
        public void notify(DelegateTask delegateTask) {
            delegateTask.setAssignee("老板");
        }
    }
    public class ManagerTaskHandler implements TaskListener {
        @Override
        public void notify(DelegateTask delegateTask) {
            delegateTask.setAssignee("经理");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • controller
    package com.gz.jelly.security.flowable.controller;
    
    import jakarta.servlet.http.HttpServletResponse;
    import org.flowable.bpmn.model.BpmnModel;
    import org.flowable.engine.*;
    import org.flowable.engine.runtime.Execution;
    import org.flowable.engine.runtime.ProcessInstance;
    import org.flowable.image.ProcessDiagramGenerator;
    import org.flowable.task.api.Task;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    @Controller
    @RequestMapping(value = "expense")
    public class ExpenseController {
        @Autowired
        private RuntimeService runtimeService;
        @Autowired
        private TaskService taskService;
        @Autowired
        private RepositoryService repositoryService;
        @Autowired
        private ProcessEngine processEngine;
    
    /***************此处为业务代码******************/
    
        /**
         * 添加报销
         *
         * @param userId    用户Id
         * @param money     报销金额
         * @param descption 描述
         */
        @RequestMapping(value = "add")
        @ResponseBody
        public String addExpense(String userId, Integer money, String descption) {
            //启动流程
            HashMap<String, Object> map = new HashMap<>();
            map.put("taskUser", userId);
            map.put("money", money);
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Expense", map);
            return "提交成功.流程Id为:" + processInstance.getId();
        }
    
        /**
         * 获取审批管理列表
         */
        @RequestMapping(value = "/list")
        @ResponseBody
        public Object list(String userId) {
            List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
            for (Task task : tasks) {
                System.out.println(task.toString());
            }
            return tasks.toArray().toString();
        }
        /**
         * 批准
         *
         * @param taskId 任务ID
         */
        @RequestMapping(value = "apply")
        @ResponseBody
        public String apply(String taskId) {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task == null) {
                throw new RuntimeException("流程不存在");
            }
            //通过审核
            HashMap<String, Object> map = new HashMap<>();
            map.put("outcome", "通过");
            taskService.complete(taskId, map);
            return "processed ok!";
        }
        /**
         * 拒绝
         */
        @ResponseBody
        @RequestMapping(value = "reject")
        public String reject(String taskId) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("outcome", "驳回");
            taskService.complete(taskId, map);
            return "reject";
        }
        /**
         * 生成流程图
         *
         * @param processId 任务ID
         */
        @RequestMapping(value = "processDiagram")
        public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
    
            //流程走完的不显示图
            if (pi == null) {
                return;
            }
            Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
            //使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象
            String InstanceId = task.getProcessInstanceId();
            List<Execution> executions = runtimeService
                    .createExecutionQuery()
                    .processInstanceId(InstanceId)
                    .list();
    
            //得到正在执行的Activity的Id
            List<String> activityIds = new ArrayList<>();
            List<String> flows = new ArrayList<>();
            for (Execution exe : executions) {
                List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
                activityIds.addAll(ids);
            }
    
            //获取流程图
            BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
            ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
            ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
            InputStream in = diagramGenerator
                    .generateDiagram(bpmnModel, "png", activityIds, flows,
                            engconf.getActivityFontName(), engconf.getLabelFontName(),
                            engconf.getAnnotationFontName(), engconf.getClassLoader(),
                            1.0, true);
            OutputStream out = null;
            byte[] buf = new byte[1024];
            int legth = 0;
            try {
                out = httpServletResponse.getOutputStream();
                while ((legth = in.read(buf)) != -1) {
                    out.write(buf, 0, legth);
                }
            } finally {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            }
        }
    
    
    
    
    
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
  • 相关阅读:
    php实战案例记录(16)php://input输入流
    基于SSH开发物流仓储调度系统 课程设计 大作业 毕业设计
    【Linux】——select详解
    Vue插件
    js基础知识整理之 —— 全局作用域
    Redis数据结构之——sds
    7/20 时事
    如何避免由 Web 字体引起的布局偏移
    【Python百日进阶-数据分析】Day117 - Plotly 是免费的吗?
    XML学习总结
  • 原文地址:https://blog.csdn.net/GZ946/article/details/134256257