文章目录

  • 一、什么是flowable?
    • 官方文档:
  • 二、技术选型
  • 三、Flowable与springBoot项目整合
    • 3.1. 添加依赖
    • 3.2. yml 文件配置
    • 3.3. 创建数据库
    • 3.4. 定义流程文件
    • 3.5. 测试controller
    • 3.6. 图片乱码处理
  • 四、启动项目,初始化表结构
  • 五、测试验证
    • 5.1. 创建一个流程:
    • 5.2. 查询待办列表:
    • 5.3. 同意:
    • 5.4. 生成流程图:
    • 项目源码地址:

一、什么是flowable?

对于flowable是什么以及关于此框架的具体信息可以参看此项目的。

官方文档:

https://www.flowable.org/docs/userguide/index.html

官网对于此项目如何使用有非常详细的描述,只是目前还没有对应的中文文档。

Flowable is a light-weight business process engine written in Java.这是官网文档对此框架的完美解释:Flowable是一个用java语言写的轻量级工作流引擎。

在简单了解flowable后与activiti框架相比的第一感觉就是开发方便快速,易与springBoot等各种框架快速整合。如果项目中需要快速实现一些工作流的相关功能那么用此框架是一个不错的选择。

二、技术选型

框架 版本
SpringBoot 2.1.5.RELEASE
flowable 6.4.0
mysql 8.0.11

三、Flowable与springBoot项目整合

3.1. 添加依赖

将flowable的依赖加入到POM中即可,flowable使用需要一个数据库,这里为了方便我选择mysql

   <!--springmvc启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--flowable工作流依赖--><dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter-basic</artifactId><version>6.4.0</version></dependency><!--mysql依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.11</version></dependency>

3.2. yml 文件配置

server:port: 80
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT&nullCatalogMeansCurrent=trueusername: rootpassword: root
flowable:async-executor-activate: false

这样操作后,flowable与springBoot的整个就完成了!

然后就可以运行了,初次运行时flowable会将自动执行flowable中的初始化脚本完成工作流所需要的数据表的建立,如果指定的数据库中还未创建过flowable的相关数据表的话。

3.3. 创建数据库

3.4. 定义流程文件

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.example.demo.listen.ManagerTaskHandler"></flowable:taskListener></extensionElements></userTask><userTask id="bossTask" name="老板审批"><extensionElements><flowable:taskListener event="create"class="com.example.demo.listen.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>

其中的两个代理类为:

package com.gblfy.flowable.listen;import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;/*** @Author: gblfy* @Description:* @Date: Create in 2019/11/03 10:26*/
public class BossTaskHandler implements TaskListener {@Overridepublic void notify(DelegateTask delegateTask) {delegateTask.setAssignee("老板");}
}
package com.gblfy.flowable.listen;import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;/*** @Author: gblfy* @Description:* @Date: Create in 2019/11/03 10:26*/
public class ManagerTaskHandler implements TaskListener {@Overridepublic void notify(DelegateTask delegateTask) {delegateTask.setAssignee("经理");}
}

尽管上面的BPMN文件很长,但放心,毕竟那是通过相关的工具生成出来的,对于核心的逻辑部分也很少(主要在process 标签内) ,如需要详细了解的可自行学习下BPMN的标签即可!当然,在flowable的使用文档中也有相关的描述,详见:Creating a ProcessEngine

这样当此框架启动的时候它会默认加载resource目录下的processes时就可以将此流程配置加载到数据库进行持久化

3.5. 测试controller

@Controller
@RequestMapping(value = "expense")
public class ExpenseController {@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate TaskService taskService;@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate ProcessEngine processEngine;/***************此处为业务代码******************/
}
/*** 添加报销** @param userId    用户Id* @param money     报销金额* @param descption 描述*/@RequestMapping(value = "add")@ResponseBodypublic 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();}//上面的代码通过接收用户的一个请求传入用户的ID和金额以及描述信息来开启一个报销流程,并返回给用户这个流程的Id
/*** 获取审批管理列表 */@RequestMapping(value = "/list")@ResponseBodypublic 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")@ResponseBodypublic 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!";}通过前端传入的任务ID来对此流程进行同意处理
 /*** 拒绝*/@ResponseBody@RequestMapping(value = "reject")public String reject(String taskId) {HashMap<String, Object> map = new HashMap<>();map.put("outcome", "驳回");taskService.complete(taskId, map);return "reject";}//  通过前端传入的任务ID来对此流程进行驳回处理
/*** 生成流程图 生成当前流程节点的流程图** @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的IdList<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);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();}}}

3.6. 图片乱码处理

通过传入流程ID生成当前流程的流程图给前端,如果流程中使用到中文且生成的图片是乱码的,则需要进配置下字体:

package com.gblfy.flowable.config;import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;/*** @Author: gblfy* @Description: 为放置生成的流程图中中文乱码* @Date: Create in 2019/11/03 10:26*/
@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {@Overridepublic void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {springProcessEngineConfiguration.setActivityFontName("宋体");springProcessEngineConfiguration.setLabelFontName("宋体");springProcessEngineConfiguration.setAnnotationFontName("宋体");}
}

四、启动项目,初始化表结构

五、测试验证

5.1. 创建一个流程:

访问:http://localhost:80/expense/add?userId=123&money=123321

返回:提交成功.流程Id为:2b29876c-fde9-11e9-b75f-f8a2d6bfea5a

