背景
项目上需要使用到工作流相关内容,比对了好久采用flowable实现,该插件和activiti等很相似,基本上可以直接移植
代码如下
<!-- 父引用用-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.13</version>
<relativePath/>
</parent>
<!-- 依赖包 -->
<properties>
<flowable.version>6.8.1</flowable.version>
</properties>
<dependencies>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-ui-modeler</artifactId>
<version>${flowable.version}</version>
</dependency>
<!-- Flowable 核心模块 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-ui-admin</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-ui-idm</artifactId>
<version>${flowable.version}</version>
</dependency>
<!-- thymeleaf架包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-ui-task</artifactId>
<version>${flowable.version}</version>
</dependency>
</dependencies>
配置文件 application-dev.yml
spring:
application:
name: flowable-service
main:
allow-circular-references: true
auto-config:
swagger2: enable
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.167.116.28:3306/z_flow?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
username: root
password: root
hikari:
pool-name: coreHikariPool
maximum-pool-size: 100
connection-timeout: 30000
minimum-idle: 62
idle-timeout: 500000
max-lifetime: 3600000
connection-test-query: SELECT 1
auto-commit: true
flowable:
#异步执行
async-executor-activate: true
#自动更新数据库
database-schema-update: true
#校验流程文件,默认校验resources下的processes文件夹里的流程文件
process-definition-location-prefix: classpath*:/processes/
process-definition-location-suffixes: "**.bpmn20.xml, **.bpmn"
#该配置只是防止页面报错,没有实际意义
common:
app:
idm-admin:
#使用管理员账户进行操作
password: admin-test
user: admin
#指定重定向的地址
idm-url: http://localhost:8080/flowable-demo
# 如果配置以下内容,会根据配置的内容创建一个管理员账户
idm:
app:
admin:
password: admin-test
user-id: admin
first-name: 管
last-name: 理员
在resources中新建processes文件夹,内部的xml文件会被flowable识别,并自动发布流程实例
新建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: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="vacationRequest" name="请假条流程" isExecutable="true">
<!-- -流程的开始 -->
<startEvent id="startEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
<!-- -流程的节点 -->
<userTask id="approveTask" name="开始请假" flowable:candidateGroups="managers"/>
<!-- -流程节点间的线条,上一个节点和下一个节点-->
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
<!-- -排他性网关 -->
<exclusiveGateway id="decision"/>
<!-- -同意时 -->
<sequenceFlow sourceRef="decision" targetRef="holidayApprovedTask">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${approved}]]>
</conditionExpression>
</sequenceFlow>
<!-- -拒绝时 -->
<sequenceFlow sourceRef="decision" targetRef="rejectEnd">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${!approved}]]>
</conditionExpression>
</sequenceFlow>
<!-- -外部服务 -->
<!-- <serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="org.javaboy.flowable02.flowable.Approve"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/> -->
<userTask id="holidayApprovedTask" flowable:assignee="${employee}" name="同意请假"/>
<sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
<!-- <serviceTask id="rejectLeave" name="Send out rejection email"
flowable:class="org.javaboy.flowable02.flowable.Reject"/>
<sequenceFlow sourceRef="rejectLeave" targetRef="rejectEnd"/> -->
<endEvent id="approveEnd"/>
<endEvent id="rejectEnd"/>
<!-- -流程的结束 -->
</process>
</definitions>
使用Springboot的启动类启动即可
常见问题:
出现表格不存在报错
原因:a)可能没有配置自动更新数据库
b) 设置为只查当前连接的schema库即可
(因为当前连接可能已经创建过工作流表)
nullCatalogMeansCurrent=true
2024-07-30 20:19:52.432 ERROR 21708 --- [ main] o.f.c.e.impl.interceptor.CommandContext : Error while closing command context
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table 'z_flow.ACT_GE_PROPERTY' doesn't exist
### The error may exist in org/flowable/common/db/mapping/entity/Property.xml
### The error may involve org.flowable.common.engine.impl.persistence.entity.PropertyEntityImpl.selectProperty-Inline
### The error occurred while setting parameters
### SQL: select * from ACT_GE_PROPERTY where NAME_ = ?
### Cause: java.sql.SQLSyntaxErrorException: Table 'z_flow.ACT_GE_PROPERTY' doesn't exist
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) ~[mybatis-3.5.10.jar:3.5.10]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:153) ~[mybatis-3.5.10.jar:3.5.10]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) ~[mybatis-3.5.10.jar:3.5.10]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) ~[mybatis-3.5.10.jar:3.5.10]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76) ~[mybatis-3.5.10.jar:3.5.10]
at org.flowable.common.engine.impl.db.DbSqlSession.selectById(DbSqlSession.java:311) ~[flowable-engine-common-6.8.1.jar:6.8.1]
at org.flowable.common.engine.impl.db.DbSqlSession.selectById(DbSqlSession.java:295) ~[flowable-engine-common-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.db.ProcessDbSchemaManager.schemaUpdate(ProcessDbSchemaManager.java:217) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.SchemaOperationsProcessEngineBuild.execute(SchemaOperationsProcessEngineBuild.java:54) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.SchemaOperationsProcessEngineBuild.execute(SchemaOperationsProcessEngineBuild.java:28) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.interceptor.CommandInvoker$1.run(CommandInvoker.java:67) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.interceptor.CommandInvoker.executeOperation(CommandInvoker.java:140) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.interceptor.CommandInvoker.executeOperations(CommandInvoker.java:114) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:72) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.interceptor.BpmnOverrideContextInterceptor.execute(BpmnOverrideContextInterceptor.java:26) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.common.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:53) ~[flowable-engine-common-6.8.1.jar:6.8.1]
at org.flowable.common.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:105) ~[flowable-engine-common-6.8.1.jar:6.8.1]
at org.flowable.common.spring.SpringTransactionInterceptor.lambda$execute$0(SpringTransactionInterceptor.java:57) ~[flowable-spring-common-6.8.1.jar:6.8.1]
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.23.jar:5.3.23]
at org.flowable.common.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:57) ~[flowable-spring-common-6.8.1.jar:6.8.1]
at org.flowable.common.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30) ~[flowable-engine-common-6.8.1.jar:6.8.1]
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:56) ~[flowable-engine-common-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.ProcessEngineImpl.<init>(ProcessEngineImpl.java:83) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl.buildProcessEngine(ProcessEngineConfigurationImpl.java:916) ~[flowable-engine-6.8.1.jar:6.8.1]
at org.flowable.spring.SpringProcessEngineConfiguration.buildProcessEngine(SpringProcessEngineConfiguration.java:76) ~[flowable-spring-6.8.1.jar:6.8.1]
at org.flowable.engine.spring.configurator.SpringProcessEngineConfigurator.initProcessEngine(SpringProcessEngineConfigurator.java:58) ~[flowable-spring-configurator-6.8.1.jar:6.8.1]
at org.flowable.engine.spring.configurator.SpringProcessEngineConfigurator.configure(SpringProcessEngineConfigurator.java:47) ~[flowable-spring-configurator-6.8.1.jar:6.8.1]
at org.flowable.common.engine.impl.AbstractEngineConfiguration.configuratorsAfterInit(AbstractEngineConfiguration.java:1120) ~[flowable-engine-common-6.8.1.jar:6.8.1]
at org.flowable.app.engine.AppEngineConfiguration.init(AppEngineConfiguration.java:237) ~[flowable-app-engine-6.8.1.jar:6.8.1]
at org.flowable.app.engine.AppEngineConfiguration.buildAppEngine(AppEngineConfiguration.java:193) ~[flowable-app-engine-6.8.1.jar:6.8.1]
at org.flowable.app.spring.SpringAppEngineConfiguration.buildAppEngine(SpringAppEngineConfiguration.java:66) ~[flowable-app-engine-spring-6.8.1.jar:6.8.1]
at org.flowable.app.spring.AppEngineFactoryBean.getObject(AppEngineFactoryBean.java:58) ~[flowable-app-engine-spring-6.8.1.jar:6.8.1]
at org.flowable.app.spring.AppEngineFactoryBean.getObject(AppEngineFactoryBean.java:31) ~[flowable-app-engine-spring-6.8.1.jar:6.8.1]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:169) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:101) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1884) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1284) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:345) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1391) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[sprin