工作流:一文让你学会使用flowable工作流

article/2025/10/7 14:32:29

1.请假流程图

下图是 一个请假申请的简单流程图
(1)申请人通过发起流程进行请假申请,给经理发送一个待审批事项;
(2)经理在待办列表选择事项,进行审批,approved同意或者rejected驳回操作,并触发不同的事件;
(3)如果经理approved,则触发Enter holidays in external system事件,并给流程发起人发送一个待办事项;
(4)如果经理rejected,则触发Send out rejection email事件,给申请人发送一个请假不批的邮件,流程结束;
(5)如果是(3),申请人需要处理待办任务进行休假,流程结束。

在这里插入图片描述

2.工作流文件

holiday-request.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: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"><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="com.example.flowable.holiday.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="com.example.flowable.holiday.SendRejectionMail"/><sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/><endEvent id="approveEnd"/><endEvent id="rejectEnd"/></process></definitions>

3.pom文件

依赖的jar包如下:

<dependency><groupId>org.flowable</groupId><artifactId>flowable-engine</artifactId><version>6.4.2</version>
</dependency>
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version>
</dependency>

2.源码

(1)HolidayRequest类为测试主类


package com.example.flowable.holiday;import org.flowable.engine.*;
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.engine.task.Comment;
import org.flowable.task.api.Task;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;/**1. 此类描述的是:测试demo2. 参考flowable手册https://tkjohn.github.io/flowable-userguide/3. @author juge4. @version 2021/9/9 9:54
*/
public class HolidayRequest {public static void main(String[] args) {//1.创建一个独立(standalone)配置ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()/*.setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1").setJdbcUsername("sa").setJdbcPassword("").setJdbcDriver("org.h2.Driver")*/.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true").setJdbcUsername("root").setJdbcPassword("123456").setJdbcDriver("com.mysql.jdbc.Driver")//如果数据表不存在的时候,自动创建数据表.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);//2.创建流程引擎ProcessEngine processEngine = cfg.buildProcessEngine();// 使用BPMN 2.0定义process。存储为XML,同时也是可以可视化的。NPMN 2.0标准可以让技术人员与业务人员都参与讨论业务流程中来//3.利用流程引擎部署流程RepositoryService repositoryService = processEngine.getRepositoryService();Deployment deployment = repositoryService.createDeployment().addClasspathResource("holiday-request.bpmn20.xml").deploy();//4.根据流程部署实例id获取流程定义实例ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();System.out.println("Found process definition : " + processDefinition.getName());//5.启动process实例//5.1需要一些初始化的变量,这里我们简单的从Scanner中获取,一般在线上会通过接口传递过来(发起流程的表单)//5.1.1 scanner输入类似于web前端表单输入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();//5.1.2 此处代码类似web后端获取前端表单传来的字段Map<String, Object> variables = new HashMap<String, Object>();variables.put("employee", employee);variables.put("nrOfHolidays", nrOfHolidays);variables.put("description", description);//6.发起流程RuntimeService runtimeService = processEngine.getRuntimeService();ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holidayRequest", variables);//7.经理查询待办任务TaskService taskService = processEngine.getTaskService();/*将第一个任务指派给"经理(managers)"组,而第二个用户任务指派给请假申请的提交人。因此需要为第一个任务添加candidateGroups属性:<userTask id="approveTask" name="Approve or reject request" flowable:candidateGroups="managers"/>这里的candidateGroups,中文一般成为候选组,实际是一组用户的带号,在实际使用中可以写用户的角色id,或者组织机构(岗位、职位)id等当用户查看待办列表时,后台根据用户的id查询角色id,然后用角色id替换managers即可查询到对应的任务列表*/List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();//8.经理处理审批任务//实际一般为用户在web前端页面的待办任务列表,此处演示为控制台输入输出人机交互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?");//8.1 选择要处理的任务//此处一般为web前端页面,点击“同意”或“驳回”的按钮,同意为"y",驳回为"n"int taskIndex = Integer.valueOf(scanner.nextLine());Task task = tasks.get(taskIndex - 1);//使用任务Id获取特定流程实例的变量Map<String, Object> processVariables = taskService.getVariables(task.getId());System.out.println(processVariables.get("employee") + " wants " +processVariables.get("nrOfHolidays") + " of holidays. Do you approve this?");//8.2 编写任务处理意见,并进行approved or rejected的操作//此处一般为web前端页面,点击“同意”或“驳回”的按钮,同意为"y",驳回为"n"boolean approved = scanner.nextLine().toLowerCase().equals("y");//8.3 完成任务//此处代码一般写在web后端,接收到前端的同意或驳回的参数,完成任务variables = new HashMap<String, Object>();variables.put("approved", approved);//注意先保存意见,再完成任务,否则任务完成后找不到if (approved){Comment comment = taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), "同意休假");comment.setUserId("manager");taskService.saveComment(comment);}else{Comment comment = taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), "不允许休假");comment.setUserId("manager");taskService.saveComment(comment);}taskService.complete(task.getId(), variables);//9.申请人查询待办事务/*并如下所示为第二个任务添加assignee属性。请注意我们没有像上面的’managers’一样使用静态值,而是使用一个流程变量动态指派。这个流程变量是在流程实例启动时传递的:<userTask id="holidayApprovedTask" name="Holiday approved" flowable:assignee="${employee}"/>*///注意发起流程时的employee,最好为申请人或者审批人的id或其他唯一字段tasks = taskService.createTaskQuery().taskAssignee(employee).list();//10.申请人处理休假任务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());}if (tasks.size() > 0){System.out.println("Which task would you like to complete?");//10.1 选择要处理的任务taskIndex = Integer.valueOf(scanner.nextLine());task = tasks.get(taskIndex - 1);//使用任务Id获取特定流程实例的变量processVariables = taskService.getVariables(task.getId());System.out.println("Hi " + processVariables.get("employee") + "please use your holidays !");//10.2 完成任务variables = new HashMap<String, Object>();Comment comment1 = taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), processVariables.get("employee") + "休假中");comment1.setUserId("employe");taskService.saveComment(comment1);taskService.complete(task.getId(), variables);}//展示审批意见List<Comment> taskComments = taskService.getProcessInstanceComments(processInstance.getProcessInstanceId());for (Comment comment:taskComments){System.out.println("审批人:"+comment.getUserId()+ ",审批意见:" + comment.getFullMessage() + ",审批时间:" + comment.getTime());}//展示流程流转的历史记录/*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");}*/}
}

(2)CallExternalSystemDelegate类为Enter holidays in external system事件的执行类

package com.example.flowable.holiday;import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;public class CallExternalSystemDelegate implements JavaDelegate {@Overridepublic void execute(DelegateExecution delegateExecution) {System.out.println("Calling the external system for employee "+ delegateExecution.getVariable("employee"));}
}

(3)SendRejectionMail类为Send out rejection email事件的执行类

ackage com.example.flowable.holiday;import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;public class SendRejectionMail implements JavaDelegate {@Overridepublic void execute(DelegateExecution delegateExecution) {System.out.println("send e-mail to employee "+ delegateExecution.getVariable("employee"));}
}

源码下载地址:
https://download.csdn.net/download/juligang320/22333758?spm=1001.2014.3001.5501

3.测试

启动HolidayRequest类进行测试,控制台日志如下:

Found process definition : Holiday Request
Who are you?
john
How many holidays do you want to request?
2
Why do you need them?
go to ...You have 3 tasks:
1) Approve or reject request
2) Approve or reject request
3) Approve or reject request
Which task would you like to complete?
3john wants 2 of holidays. Do you approve this?
yCalling the external system for employee johnYou have 1 tasks:
1) Holiday approved
Which task would you like to complete?
1Hi johnplease use your holidays !审批人:employe,审批意见:john休假中,审批时间:Thu Sep 09 15:13:51 CST 2021
审批人:manager,审批意见:同意休假,审批时间:Thu Sep 09 15:13:47 CST 2021

