Flowable工作流引擎:Spring Boot集成指南

news/2024/10/22 7:27:07/

Flowable工作流引擎:Spring Boot集成指南

  • 前言
  • 开始集成
    • 相关配置文件
    • pom文件

前言

在快速变化的软件开发世界中,工作流管理成为了企业应用不可或缺的组成部分。无论是简化复杂业务流程、提升操作效率还是确保流程的一致性和透明性,一个强大的工作流引擎都显得至关重要。在这样的背景下,Flowable作为一个轻量级、可嵌入的工作流引擎,因其卓越的灵活性和易于集成的特点,赢得了开发社区的广泛青睐。

为什么选择Flowable?

Flowable提供了一个功能丰富的工作流和业务流程管理(BPM)平台。它不仅支持BPMN 2.0标准,还提供了易于使用的API和用户友好的管理界面。与同类工作流引擎相比,Flowable拥有活跃的社区支持、频繁的更新发布以及一系列成熟的工具和插件,这些都使得它在处理复杂的业务流程时变得更加得心应手。

Flowable的应用场景

Flowable适用于多种业务场景,包括但不限于文档审批流程、订单处理系统、IT服务管理等。它的灵活性允许开发者根据具体需求定制流程,而其高效的性能则确保了即使在高负载情况下也能平稳运行。

集成需求

对于构建在Spring框架之上的现代应用来说,将Flowable集成进Spring Boot应用中可以带来巨大的便利。这样的集成不仅简化了流程管理,而且充分利用了Spring生态中的丰富资源和便捷性。在本系列文章中,我们将深入探讨如何在Spring Boot环境下集成并使用Flowable,以及如何利用这一集成来优化业务流程。

文章结构

本系列博客将从环境搭建开始,逐步介绍Flowable的基础概念、核心组件以及实际案例。我们会通过详细的步骤和示例代码,演示如何创建和管理流程定义,如何启动和查询流程实例,以及如何处理各种异常情况。最后,我们还会讨论如何将Flowable与Spring Security等其他流行技术结合使用,以实现更加安全和强大的工作流解决方案。

目标读者

无论你是寻求提高现有工作流程效率的开发者,还是需要构建新的工作流程管理系统的软件工程师,甚至是想要了解当前最热门工作流技术的项目经理,本系列博客都将为你提供有价值的信息和指导。

准备工作

在阅读本系列文章之前,建议读者具备一定的Java编程经验和基本的Spring Boot知识。此外,对工作流的基本理解将有助于更好地把握文章的内容。

版本信息

为了确保教程的准确性和可操作性,我们将基于Flowable 6.x版本和Spring Boot 2.x进行讲解。请确保按照这些版本进行环境的搭建。

资源和帮助

