精华内容
下载资源
问答
  • Flowable工作流

    2020-05-15 17:11:53
    Flowable工作流 Flowable工作流Flowable工作流一.认识flowable1.flowable发展史BPMNBPMN2.0概述:**BPMN2.0所包含的元素:**flowable实例三.flowable数据库表的介绍1.对表分类2.流程启动到结束数据库变化四.flowable...

    Flowable工作流

    一.认识flowable

    Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎让你可以部署BPMN 2.0流程定义(用于定义流程的行业XML标准)、创建这些流程定义的流程实例、进行查询、访问运行中或历史的流程实例与相关数据,等等。

    1.flowable发展史

    三个框架诞生的先后顺序是 JBPM>Activiti>Flowable
    2010年,JBPM4发布之后, Joram Barrez(JBPM的创始人)与合作伙伴在JBPM的未来架构上产生了重大的分歧,于是乎Tom Baeyens离开了JBoss公司并加入到Alfresco公司,真是一言不合就“分手”。
    2010年6月18日,Alfresco公司发布了第一个Activiti版本(5.0.alpha1)。Activiti直接将第一个版本号定义为5.0可谓意味深远,表明Activiti框架才是JBPM4的延续。从上面的图可以看出来,activiti从12年底的时候,才开始大量的重构和开发。
    2010年10月6日,JBoss完全抛弃了JBPM4的架构设计,使用了规则引擎(Drools Flow)进行项目的彻底重构,并推出了JBPM5。
    2016年10月13日,Tijs Rademarkers (原Activiti Project Lead)发布了Flowable 5.22.0版本的上线公告,该版本基于上Activiti5.22版本拉取的新分支,并没有从本质上增加更多的新特性。
    2016年11月1日,Flowable团队开放了Flowable Eclipse Designer(该插件用于在Eclipse开发工具中绘制流程文档)。
    2016年12月15日,Flowable团队发布了Flowable 6.0.0.RC1版本的上线公告。
    2017年3月27日,Flowable团队发布了Flowable 5.23.0版本的上线公告。
    2017年4月28日,Flowable团队发布了Flowable 6.0.1版本的上线公告。
    2017年5月29日,大名鼎鼎的Joram Barrez(原JBPM的创始人)加入了Flowable团队,专心于Flowable的研发。
    2017年7月21日,Flowable团队发布了Flowable 6.1.1版本的上线公告。
    2017年10月13日,Flowable团队发布了flowable-6.2.0-release版本的上线公告。
    2017年12月11日,Flowable团队发布了flowable-6.2.1-release版本的上线公告。
    2018年04月04日,Flowable团队发布了flowable-6.3.0-release版本的上线公告。
    2018年05月22日,Flowable团队发布了flowable-6.3.1-release版本的上线公告。
    2018年10月02日,Flowable团队发布了flowable-6.4.0-release版本的上线公告。

    官网:https://www.flowable.org/

    中文文档:https://tkjohn.github.io/flowable-userguide/#_configuration

    2.BPMN

    在这里插入图片描述
    BPMN 标准发展版本历史如下。BPMN2.0在1.x基础上新增了元模型、存储、交互、执行。
    在这里插入图片描述

    BPMN2.0概述:

    1、是一套业务流程模型与符号建模标准;

    2、精准的执行语义来描述元素的操作,可以将元素的操作描述的很清楚,没有二义性;

    3、以XML为载体,以符号可视化业务,每个xml模块都可以对应符号,流程图与xml有一个相互转换的过程。

    BPMN2.0所包含的元素:

    1、流对象(FlowObjects):包括其中的活动、事件与网关。

        活动(Activities)  [User Task 、Service Task ......]
    
        事件(Events)  [Start Event、End Event......]
    
        网关(Gateways)  [Exclusive Gateway ......]
    

    2、连接对象(ConnectingObject):流对象通过连接对象连接起来表示数据的流转;

    3、数据(Data):包括一些数据对象、数据输入\输出对象等。

        数据对象(Data Objects)
    
        数据输入(Data Inputs )
    
        数据输出(Data OutPuts)
    
        数据存储(Data Stores)
    

    4、泳道(Swimlanes):对业务做范围维度的区分,一般通过不同的职能进行区分。

    ​ 池(Pools ): 池描述流程中的一个参与者。可以看做是将一系列活动区别于其他池的一个图形容器

    ​ 道(Lanes ):道就是在池里面再细分,可以是垂直的也可以是水平的。道也是用于组织和分类活动。

    5、描述对象(Artifacts):不影响流程运行,为流程图可读性进行补充性描述。

    一个简单的流程图
    在这里插入图片描述

    二.flowable实例

    项目结构如下:
    在这里插入图片描述
    1.导入依赖

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
            <relativePath />
        </parent>
    	<dependencies>
    		<!--flowable-->
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-spring-boot-starter</artifactId>
                <version>6.4.0</version>
            </dependency>
            <!--数据库-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.45</version>
            </dependency>
            <!--rest支持-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    

    2.编写启动类

    @SpringBootApplication
    public class RepairApp {
        /**
         *日志信息
         */
        private static final Logger log = LoggerFactory.getLogger(RepairApp.class);
    
        public static void main(String[] args) {
            log.info("项目开始启动");
            SpringApplication.run(RepairApp.class,args);
            log.info("项目启动完成");
        }
    }
    

    3.配置文件

    #数据源配置
    spring:
      datasource:
        url: jdbc:mysql://106.13.61.208/repair?characterEncoding=UTF-8
        username: root
        password: 123456
    
    #flowable配置
    #自动部署验证设置:true-开启(默认)、false-关闭
    flowable:
      check-process-definitions: false
    

    4.导入BPMN文件

    <?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="mydemo" name="demo" isExecutable="true">
        <documentation>111</documentation>
        <startEvent id="startEvent1"></startEvent>
        <userTask id="sid-7C91C99C-1D01-4AC6-88FB-03CAA1603477" name="出差报销" flowable:assignee="${user}">
          <extensionElements>
            <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
          </extensionElements>
        </userTask>
        <exclusiveGateway id="sid-49E6AEBB-D5B9-4B9E-A99E-2E2454642891"></exclusiveGateway>
        <sequenceFlow id="sid-5B89E7D6-7B3A-439A-9F15-D3B985515C7E" sourceRef="sid-7C91C99C-1D01-4AC6-88FB-03CAA1603477" targetRef="sid-49E6AEBB-D5B9-4B9E-A99E-2E2454642891"></sequenceFlow>
        <userTask id="sid-457C6876-FE69-47E8-B9B1-5F1AEC979758" name="经理审批" flowable:assignee="manage">
          <extensionElements>
            <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
          </extensionElements>
        </userTask>
        <userTask id="sid-05C7AEC3-C967-4056-9AAA-B21C57E214F4" name="老板审批" flowable:assignee="boss">
          <extensionElements>
            <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
          </extensionElements>
        </userTask>
        <endEvent id="sid-27C7BF58-F8CF-4B3A-868C-F2158DF03AD8"></endEvent>
        <sequenceFlow id="sid-1A2DAF03-7BA0-4531-A02D-09F6AF31C33B" sourceRef="startEvent1" targetRef="sid-7C91C99C-1D01-4AC6-88FB-03CAA1603477"></sequenceFlow>
        <sequenceFlow id="sid-C2FEB1B6-B383-41AF-BBA8-CC9CCB4FD2FA" name="驳回" sourceRef="sid-457C6876-FE69-47E8-B9B1-5F1AEC979758" targetRef="sid-7C91C99C-1D01-4AC6-88FB-03CAA1603477">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="驳回"}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="sid-5D877DFD-FD4F-4686-AD25-162AF7265D28" name="驳回" sourceRef="sid-05C7AEC3-C967-4056-9AAA-B21C57E214F4" targetRef="sid-7C91C99C-1D01-4AC6-88FB-03CAA1603477">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="驳回"}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="sid-A4FA12EE-2B6E-40E1-8324-7C3D08C59D19" name="money&lt;=500" sourceRef="sid-49E6AEBB-D5B9-4B9E-A99E-2E2454642891" targetRef="sid-457C6876-FE69-47E8-B9B1-5F1AEC979758">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money<=500}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="sid-0EFF9C10-9F5B-45C8-B0D5-DF9C6FA3466C" name="通过" sourceRef="sid-05C7AEC3-C967-4056-9AAA-B21C57E214F4" targetRef="sid-27C7BF58-F8CF-4B3A-868C-F2158DF03AD8">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="通过"}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="sid-73F869E4-1EEF-4218-B568-E431EC21D1DA" name="通过" sourceRef="sid-457C6876-FE69-47E8-B9B1-5F1AEC979758" targetRef="sid-27C7BF58-F8CF-4B3A-868C-F2158DF03AD8">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="通过"}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="sid-218819A2-D9B3-4EAC-858D-A1F12D9DDBFF" name="money&gt;500" sourceRef="sid-49E6AEBB-D5B9-4B9E-A99E-2E2454642891" targetRef="sid-05C7AEC3-C967-4056-9AAA-B21C57E214F4">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money>500}]]></conditionExpression>
        </sequenceFlow>
      </process>
      <bpmndi:BPMNDiagram id="BPMNDiagram_mydemo">
        <bpmndi:BPMNPlane bpmnElement="mydemo" id="BPMNPlane_mydemo">
          <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
            <omgdc:Bounds height="30.0" width="30.0" x="60.0" y="199.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="sid-7C91C99C-1D01-4AC6-88FB-03CAA1603477" id="BPMNShape_sid-7C91C99C-1D01-4AC6-88FB-03CAA1603477">
            <omgdc:Bounds height="80.0" width="100.0" x="158.0" y="174.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="sid-49E6AEBB-D5B9-4B9E-A99E-2E2454642891" id="BPMNShape_sid-49E6AEBB-D5B9-4B9E-A99E-2E2454642891">
            <omgdc:Bounds height="40.0" width="40.0" x="303.0" y="194.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="sid-457C6876-FE69-47E8-B9B1-5F1AEC979758" id="BPMNShape_sid-457C6876-FE69-47E8-B9B1-5F1AEC979758">
            <omgdc:Bounds height="80.0" width="100.0" x="405.0" y="174.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="sid-05C7AEC3-C967-4056-9AAA-B21C57E214F4" id="BPMNShape_sid-05C7AEC3-C967-4056-9AAA-B21C57E214F4">
            <omgdc:Bounds height="80.0" width="100.0" x="273.0" y="295.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="sid-27C7BF58-F8CF-4B3A-868C-F2158DF03AD8" id="BPMNShape_sid-27C7BF58-F8CF-4B3A-868C-F2158DF03AD8">
            <omgdc:Bounds height="28.0" width="28.0" x="441.0" y="321.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNEdge bpmnElement="sid-5B89E7D6-7B3A-439A-9F15-D3B985515C7E" id="BPMNEdge_sid-5B89E7D6-7B3A-439A-9F15-D3B985515C7E">
            <omgdi:waypoint x="257.9499999999977" y="214.21623376623376"></omgdi:waypoint>
            <omgdi:waypoint x="303.4130434782609" y="214.4130434782609"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sid-C2FEB1B6-B383-41AF-BBA8-CC9CCB4FD2FA" id="BPMNEdge_sid-C2FEB1B6-B383-41AF-BBA8-CC9CCB4FD2FA">
            <omgdi:waypoint x="455.0" y="174.0"></omgdi:waypoint>
            <omgdi:waypoint x="455.0" y="135.0"></omgdi:waypoint>
            <omgdi:waypoint x="204.20703124999994" y="135.0"></omgdi:waypoint>
            <omgdi:waypoint x="204.20703124999994" y="174.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sid-0EFF9C10-9F5B-45C8-B0D5-DF9C6FA3466C" id="BPMNEdge_sid-0EFF9C10-9F5B-45C8-B0D5-DF9C6FA3466C">
            <omgdi:waypoint x="372.95000000000005" y="335.0"></omgdi:waypoint>
            <omgdi:waypoint x="441.0" y="335.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sid-A4FA12EE-2B6E-40E1-8324-7C3D08C59D19" id="BPMNEdge_sid-A4FA12EE-2B6E-40E1-8324-7C3D08C59D19">
            <omgdi:waypoint x="342.51504576659045" y="214.42748091603053"></omgdi:waypoint>
            <omgdi:waypoint x="404.99999999999324" y="214.18992395437263"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sid-1A2DAF03-7BA0-4531-A02D-09F6AF31C33B" id="BPMNEdge_sid-1A2DAF03-7BA0-4531-A02D-09F6AF31C33B">
            <omgdi:waypoint x="89.94999896690354" y="214.0"></omgdi:waypoint>
            <omgdi:waypoint x="157.99999999997266" y="214.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sid-5D877DFD-FD4F-4686-AD25-162AF7265D28" id="BPMNEdge_sid-5D877DFD-FD4F-4686-AD25-162AF7265D28">
            <omgdi:waypoint x="273.0" y="335.0"></omgdi:waypoint>
            <omgdi:waypoint x="208.0" y="335.0"></omgdi:waypoint>
            <omgdi:waypoint x="208.0" y="253.95000000000002"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sid-218819A2-D9B3-4EAC-858D-A1F12D9DDBFF" id="BPMNEdge_sid-218819A2-D9B3-4EAC-858D-A1F12D9DDBFF">
            <omgdi:waypoint x="323.42083333333335" y="233.52100333055787"></omgdi:waypoint>
            <omgdi:waypoint x="323.1657676348548" y="295.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sid-73F869E4-1EEF-4218-B568-E431EC21D1DA" id="BPMNEdge_sid-73F869E4-1EEF-4218-B568-E431EC21D1DA">
            <omgdi:waypoint x="455.0" y="253.95000000000002"></omgdi:waypoint>
            <omgdi:waypoint x="455.0" y="321.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
        </bpmndi:BPMNPlane>
      </bpmndi:BPMNDiagram>
    </definitions>
    

    5.部署流程
    service层

    /**
         * 部署流程
         * filePath 文件路径 name 流程名字
         */
        public Map<String, Object> deploymentFlow(String filePath, String name) {
            try {
                DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                        .addClasspathResource(filePath).name(name);
                Deployment deployment = deploymentBuilder.deploy();
                logger.info("成功:部署工作流程:" + filePath);
                logger.error("deployment.getKey():" + deployment.getKey());
                logger.error("deployment.getName():" + deployment.getName());
                //acr_re_deployment表的id
                String id = deployment.getId();
    
                ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
                //搜索条件deploymentId
                query.deploymentId(id);
                //最新版本过滤
                query.latestVersion();
                //查询
                ProcessDefinition definition = query.singleResult();
                //act_re_procdef表的key
                String key = definition.getKey();
                System.out.println("act_re_procdef表的key" + key);
                String id1 = definition.getId();
                System.out.println("流程定义id1:::" + id1);
    
                Map<String, Object> map = new HashMap<>();
                map.put("act_re_procdef表的key", key);
                map.put("act_re_procdef表的id", id1);
                return map;
            } catch (Exception e) {
                logger.error("失败:部署工作流:" + e);
                return null;
            }
        }
    

    controller层:

     /**
         * 部署流程
         * */
        @RequestMapping("/deploy")
        public Map<String,Object> deploymentFlow(String filePath, String name){
            return flowableService.deploymentFlow(filePath,name);
        }
    

    测试:http://127.0.0.1:8080/deploy?filePath=processes/demo.bpmn20.xml
    在这里插入图片描述
    6.启动流程
    service层:

    /**
         * 开始流程
         */
        public ProcessInstance startProcessInstance(String processKey, Map map) {
            // 定义流程的key
            // String processDefinitionKey = processKey;
            if (StringUtils.isEmpty(processKey)) {
                return null;
            }
            ProcessInstance pi = runtimeService.startProcessInstanceByKey(processKey, map);
    
            System.out.println("processInstanceId流程实例ID:" + pi.getId());
            System.out.println("ProcessDefinitionId流程定义ID:" + pi.getProcessDefinitionId());
            return pi;
        }
    

    controller层:

    /**
         * 启动流程
         * */
        @RequestMapping("/start")
        public Map<String, Object> startProcessInstance(String processKey, String userId){
            Map<String, Object> map = new HashMap<>();
            map.put("user",userId);
            ProcessInstance pi = flowableService.startProcessInstance(processKey, map);
            Map<String, Object> pra = new HashMap<>();
            pra.put("流程实例ID", pi.getId());
            pra.put("流程定义ID:", pi.getProcessDefinitionId());
            return pra;
        }
    

    测试:http://127.0.0.1:8080/start?processKey=mydemo&userId=123

    在这里插入图片描述
    7.查看待办任务
    service层:

        /**
         * 查询代理人任务
         */
        public List<Task> queryAssigneeTask(String assignee) {
            List<Task> tasks = taskService.createTaskQuery().taskAssignee(assignee).list();
            return tasks;
        }
    

    controler层:

        /**
         * 查询代理人任务
         * */
        @RequestMapping("/queryTask")
        public Map<String, Object> queryAssigneeTask(String assignee){
            List<Task> tasks=flowableService.queryAssigneeTask(assignee);
            Map<String, Object> map = new HashMap<>();
            int i = 1 ;
            for (Task task : tasks) {
                map.put("task"+i,task.toString());
                i++;
            }
            return map;
        }
    

    测试:http://127.0.0.1:8080/queryTask?assignee=123

    在这里插入图片描述
    id:待办理的任务节点id

    name:待办理的任务的描述

    8.出差报销
    service层:

        /**
         * 完成任务
         */
        public boolean completeTask(String taskId, Map<String, Object> paras) {
    
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task == null) {
                logger.error("task:" + task);
                return false;
            }
    
            if (null == paras) {
                taskService.complete(taskId);
            } else {
                taskService.complete(taskId, paras);
            }
    
            return true;
        }
    

    controller层:

    /**
        * 出差报销 
        */
        @RequestMapping("reimburse")
        public String reimburse(String taskId, Integer money) {    
        	Map<String, Object> map = new HashMap<>();    
        	map.put("money", money);    
        	try {        
        		flowableService.completeTask(taskId, map);    
        	} catch (Exception e) {        
        		e.printStackTrace();       
        		return "系统异常";    
        	}    
        	return "申请报销";
        }
    

    测试:http://127.0.0.1:8080/reimburse?taskId=5af07084-ccbe-11e9-80cb-1ae3475a33dc&money=600
    在这里插入图片描述
    9.审核通过
    service层:同上

        /**
         * 完成任务
         */
        public boolean completeTask(String taskId, Map<String, Object> paras) {
    
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task == null) {
                logger.error("task:" + task);
                return false;
            }
    
            if (null == paras) {
                taskService.complete(taskId);
            } else {
                taskService.complete(taskId, paras);
            }
    
            return true;
        }
    

    controller层

        /**
         * 审核通过
         * */
        @RequestMapping("/pass")
        public String pass(String taskId){
            Map<String, Object> map = new HashMap<>();
            map.put("outcome", "通过");
            try {
                flowableService.completeTask(taskId, map);
            }catch (Exception e){
                e.printStackTrace();
                return "系统异常";
            }
            return "审核通过";
        }
    

    测试:http://127.0.0.1:8080/pass?taskId=90a3e272-ccbf-11e9-823f-1ae3475a33dc
    在这里插入图片描述
    10.查看流程图
    service层:

        /**
         * 查看流程是否完成
         */
        public boolean isFinished(String processInstanceId) {
            return historyService.createHistoricProcessInstanceQuery().finished()
                    .processInstanceId(processInstanceId).count() > 0;
        }
    
       /**
         * 查看流程图
         */
        public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) {
            /**
             * 获得当前活动的节点
             */
            String processDefinitionId = "";
            if (this.isFinished(processId)) {
                // 如果流程已经结束,则得到结束节点
                HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
    
                processDefinitionId = pi.getProcessDefinitionId();
            } else {
                // 如果流程没有结束,则取当前活动节点
                // 根据流程实例ID获得当前处于活动状态的ActivityId合集
                ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
                processDefinitionId = pi.getProcessDefinitionId();
            }
            List<String> highLightedActivitis = new ArrayList<String>();
    
            /**
             * 获得活动的节点
             */
            List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
    
            for (HistoricActivityInstance tempActivity : highLightedActivitList) {
                String activityId = tempActivity.getActivityId();
                highLightedActivitis.add(activityId);
            }
    
            List<String> flows = new ArrayList<>();
    
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
            //获取流程图
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
    
            ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
            InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivitis, 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);
                }
            } catch (IOException e) {
                logger.error("操作异常", e);
            } finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                    if (in != null) {
                        in.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    

    controller层:

        /**
         * 查看流程图
         */
        @RequestMapping("/processDiagram")
        public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
            flowableService.genProcessDiagram(httpServletResponse, processId);
        }
    

    测试:http://127.0.0.1:8080/processDiagram?processId=5ae6fa9f-ccbe-11e9-80cb-1ae3475a33dc
    在这里插入图片描述
    问题:流程图中中文有乱码

    解决:添加配置类

    @Configuration
    public class Config implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration>{
        @Override
        public void configure(SpringProcessEngineConfiguration engineConfiguration) {
            engineConfiguration.setActivityFontName("宋体");
            engineConfiguration.setLabelFontName("宋体");
            engineConfiguration.setAnnotationFontName("宋体");
        }
    }
    

    重启项目,再次访问
    乱码问题解决!!!

    三.flowable数据库表的介绍

    在项目启动时,会在数据库新建66张表(版本不同,表的数量可能不同)
    在这里插入图片描述

    1.对表分类

    清单:
    在这里插入图片描述
    通用数据表
    在这里插入图片描述
    流程定义存储表
    在这里插入图片描述
    身份数据表
    在这里插入图片描述
    运行时流程数据表
    在这里插入图片描述
    历史流程数据表
    在这里插入图片描述

    2.流程启动到结束数据库变化

    ​ 部署完毕后,act_re_deployment表中会有一条部署记录,记录这次部署的基本信息,然后是act_ge_bytearray表中有两条记录,记录的是本次上传的bpmn文件和对应的图片文件,每条记录都有act_re_deployment表的外键关联,然后是act_re_procdef表中有一条记录,记录的是该bpmn文件包含的基本信息,包含act_re_deployment表外键。

    流程启动,首先向act_ru_execution表中插入一条记录,记录的是这个流程定义的执行实例,其中id和proc_inst_id相同都是流程执行实例id,也就是本次执行这个流程定义的id,包含流程定义的id外键。

    然后向act_ru_task插入一条记录,记录的是第一个任务的信息,也就是开始执行第一个任务。包括act_ru_execution表中的execution_id外键和proc_inst_id外键,也就是本次执行实例id。

    然后向act_hi_procinst表和act_hi_taskinst表中各插入一条记录,记录的是本次执行实例和任务的历史记录:

    任务提交后,首先向act_ru_variable表中插入变量信息,包含本次流程执行实例的两个id外键,但不包括任务的id,因为setVariable方法设置的是全局变量,也就是整个流程都会有效的变量:

    当流程中的一个节点任务完成后,进入下一个节点任务,act_ru_task表中这个节点任务的记录被删除,插入新的节点任务的记录。

    同时act_ru_execution表中的记录并没有删除,而是将正在执行的任务变成新的节点任务。

    同时向act_hi_var_inst和act_hi_taskinst插入历史记录。

    整个流程执行完毕,act_ru_task,act_ru_execution和act_ru_variable表相关记录全被清空。

    全程有一个表一直在记录所有动作,就是act_hi_actinst表:

    以上就是flowable流程启动到结束的所有流程的变化。

    四.flowable中的五个引擎

    • 内容引擎 ContentEngine
    • 身份识别引擎 IdmEngine
    • 表单引擎 FormEngine
    • 决策引擎DmnEngine
    • 流程引擎 ProcessEngine

    1.流程引擎 ProcessEngine
    1.1 **RepositoryService

    管理流程定义

    1.2 **RuntimeService

    执行管理,包括启动、推进、删除流程实例等操作

    1.3 **TaskService

    任务管理

    1.4 **HistoryService

    历史管理(执行完的数据的管理)

    1.5 IdentityService

    组织机构管理

    1.6 FormService

    一个可选服务,任务表单管理

    1.7 ManagerService

    获取引擎所在的数据库中存在的表、获取表的元数据信息、创建删除等作业、执行命令类、执行自定义SQL、操作事件日志。

    1.8 DynamicBpmnService

    动态修改Bpmn流程定义以及部署库等操作。

    2.内容引擎ContentEngine

    2.1 内容引擎包含的服务有:ContentService和ContentManagementService。

    2.2 ContentManagementService提供对数据库表的管理操作。

    Map<String, Long> getTableCount(); 获取每个表的记录数量;
    String getTableName(Class<?> flowableEntityClass);根据实体类获得对应的数据库表名
    TableMetaData getTableMetaData(String tableName);根据实体类获得对应的数据库表名
    TablePageQuery createTablePageQuery();创建一个可以进行排序、根据条件分页的查询类
    3.身份识别引擎 IdmEngine

    身份识别引擎包含的服务有:IdmIdentityService、IdmManagementService、IdmEngineConfiguration。

    3.1 IdmIdentityService

    • 提供用户的创建、修改、删除、密码修改、登录、用户头像设置等;
    • 提供组Group的创建、删除、用户与组关系的关联、删除关联;
    • 提供权限的创建、删除、关联等.

    3.2 IdmManagementService

    对身份识别相关的数据库表进行统计、获取表的列信息。

    3.3 IdmEngineConfiguration

    提供数据库配置信息。

    4.表单引擎 FormEngine

    4.1 FormManagementService

    提供对数据库表的管理操作。

    4.2 FormRepositoryService

    表单资源服务。

    4.3 FormService

    提供表单实例的增删改查操作服务。

    5.决策引擎DmnEngine

    5.1 DmnManagementService

    该类主要用于获取一系列的数据表元数据信息。

    5.2 DmnRepositoryService

    动态部署流程资源。

    5.3 DmnRuleService

    按照规则启动流程实例。

    5.4 DmnHistoryService

    提供对决策执行历史的访问的服务。

    展开全文
  • flowable工作流

    万次阅读 2017-11-30 11:29:36
    1、 什么是Flowable?...Flowable是Activiti原班主创人员从Activiti分离出来的一套工作流引擎,是一个业务流程管理(BPM)和工作流系统,适用于开发人员和系统管理员。其核心是超快速、稳定的BPMN2流程引擎,易于与

    1、 什么是Flowable?

    如果你对工作流引擎有所了解,那么一定知道Java领域当前主流的工作流引擎无非就是Jboss旗下的JBPM和Alfresco旗下的Activiti。

    Flowable是Activiti原班主创人员从Activiti分离出来的一套工作流引擎,是一个业务流程管理(BPM)和工作流系统,适用于开发人员和系统管理员。其核心是超快速、稳定的BPMN2流程引擎,易于与 Spring集成使用。

    2.eclispe测试Flowable(maven项目)

    2.1 工程目录

    2.2 pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>com.zjgt</groupId>
    	<artifactId>flowable</artifactId>
    	<packaging>war</packaging>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>flowable Maven Webapp</name>
    	<url>http://maven.apache.org</url>
    
    	<dependencies>
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>4.12</version>
    		</dependency>
    		<!-- 导入Mysql数据库链接jar包 -->
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    			<version>5.1.30</version>
    		</dependency>
    
    		<!-- flowable工作流 -->
    		<dependency>
    			<groupId>org.flowable</groupId>
    			<artifactId>flowable-spring</artifactId>
    			<version>6.2.0</version>
    		</dependency>
    		<!-- alibaba 连接池 -->
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>druid</artifactId>
    			<version>1.1.5</version>
    		</dependency>
    
    
    	</dependencies>
    
    	<build>
    		<finalName>flowable</finalName>
    		<resources>
    			<resource>
    				<directory>src/main/java</directory>
    				<includes>
    					<include>**/*.xml</include>
    				</includes>
    			</resource>
    			<resource>
    				<directory>src/main/resources</directory>
    				<includes>
    					<include>**/*</include>
    				</includes>
    			</resource>
    		</resources>
    	</build>
    
    
    </project>
    
    2.3 FlowableTest.java


    package com.cesat;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import org.flowable.engine.IdentityService;
    import org.flowable.engine.ProcessEngine;
    import org.flowable.engine.ProcessEngineConfiguration;
    import org.flowable.engine.RepositoryService;
    import org.flowable.engine.RuntimeService;
    import org.flowable.engine.TaskService;
    import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
    import org.flowable.engine.repository.Deployment;
    import org.flowable.engine.repository.DeploymentBuilder;
    import org.junit.Before;
    import org.junit.Test;
    
    public class FlowableTest {
    
    	// 获取到flowable ProcessEngine
    	ProcessEngine processEngine = null;
    	// 获取RepositoryService 实例对象
    	RepositoryService repositoryService = null;
    	// 资源名称
    	String resourceName = "leaveProcess.bpmn";
    
    	@Test
    	public void init() {
    
    		ProcessEngineConfiguration conf = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
    		// 设置数据源信息
    		conf.setJdbcDriver("com.mysql.jdbc.Driver");
    		conf.setJdbcUrl("jdbc:mysql://localhost:3306/flowable_db");
    		conf.setJdbcUsername("root");
    		conf.setJdbcPassword("123456");
    		// 设置自动建表
    		conf.setDatabaseSchemaUpdate("true");
    		// 创建一个流程引擎对象,在创建流程引擎对象过程中会自动建表
    		ProcessEngine processEngine = conf.buildProcessEngine();
    	}
    
    }
    
    2.3鼠标右键选择RunAS-->Junit Test 即可执行 可在navcat里面查看已经创建好的数据库











    展开全文
  • flowable 工作流

    2021-04-11 19:38:20
    1. 从官网下载flowable-6.5.0 : https://flowable.com/open-source/downloads/ 下载完,解压后,打开目录 wars 2.找个干净的 tomcat8 把 wars 文件目录里面的 flowable-admin.warflowable-idm.warflowable-...

    1. 从官网下载 flowable-6.5.0 :  https://flowable.com/open-source/downloads/

    下载完,解压后,打开目录 wars

    2.找个干净的 tomcat8 

    把 wars 文件目录里面的

    flowable-admin.war  flowable-idm.war  flowable-modeler.war  flowable-rest.war  flowable-task.war

    共 5 个 war包放到tomact的 webapps 目录

    3. 然后找到 tomcat / bin / startup.bat 启动 tomcat

    会等待一段时间,所有war包都解压后

    4.找到每个项目中的。 项目 ww.fhadmin.org

    比如:\webapps\flowable-admin\WEB-INF\classes  application-dev.properties 这样的配置文件

    修改:改成自己的数据库链接地址,数据库名flowable 自己创建,从flowable-6.5.0.zip里面database下面的creat/all 下的sql 脚本执行去建表 86张表

    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8
    spring.datasource.username=root
    spring.datasource.password=root
    
    flowable.admin.app.server-config.process.port=9999
    flowable.admin.app.server-config.cmmn.port=9999
    flowable.admin.app.server-config.app.port=9999
    flowable.admin.app.server-config.dmn.port=9999
    flowable.admin.app.server-config.form.port=9999
    flowable.admin.app.server-config.content.port=9999
    

    修改\webapps\flowable-admin\WEB-INF\classes  flowable-default.properties, 主要就是修改数据库链接上,改成mysql的.  项目 ww.fhadmin.org

    server.port=9988
    server.servlet.context-path=/flowable-admin
    management.endpoints.jmx.unique-names=true
    # This is needed to force use of JDK proxies instead of using CGLIB
    spring.aop.proxy-target-class=false
    spring.aop.auto=false
    spring.application.name=flowable-ui-admin
    spring.liquibase.enabled=false
    spring.servlet.multipart.max-file-size=10MB
    spring.banner.location=classpath:/org/flowable/spring/boot/flowable-banner.txt
    # The default domain for generating ObjectNames must be specified. Otherwise when multiple Spring Boot applications start in the same servlet container
    # all would be created with the same name (com.zaxxer.hikari:name=dataSource,type=HikariDataSource) for example
    spring.jmx.default-domain=${spring.application.name}
    
    # Expose all actuator endpoints to the web
    # They are exposed, but only authenticated users can see /info and /health abd users with access-admin can see the others
    management.endpoints.web.exposure.include=*
    # Full health details should only be displayed when a user is authorized
    management.endpoint.health.show-details=when_authorized
    # Only users with role access-admin can access full health details
    management.endpoint.health.roles=access-admin
    # Spring prefixes the roles with ROLE_. However, Flowable does not have that concept yet, so we need to override that with an empty string
    flowable.common.app.role-prefix=
    
    # H2 example (default)
    
    #spring.datasource.driver-class-name=org.h2.Driver
    #spring.datasource.url=jdbc:h2:tcp://localhost/flowableadmin
    #spring.datasource.url=jdbc:h2:~/flowable-db/db;AUTO_SERVER=TRUE;AUTO_SERVER_PORT=9091;DB_CLOSE_DELAY=-1
    
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8
    
    #spring.datasource.driver-class-name=org.postgresql.Driver
    #spring.datasource.url=jdbc:postgresql://localhost:5432/flowableadmin
    
    #spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
    #spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=flowableadmin
    
    #spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
    #spring.datasource.url=jdbc:oracle:thin:@localhost:1521:FLOWABLEADMIN
    
    #spring.datasource.driver-class-name=com.ibm.db2.jcc.DB2Driver
    #spring.datasource.url=jdbc:db2://localhost:50000/flowableadmin
    
    spring.datasource.username=root
    spring.datasource.password=root

    5. 几个项目的都修改完,关闭之前运行的tomcat ,重新启动

    都正常启动后,需要时间久点

    访问 http://127.0.0.1:8080/flowable-admin   用户名 admin 密码 text

    访问 http://127.0.0.1:8080/flowable-idm   用户名 admin 密码 text

    访问 http://127.0.0.1:8080/flowable-modeler   用户名 admin 密码 text

    展开全文
  • 本文档为flowable工作流官方文档汉化版。 本文档为flowable工作流官方文档汉化版。
  • SpringBoot+Flowable工作流

    2021-06-03 08:09:35
    SpringBoot+Flowable工作流SpringBoot+Flowable工作流SpringBoot整合Flowable初始化表报Error initialising Content schema问题 SpringBoot+Flowable工作流 SpringBoot项目中简单使用flowable工作流 1 pom.xml文件 ...

    SpringBoot+Flowable工作流

    SpringBoot项目中简单使用flowable工作流

    1 pom.xml文件

      <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <version>2.0.9.RELEASE</version>
        </dependency>
        <!--flowable工作流依赖-->
        <dependency>
          <groupId>org.flowable</groupId>
          <artifactId>flowable-spring-boot-starter</artifactId>
          <version>6.3.0</version>
        </dependency>
        <!--mysql依赖-->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.17</version>
        </dependency>
    
      </dependencies>
    

    2 application.yml配置文件

    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
    flowable:
      #关闭定时任务JOB
      async-executor-activate: false
    

    3 在resources下创建文件夹processes,创建文件ExpenseProcess.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: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">
              <![CDATA[false]]></modeler:initiator-can-complete>
          </extensionElements>
        </userTask>
        <exclusiveGateway id="judgeTask"></exclusiveGateway>
        <userTask id="directorTak" name="经理审批">
          <extensionElements>
            <flowable:taskListener event="create"
              class="com.cf.Listener.ManagerTaskHandler"></flowable:taskListener>
          </extensionElements>
        </userTask>
        <userTask id="bossTask" name="老板审批">
          <extensionElements>
            <flowable:taskListener event="create"
              class="com.cf.Listener.BossTaskHandler"></flowable:taskListener>
          </extensionElements>
        </userTask>
        <endEvent id="end" name="结束"></endEvent>
        <sequenceFlow id="directorNotPassFlow" name="驳回" sourceRef="directorTak" targetRef="fillTask">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="fillTask">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></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"><![CDATA[${money > 500}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="directorPassFlow" name="通过" sourceRef="directorTak" targetRef="end">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="judgeLess" name="小于500元" sourceRef="judgeTask" targetRef="directorTak">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 500}]]></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>
    

    4 创建Controller控制类

    package com.cf.controller;
    
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import javax.servlet.http.HttpServletResponse;
    import org.flowable.bpmn.model.BpmnModel;
    import org.flowable.engine.ProcessEngine;
    import org.flowable.engine.ProcessEngineConfiguration;
    import org.flowable.engine.RepositoryService;
    import org.flowable.engine.RuntimeService;
    import org.flowable.engine.TaskService;
    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;
    
    /**
     * @Description:
     * @Date: 2021/5/30
     */
    @Controller
    @RequestMapping("/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) {
            //启动流程
            HashMap<String, Object> map = new HashMap<String, Object>();
            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.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<String, Object>();
            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<String, Object>();
            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<String>();
            List<String> flows = new ArrayList<String>();
            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);
            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();
                }
            }
        }
    
    }
    
    

    5 创建任务处理类BossTaskHandlerManagerTaskHandler

    public class BossTaskHandler implements TaskListener {
    
        public void notify(DelegateTask delegateTask) {
            delegateTask.setAssignee("老板");
        }
    }
    
    public class ManagerTaskHandler implements TaskListener {
    
        public void notify(DelegateTask delegateTask) {
            delegateTask.setAssignee("经理");
        }
    }
    

    6 添加字体配置类

    @Configuration
    public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
    
        public void configure(SpringProcessEngineConfiguration engineConfiguration) {
            engineConfiguration.setActivityFontName("宋体");
            engineConfiguration.setLabelFontName("宋体");
            engineConfiguration.setAnnotationFontName("宋体");
        }
    }
    

    测试
    通过浏览器访问:
    1 添加报销申请 http://127.0.0.1:8080/expense/add?userId=123&money=500
    2 查看任务清单 http://127.0.0.1:8080/expense/list?userId=123
    3 完成任务 http://127.0.0.1:8080/expense/apply?taskId=123
    4 查看流程图 http://127.0.0.1:8080/expense/processDiagram?processId=123

    SpringBoot整合Flowable初始化表报Error initialising Content schema问题

    参考资料:

    flowable 6.3.0版本

    Mysql 5.5.40版本

    相关配置完成后,启动报错

    -- 报错信息
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'expenseController': Unsatisfied dependency expressed through field 'runtimeService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'runtimeServiceBean' defined in class path resource [org/flowable/spring/boot/ProcessEngineAutoConfiguration.class]: Unsatisfied dependency expressed through method 'runtimeServiceBean' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'processEngine': FactoryBean threw exception on object creation; nested exception is org.flowable.engine.common.api.FlowableException: Error initialising Content schema
    
    	Error initialising Content schema
    	
    -- 报错原因 
    Reason: liquibase.exception.DatabaseException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(6) NULL, CREATED_BY_ VARCHAR(255) NULL, LAST_MODIFIED_ timestamp(6) NULL, LAST_' at line 1 [Failed SQL: CREATE TABLE flowable.ACT_CO_CONTENT_ITEM (ID_ VARCHAR(255) NOT NULL, NAME_ VARCHAR(255) NOT NULL, MIME_TYPE_ VARCHAR(255) NULL, TASK_ID_ VARCHAR(255) NULL, PROC_INST_ID_ VARCHAR(255) NULL, CONTENT_STORE_ID_ VARCHAR(255) NULL, CONTENT_STORE_NAME_ VARCHAR(255) NULL, FIELD_ VARCHAR(400) NULL, CONTENT_AVAILABLE_ BIT(1) DEFAULT 0 NULL, CREATED_ timestamp(6) NULL, CREATED_BY_ VARCHAR(255) NULL, LAST_MODIFIED_ timestamp(6) NULL, LAST_MODIFIED_BY_ VARCHAR(255) NULL, CONTENT_SIZE_ BIGINT DEFAULT 0 NULL, TENANT_ID_ VARCHAR(255) NULL, CONSTRAINT PK_ACT_CO_CONTENT_ITEM PRIMARY KEY (ID_))]
    

    ​ 错误提示信息, 检查Mysql的版本, 下列执行的Sql报错. 将Sql拷贝到navicat中运行,报同样错误,怀疑Mysql版本冲突问题. 上网查阅资料, Mysql5.5和5.6版本,在dump中sql语句的时间戳TIMESTAMP有区别, 5.5版本是timestamp , 5.6版本是timestamp(0)后面有跟时间戳.

    ​ 将以上sql中timestamp后括号去掉, 运行sql成功.

    总结: 可通过升级Mysql的版本解决该问题.

    展开全文
  • 项目集成Flowable工作流

    千次阅读 2020-01-17 11:23:50
    企业级项目集成Flowable工作流,基于(师父)的开源项目的集成,此开源项目是师傅十几年的经验和实战总结而成,直接可以用于企业开发,旨为帮助更多需要帮助的人! 说明 链接 项目开原地址 ...
  • Flowable工作流文档: https://tkjohn.github.io/flowable-userguide/
  • flowable工作流子流程介绍 工作流提供了子流程的调用,一种是内部子流程,可以让用户主要看主流程,保持业务清晰,另一种是引用外部子流程(call activity),复用外部流程功能。 工作中有用到flowable 6.5.06版本...
  • 1.添加依赖 <dependency>...org.flowable</groupId> <artifactId>flowable-engine</artifactId> <version>6.4.2</version> </dependency> 2.使用T...
  • spring boot集成flowable工作流 带源码

    千次阅读 热门讨论 2019-02-27 14:26:51
    flowable工作流的介绍参考官方用户手册。 以下直接介绍“出差报销”实例依赖的步骤,源码地址:码云仓库 https://gitee.com/acelee723/acelee-flowable,文章内容转载于: 采用springboot+flowable快速实现工作流...
  • spring-cloud 2.0 集成工作流 flowable
  • Flowable工作流学习

    2019-11-09 21:27:14
    参考资料: 1.Flowable 学习笔记 ...2.Flowable中文文档 https://tkjohn.github.io/flowable-userguide/#_introduction 3.Flowable英文文档 https://www.flowable...
  • flowable 工作流 war包

    2019-03-08 09:31:16
    flowable-6.4.0

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,715
精华内容 686
关键字:

flowable工作流