4 说明

一般工作流使用的是web方式,web前端页面输入,后端进行逻辑处理并输出到前端页面展示。HolidayRequest类中的demo,输入采用scanner,控制台代替web前端页面。

以上列子主要参考一下文档:
flowable官方手册:https://tkjohn.github.io/flowable-userguide/

欢迎交流!


http://chatgpt.dhexx.cn/article/RqehUYtV.shtml

相关文章

jeesite工作流使用

问题&#xff1a;jeesite工作流如何使用&#xff1f; 背景&#xff1a;公司没人熟悉工作流&#xff0c;现在要上线办公系统&#xff0c;请假&#xff0c;加班&#xff0c;报销&#xff0c;预审批&#xff0c;用印&#xff0c;付款等工作流要写&#xff0c;之前有简单版本&…

工作流的大致开发流程

前段时间公司在做一个oa的项目&#xff0c;用到了flowable工作流&#xff0c;刚开始的时候还在纠结于是用activity还是flowable&#xff0c;后来查了相关资料发现flowable的作者之前就是开发activity的作者&#xff0c;只不过后来自己出去又搞了一套就叫做flowable&#xff0c;…

flowable工作流所有业务概念

1.什么是工作流审批 根据本人的理解&#xff0c;就是审批流程管理。 2.什么是flowable 1.官方解释 官方解释如下&#xff1a; Flowable 项目提供了一套核心的开源业务流程引擎&#xff0c;这些引擎紧凑且高效。它们为开发人员、系统管理员和业务用户提供工作流和业务流程管…