在官方Flowable网站(https://flowable.org/)上,你可以找到丰富的文档资源和社区论坛。如果遇到问题,不要犹豫,在论坛中寻求帮助或直接查阅FAQs。

现在,让我们一起踏上探索Flowable和Spring Boot集成之旅,开启高效工作流管理的新纪元。

开始集成

相关配置文件

FlowableConfig

@SuppressWarnings("all")
@Configuration
public class FlowableConfig {@Autowiredprivate DataSource dataSource;@Autowiredprivate PlatformTransactionManager transactionManager;@Autowiredprivate IdWorkerIdGenerator idWorkerIdGenerator;@Value("${workflow.databaseUpdate}")private Boolean databaseUpdate;/*** SpringProcessEngineConfiguration配置** @return*/@Beanpublic SpringProcessEngineConfiguration getSpringProcessEngineConfiguration() {// 创建SpringProcessEngineConfiguration对象SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();// 设置活动元素的字体名称为"宋体"config.setActivityFontName("宋体");// 设置注解元素的字体名称为"宋体"config.setAnnotationFontName("宋体");// 设置标签元素的字体名称为"黑体"config.setLabelFontName("黑体");// 设置数据源config.setDataSource(dataSource);// 设置事务管理器config.setTransactionManager(transactionManager);// 禁用身份和访问管理引擎config.setDisableIdmEngine(true);// 设置数据库类型为MySQLconfig.setDatabaseType(ProcessEngineConfigurationImpl.DATABASE_TYPE_MYSQL);// 设置数据库模式更新策略为自动更新 生产环境设置DB_SCHEMA_UPDATE_FALSEif (null != databaseUpdate && databaseUpdate) {config.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);} else {config.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE);}// 设置委托表达式字段注入模式为混合模式config.setDelegateExpressionFieldInjectionMode(DelegateExpressionFieldInjectionMode.MIXED);// 设置ID生成器为idWorkerIdGeneratorconfig.setIdGenerator(idWorkerIdGenerator);// 激活异步执行器 关闭异步执行器config.setAsyncExecutorActivate(Boolean.FALSE);// 设置HTTP客户端配置HttpClientConfig httpClientConfig = new HttpClientConfig();httpClientConfig.setConnectTimeout(1000000); // 连接超时时间httpClientConfig.setConnectionRequestTimeout(1000000); // 连接请求超时时间httpClientConfig.setSocketTimeout(1000000); // 建立socket连接超时时间httpClientConfig.setRequestRetryLimit(3); // 请求失败重试次数config.setHttpClientConfig(httpClientConfig);// 历史数据记录级别config.setHistoryLevel(HistoryLevel.AUDIT);// 设置知识库缓存限制为200config.setKnowledgeBaseCacheLimit(200);// 设置流程定义缓存限制为200config.setProcessDefinitionCacheLimit(200);// 添加自定义的JobHandlerList<JobHandler> customJobHandlers = new ArrayList<>();customJobHandlers.add(new CustomJobHandler());config.setCustomJobHandlers(customJobHandlers);return config;}@Bean@Primarypublic TaskExecutor primaryTaskExecutor() {return new ThreadPoolTaskExecutor();}}

IdWorkerIdGenerator

@Component
public class IdWorkerIdGenerator implements IdGenerator {@Overridepublic String getNextId() {return String.valueOf(SpringUtils.getBean(IdWorker.class).nextId());}
}
@Component
public class IdWorker {// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)private final static long twepoch = 1288834974657L;// 机器标识位数private final static long workerIdBits = 5L;// 数据中心标识位数private final static long datacenterIdBits = 5L;// 机器ID最大值private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);// 数据中心ID最大值private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);// 毫秒内自增位private final static long sequenceBits = 12L;// 机器ID偏左移12位private final static long workerIdShift = sequenceBits;// 数据中心ID左移17位private final static long datacenterIdShift = sequenceBits + workerIdBits;// 时间毫秒左移22位private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;private final static long sequenceMask = -1L ^ (-1L << sequenceBits);/* 上次生产id时间戳 */private static long lastTimestamp = -1L;// 0,并发控制private long sequence = 0L;private final long workerId;// 数据标识id部分private final long datacenterId;public IdWorker() {this.datacenterId = getDatacenterId(maxDatacenterId);this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);}/*** @param workerId     工作机器ID* @param datacenterId 序列号*/public IdWorker(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));}this.workerId = workerId;this.datacenterId = datacenterId;}/*** 获取下一个ID** @return*/public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}if (lastTimestamp == timestamp) {// 当前毫秒内,则+1sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {// 当前毫秒内计数满了,则等待下一秒timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;// ID偏移组合生成最终的ID,并返回IDlong nextId = ((timestamp - twepoch) << timestampLeftShift)| (datacenterId << datacenterIdShift)| (workerId << workerIdShift) | sequence;return nextId;}private long tilNextMillis(final long lastTimestamp) {long timestamp = this.timeGen();while (timestamp <= lastTimestamp) {timestamp = this.timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}/*** <p>* 获取 maxWorkerId* </p>*/protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {StringBuffer mpid = new StringBuffer();mpid.append(datacenterId);String name = ManagementFactory.getRuntimeMXBean().getName();if (!name.isEmpty()) {/** GET jvmPid*/mpid.append(name.split("@")[0]);}/** MAC + PID 的 hashcode 获取16个低位*/return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);}/*** <p>* 数据标识id部分* </p>*/protected static long getDatacenterId(long maxDatacenterId) {long id = 0L;try {InetAddress ip = InetAddress.getLocalHost();NetworkInterface network = NetworkInterface.getByInetAddress(ip);if (network == null) {id = 1L;} else {byte[] mac = network.getHardwareAddress();id = ((0x000000FF & (long) mac[mac.length - 1])| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;id = id % (maxDatacenterId + 1);}} catch (Exception e) {System.out.println(" getDatacenterId: " + e.getMessage());}return id;}
}

CustomJobHandler

@Slf4j
public class CustomJobHandler implements JobHandler {public static final String TYPE = "custom-handler";@Overridepublic String getType() {return "custom-handler";}@Overridepublic void execute(JobEntity jobEntity, String s, VariableScope variableScope, CommandContext commandContext) {log.info("============执行自定义定时任务============");log.info("定时任务详情={}", JSON.toJSONString(jobEntity));}
}

pom文件

  <flowable.version>6.7.2</flowable.version><!-- Flowable相关依赖项 --><dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>${flowable.version}</version><exclusions><!-- 排除flowable-spring-boot-starter-app,因为不需要该功能 --><exclusion><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter-app</artifactId></exclusion><!-- 排除flowable-form-spring-configurator,因为不需要该功能 --><exclusion><groupId>org.flowable</groupId><artifactId>flowable-form-spring-configurator</artifactId></exclusion><!-- 排除flowable-idm-spring-configurator,因为不需要该功能 --><exclusion><groupId>org.flowable</groupId><artifactId>flowable-idm-spring-configurator</artifactId></exclusion><!-- flowable-spring-boot-starter-cmmn,因为不需要该功能 --><exclusion><groupId>org.flowable</groupId><artifactId>flowable-cmmn-spring-configurator</artifactId></exclusion><!-- flowable-spring-boot-starter-cmmn,因为不需要该功能 --><exclusion><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter-cmmn</artifactId></exclusion><!-- flowable-spring-boot-starter-dmn,因为不需要该功能 --><exclusion><groupId>org.flowable</groupId><artifactId>flowable-dmn-spring-configurator</artifactId></exclusion><!-- flowable-spring-boot-starter-dmn,因为不需要该功能 --><exclusion><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter-dmn</artifactId></exclusion><!-- 排除mybatis,因为与其他依赖项存在冲突 --><exclusion><artifactId>mybatis</artifactId><groupId>org.mybatis</groupId></exclusion></exclusions></dependency><!-- flowable-bpmn-model依赖项,用于创建和操作BPMN 2.0流程模型 --><dependency><groupId>org.flowable</groupId><artifactId>flowable-bpmn-model</artifactId><version>${flowable.version}</version><scope>compile</scope></dependency><!-- flowable-json-converter依赖项,用于将BPMN模型转换为JSON格式,并在需要时进行反向转换 --><dependency><groupId>org.flowable</groupId><artifactId>flowable-json-converter</artifactId><version>${flowable.version}</version><scope>compile</scope></dependency><!-- flowable-bpmn-converter依赖项,用于将BPMN模型转换为Flowable内部的可执行流程定义 --><dependency><groupId>org.flowable</groupId><artifactId>flowable-bpmn-converter</artifactId><version>${flowable.version}</version><scope>compile</scope></dependency><!-- flowable-bpmn-layout依赖项,用于自动布局BPMN模型,以确保流程图的可读性和美观性 --><dependency><groupId>org.flowable</groupId><artifactId>flowable-bpmn-layout</artifactId><version>${flowable.version}</version></dependency>

至此便完成了初步集成,可在项目中使用flowable的api完成工作流的使用。

使用也很简单 ,直接注入使用即可

  @Autowiredprivate IProcessDefinitionService iProcessDefinitionService;@Autowiredprivate RepositoryService repositoryService;

http://www.ppmy.cn/news/1423277.html

相关文章

前端网络---http协议演变

http协议的演变 什么是http协议&#xff1f; HTTP 协议全称为 Hypertext Transfer Protocol&#xff0c;即超文本传输协议&#xff0c;是互联网上应用最为广泛的一种网络传输协议 http协议演变 1991年0.9版本-------1996年1.0版本-------1997年1.1版本--------2015年2版本-…

走 https 和不走 https 对前端有什么影响

走 https 和不走 https 对前端有什么影响 之前网站走的是 https &#xff0c;自从域名那边改成需要三个月就要更新之后就没有再用 https&#xff0c;现在都是走的 http&#xff0c;使用中遇到了几个比较明显的功能限制。 最直接的影响就是不能使用 ServiceWorker 了&#xff…

简述Kafka的高可靠性

什么叫可靠性&#xff1f; 大家都知道&#xff0c;系统架构有三高&#xff1a;「高性能、高并发和高可用」&#xff0c;三者的重要性不言而喻。 对于任意系统&#xff0c;想要同时满足三高都是一件非常困难的事情&#xff0c;大型业务系统或者传统中间件都会搭建复杂的架构来…

病毒繁殖-第12届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第52讲。 病毒繁殖&#xf…

IDEA远程调试debug

IDEA远程调试debug jar包启动脚本配置IDEA配置 通俗的说&#xff1a;本地有代码&#xff0c;服务器项目出现问题&#xff0c;环境的中间件配置不同&#xff0c;用idea远程调试&#xff0c;能快速定位问题&#xff0c;解决问题。 jar包启动脚本配置 jdk5-8写法 java -Xdebug -…

Linux:Redis7.2.4的源码包部署(2)

本章使用的是centos9进行部署 1.获取rpm安装包 Index of /releases/ (redis.io)https://download.redis.io/releases/这个网站有历史的版本&#xff0c;我这里使用的是最新版7.2.4进行安装 点击即可进行下载 方进Linux中&#xff0c;如果你的Linux中可以直接使用wget去下载 2…

Ubuntu 22.04安装中文输入法

1. 安装 sudo apt install fcitx5 2. 管理已安装的语言 Setting->Region & Language->Manage Installed Language 在下图中点击“安装”&#xff0c;之后需要等一会 选择Fcitx 5 3. 添加输入法 Setting->Keyboard 点击chinese 选择你想要的输入法 重启一下&a…

全网最全 Linux 命令总结,建议收藏!

今天&#xff0c;给小伙伴们带来一篇 Linux 命令总结的非常全的文章&#xff0c;也是我们平时工作中使用率非常高的操作命令&#xff0c;命令有点多&#xff0c;建议小伙伴们可以先收藏后阅读。 1 基本命令 uname -m 显示机器的处理器架构 uname -r 显示正在使用的内核版本 …