5.2. 查询待办列表:

访问:http://localhost:80/expense/list?userId=123

输出:Task[id=2b30da72-fde9-11e9-b75f-f8a2d6bfea5a, name=出差报销]

5.3. 同意:

​ 注意 : 带的是taskid

访问:http://localhost:80/expense/apply?taskId=2b30da72-fde9-11e9-b75f-f8a2d6bfea5a

返回:processed ok!

5.4. 生成流程图:

访问: http://localhost:80/expense/processDiagram?processId=2b29876c-fde9-11e9-b75f-f8a2d6bfea5a

项目源码地址:

码云链接:
https://gitee.com/gb_90/springboot-flowable

Gitlab链接:
https://gitlab.com/gb-heima/springboot-flowable

Springboot-Flowable 快速开发工作流相关推荐

  1. SpringBoot+flowable快速实现工作流,so easy!

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/zhan107876/article/ details/120815560 总览 使用flowab ...

  2. 快速开发工作流_02_集成在线流程设计器

    接上一篇:快速开发工作流_01_简单流程案例https://gblfy.blog.csdn.net/article/details/102881983 文章目录 七.流程设计器 modeler 7.1 ...

  3. 快速开发工作流_01_简单流程案例

    文章目录 一.介绍 二.技术选型 三.登录/绘制流程图 3.1. 需要先登录 3.2. 绘制流程图 四. 使用说明 4.1. 选择数据库 4.2. 增加 mybatis, modeler,idm 等配 ...

  4. 快速开发工作流_03_集成在线流程设计器_内置用户免登录

    接上一篇:快速开发工作流_02_集成在线流程设计器 https://gblfy.blog.csdn.net/article/details/103676784 文章目录 八.内置用户免登录 8.1. ...

  5. Jeecg-Boot 2.1.2版本发布,基于SpringBoot的快速开发平台

    项目介绍 JeecgBoot是一款基于代码生成器的JAVA快速开发平台,开源界"小普元"超越传统商业企业级开发平台!采用前后端分离架构:SpringBoot 2.x,Ant Des ...

  6. activiti 工作流_activiti-boot快速开发工作流框架

    activiti-boot是一个快速开发的工作流框架, 采用流行的框架springBoot+mybatis+shiro+redis开发,实现了权限管理(菜单权限.数据权限),activiti工作流程引 ...

  7. 基于React和SpringBoot的快速开发模板QuickAdmin

    经过一段时间的总结和完善,我的管理系统快速开发模板已经基本成型,现在GitHub上开源啦: QuickAdmin QuickAdmin是基于Spring Boot和React.js实现的管理系统开发框 ...

  8. activiti 工作流_技术干货 | 金仓通用数据库中,如何使用Activiti快速开发工作流应用?...

    Activiti 是一个针对企业用户.开发人员 .系统管理员的轻量级工作流业务管理平台,可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言进行定义,业务系统将按照预先定义的流程进行执行,实现业 ...

  9. SpringBoot 接口快速开发神器(接口可视化界面实现)

    点击关注公众号,实用技术文章及时了解 简介 magic-api 是一个基于Java的接口快速开发框架,编写接口将通过magic-api提供的UI界面完成,自动映射为HTTP接口,无需定义Control ...

最新文章

  1. oracle查询游标行数,如何查找Oracle PL/SQL游标中的记录数量?
  2. java微妙_10个微妙的Java编码最佳实践
  3. python 面向对象实现CNN(四)
  4. 【物联网】OpenWrt OpenWRT的源码下载及目录结构
  5. ad元件定位孔放在哪一层_打造个人IP系列(4)——确立定位 搭建人设(上)
  6. apicloud入门学习笔记1:简单介绍
  7. nodejs调用函数和模块
  8. tcp通讯 怎么进行安全认证_西门子PLC在博图环境下进行TCP通讯详解
  9. javascript:;禁用a标签默认功能的缺点。
  10. redis技术分享ppt_一线互联网架构师技术分享:基于redis的分布式锁实现
  11. [转]五个值得关注的图形数据库
  12. java有主函数的类_Android Project中运行带有main函数的Java类
  13. 《Excel图表之道》高清PDF精美样章
  14. win7局域网计算机 慢,win7系统局域网传输速度很慢的方法介绍
  15. iOS蓝牙链接打印机的使用心得
  16. linux远程连接db2,使用命令行连接远程DB2数据库
  17. A + B Problem Too
  18. MongoDB 之滴滴、摩拜都在用的索引-educoder上面的题目以及笔记
  19. window11 网络突然就用不了,系统更新网络就用不了了,DNS服务器可能不可用
  20. google全屏快捷方式 关键字 kiosk

热门文章

  1. (pytorch-深度学习系列)卷积神经网络中的填充(padding)和步幅(stride)
  2. (pytorch-深度学习系列)读取和存储数据-学习笔记
  3. 浅谈python MRO与Mixin模式
  4. 【优秀文章保存】webcollector抽取新闻正文
  5. java 正则表达式 手机号 邮箱(转载)
  6. “云网管” ---云上构建网络自动化体系
  7. 开源微服务编排框架:Netflix Conductor
  8. 内核热补丁,真的安全么?
  9. 如何生成 Flink 作业的交互式火焰图?
  10. 揭秘 RocketMQ 新特性以及在金融场景下的实践