微服务与工作流

本文主要想谈一谈工作流在微服务系统中的使用以及工作流能够为微服务系统带来的好处。 通过查找资料可得&#xff0c;微服务的编排主要分为两种形式&#xff0c;一种是“choreography”&#xff0c;有人将其翻译成微服务的编排&#xff1b;另一种是“orchestration”,有人将其翻…

Camunda工作流引擎入门

文档集合 1、camunda文档&#xff1a;https://docs.camunda.org/get-started/quick-start/ 2、camunda资源下载&#xff1a;https://camunda.com/download/ 3、camunda示例github仓库&#xff1a;https://github.com/camunda/camunda-bpm-examples 4、camunda 代码仓库&…

工作流设计详解

工作流 概念&#xff1a; workflow流程性通知和审批控制&#xff0c;业务流程中、发送、提供附加信息或进行附加业务处理&#xff0c;两个或两个以上的人为共同目标&#xff0c;连续以并行或串行的方式完成某一业务。 工作流 设计&#xff1a; 按照业务规划流程图&#xff0…

什么是工作流?为什么程序员要用它?

每一个程序员&#xff0c;在接触到工作流的时候&#xff0c;都会有这么一个疑问——我用一般的方法可以实现&#xff0c;为什么还要用工作流&#xff1f; 我曾经也问过这个问题&#xff0c;不过现在稍微有点明白了。别着急要答案&#xff0c;看过下面的例子&#xff0c;或许你…

什么是工作流

什么是工作流&#xff1f; 工作流是从英文单词work flow中直译过来的。最直白的意思就是日常工作中相对固定的流程计算机化。 在此列举两个工作流简例&#xff1a; 客户到银行开户的工作流&#xff1a; 客户索取开户资料单——资料填写——营业员核对个人证件——营业员核对帐款…

什么是工作流?如何利用工作流引擎实现业务流程

工作流引擎是用来实现工作流的一种组件化工具&#xff0c;它是一整套解决方案&#xff0c;比如说一般工作流引擎包含这些功能&#xff1a;流程节点管理、流向管理等&#xff0c;是为了减小开发成本而推出的。因为在软件开发过程中&#xff0c;如果是从零开始实现工作流&#xf…

什么是工作流,flowable 与 Activiti对比

工作流 什么是工作流工作流是复杂版本的状态机Java工作流开源框架工作流对比Activiti设计器 Flowable兼容性 Camunda设计器兼容性&#xff1a;小结&#xff1a; 社区活跃度FlowableActivitiCamunda 总结 什么是工作流 工作流&#xff0c;是指“业务​过程的部分或整体在​计算…

工作流是什么

刚入职一家公司不久&#xff0c;昨天去和经理与客户对接需求的之前&#xff0c;经理问我接触过工作流没有之前。作为一个20年毕业的老人了&#xff0c;只能尴尬的说一句没有我下去会去了解下。这里我就暂且找一下别人总结的文章和大家一起学习下。 一、什么是工作流 工作流&a…

什么是工作流?

这里说的工作流是狭义的管理工作流程。 现代企业的日常活动中&#xff0c;70%以上都是有两个或两个以上的员工共同参与协作的的任务&#xff0c;比如生产流程、业务流程、各类行政申请流程、财务审批流程、人事处理流程、质量控制及客服流程等。一项工作&#xff0c;经过一个步…

union用法和enum用法

1 union用法 C语言中的union在语法上与struct相似。 union只分配最大成员的空间&#xff0c;所有成员共享这个空间 2 union的注意事项 union的使用受系统大小端的影响 编程&#xff1a;判断系统的大小端 #include <stdio.h>// 1&#xff1a;小端&#xff0c;0&…

C语言 C++中的union用法总结(包懂)

开始的话 已经好长时间没有更新了&#xff0c;对不起自己&#xff0c;更对不起我亲爱的读者&#xff0c;同时也对不起自己开办的这个博客平台。忙&#xff0c;太忙了&#xff0c;忙于找工作&#xff0c;找一份好工作&#xff0c;纠结于去大城市闯呢&#xff0c;还是回到本省的首…

php union用法,SQL Union用法是什么?

sql union用法是什么&#xff1f; sql union用法的总结&#xff1a; UNION 运算符将多个 SELECT 语句的结果组合成一个结果集。 (&#xff11;)使用 UNION 须满足以下条件&#xff1a; &#xff21;&#xff1a;所有查询中必须具有相同的结构(即查询中的的列数和列的顺序必须相…

mysql union语法,mysql中的union用法

UNION在mysql中被称为集合操作,操作类型分为两种:UNION DISTINCT 和 UNION ALL;注意:UNION和UNION DISTINCT是一样的功能。UNION功能为合并多个查询的结果并去重,UNION ALL的功能为合并多个查询的结果不去重。 集合操作时,两边的输入必须拥有相同的列数,如果数据类型不…

mysql得union使用方法_mysql中Union All使用方法

在mysql数据库使用UNION 时&#xff0c;会把结果集中重复的记录删掉&#xff0c;也正因为做了去重操作&#xff0c;所以效率相对Union All来讲稍微低一点&#xff0c;使用UNION ALL &#xff0c;MySQL 会把所有的记录返回&#xff0c;效率高于UNION。本文向大家介绍UNION ALL的…

SQL 中union的使用

采用where的解法 select name,population,area from World where area>3000000 or population>25000000 ;使用union的解法 select name,population,area from World where area>3000000 union select name,population,area from World where population>2500000…

C语言共用体(C语言union用法)详解

转载重点&#xff1a;共用体的所有成员占用同一段内存&#xff0c;修改一个成员会影响其余所有成员。图形分析影响过程 通过前面的讲解&#xff0c;我们知道结构体&#xff08;Struct&#xff09;是一种构造类型或复杂类型&#xff0c;它可以包含多个类型不同的成员。在C语言中…

C语言 union用法

我们知道结构体&#xff08;Struct&#xff09;是一种构造类型或复杂类型&#xff0c;它可以包含多个类型不同的成员。在C语言中&#xff0c;还有另外一种和结构体非常类似的语法&#xff0c;叫做共用体&#xff08;Union&#xff09;&#xff0c;它的定义格式为&#xff1a; …