flowable导入bpmn文件
在springboot项目的resources目录下面新建文件夹processes,把bpmn的xml文件放入processes文件夹中,再次启动项目,这个流程文件就自动部署了。

但是这种方式部署方式局限性太大,导入后流程的名字,分类,key都是自动生成或者是null值,不方便使用,因此一般不会使用这种导入流程的方式,下面介绍通过其他导入流程的方式。
首先自动注入RepositoryService:
@Autowired
RepositoryService repositoryService;
根据RepositoryService这个类的注释Service providing access to the repository of process definitions and deployments可以知道这个类的功能就是进行流程部署和流程定义查询的。
flowable中提供的类的使用方法都是先调用createXXXX方法,之后进行相关设置,然后使用,例如部署流程,就是调用createDeployment之后获得DeploymentBuilder,之后调用对象的deploy方法部署该流程。
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
.addInputStream("demo",new FileInputStream("D:\\demo.bpmn20.xml"));
deploymentBuilder.deploy();
可以在配置文件中添加一行配置:
logging.level.org.flowable=debug
这样就可以在日志中输出flowable执行的SQL语句,可以加深对flowable的理解。
DeploymentBuilder里面有很多方法,大体可以分为两类,跟bpmn文件有关的和设置bpmn属性有关的。

上面这些方法都是跟bpmn文件相关的,有从文件流导入的,有从classpath下导入的,有从字节流导入的,还有导入zip文件的,这里以导入文件流为例,因为不管从网页还是从磁盘都可以读取为文件流进行部署。

这两个方法是关闭检查xml是否合规用的,关闭之后不再检查xml文件是否符合规范,一般不要关闭。

这些方法是设置名字,分类,key,父流程id,多租户(多租户以后讲),建议名字,分类,key都要设置,不然系统会自动设置或者使用null值,会在后期导致很多问题。

后面的方法根据注释大概也能理解,然后就可以写出如下部署代码:
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
.name("核减流程")
.category("办公流程")
.key("reduce")
.addInputStream("demo.bpmn",new FileInputStream("D:\\demo.bpmn20.xml"));
deploymentBuilder.deploy();
注意:这里如果使用addInputStream方法,name属性必须以.bpmn或bpmn20.xml结尾,否则不会向ACT_RE_PROCDEF表中插入数据
部署时的日志文件也很好理解:
2023-01-31 09:52:38.693 DEBUG 17360 --- [ main] o.f.c.e.impl.interceptor.LogInterceptor : --- starting DeployCmd --------------------------------------------------------
2023-01-31 09:52:38.693 DEBUG 17360 --- [ main] o.f.c.s.SpringTransactionInterceptor : Running command with propagation REQUIRED
2023-01-31 09:52:38.694 DEBUG 17360 --- [ main] o.f.c.engine.impl.agenda.AbstractAgenda : Operation class org.flowable.engine.impl.interceptor.CommandInvoker$1 added to agenda
2023-01-31 09:52:38.694 DEBUG 17360 --- [ main] o.f.e.impl.interceptor.CommandInvoker : Executing operation class org.flowable.engine.impl.interceptor.CommandInvoker$1
2023-01-31 09:52:38.695 DEBUG 17360 --- [ main] o.f.e.impl.bpmn.deployer.BpmnDeployer : Processing deployment 核减流程
2023-01-31 09:52:38.695 DEBUG 17360 --- [ main] o.f.e.i.b.d.ParsedDeploymentBuilder : Processing BPMN resource demo.bpmn
2023-01-31 09:52:38.958 WARN 17360 --- [ main] o.f.engine.impl.bpmn.parser.BpmnParse : Following warnings encountered during process validation: [Validation set: 'flowable-executable-process' | Problem: 'flowable-exclusive-gateway-seq-flow-without-conditions'] : Exclusive gateway has at least one outgoing sequence flow without a condition (which isn't the default one) - [Extra info : processDefinitionId = flow_e8096tma | processDefinitionName = flow_7a7oej0l | | id = Gateway_0tprzx4 | | activityName = | ] ( line: 52, column: 56)
[Validation set: 'flowable-executable-process' | Problem: 'flowable-exclusive-gateway-seq-flow-without-conditions'] : Exclusive gateway has at least one outgoing sequence flow without a condition (which isn't the default one) - [Extra info : processDefinitionId = flow_e8096tma | processDefinitionName = flow_7a7oej0l | | id = Gateway_0rxfh19 | | activityName = | ] ( line: 81, column: 56)
[Validation set: 'flowable-executable-process' | Problem: 'flowable-exclusive-gateway-seq-flow-without-conditions'] : Exclusive gateway has at least one outgoing sequence flow without a condition (which isn't the default one) - [Extra info : processDefinitionId = flow_e8096tma | processDefinitionName = flow_7a7oej0l | | id = Gateway_1rfyplm | | activityName = | ] ( line: 92, column: 56)
2023-01-31 09:52:38.958 DEBUG 17360 --- [ main] o.f.e.i.b.p.handler.ProcessParseHandler : Parsing process flow_e8096tma
2023-01-31 09:52:39.416 DEBUG 17360 --- [ main] p.e.P.selectLatestProcessDefinitionByKey : ==> Preparing: select * from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null) and DERIVED_FROM_ is null and VERSION_ = (select max(VERSION_) from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null))
2023-01-31 09:52:39.420 DEBUG 17360 --- [ main] p.e.P.selectLatestProcessDefinitionByKey : ==> Parameters: flow_e8096tma(String), flow_e8096tma(String)
2023-01-31 09:52:39.426 DEBUG 17360 --- [ main] p.e.P.selectLatestProcessDefinitionByKey : <== Total: 1
2023-01-31 09:52:39.429 DEBUG 17360 --- [ main] ubscriptionsByTypeAndProcessDefinitionId : ==> Preparing: select * from ACT_RU_EVENT_SUBSCR WHERE (EVENT_TYPE_ = ?) and PROC_DEF_ID_ = ? and EXECUTION_ID_ is null and PROC_INST_ID_ is null and (TENANT_ID_ = '' or TENANT_ID_ is null)
2023-01-31 09:52:39.431 DEBUG 17360 --- [ main] ubscriptionsByTypeAndProcessDefinitionId : ==> Parameters: message(String), flow_e8096tma:1:eeae9675-a109-11ed-a95e-d41b81b9a72d(String)
2023-01-31 09:52:39.435 DEBUG 17360 --- [ main] ubscriptionsByTypeAndProcessDefinitionId : <== Total: 0
2023-01-31 09:52:39.437 DEBUG 17360 --- [ main] ubscriptionsByTypeAndProcessDefinitionId : ==> Preparing: select * from ACT_RU_EVENT_SUBSCR WHERE (EVENT_TYPE_ = ?) and PROC_DEF_ID_ = ? and EXECUTION_ID_ is null and PROC_INST_ID_ is null and (TENANT_ID_ = '' or TENANT_ID_ is null)
2023-01-31 09:52:39.439 DEBUG 17360 --- [ main] ubscriptionsByTypeAndProcessDefinitionId : ==> Parameters: signal(String), flow_e8096tma:1:eeae9675-a109-11ed-a95e-d41b81b9a72d(String)
2023-01-31 09:52:39.441 DEBUG 17360 --- [ main] ubscriptionsByTypeAndProcessDefinitionId : <== Total: 0
2023-01-31 09:52:39.442 DEBUG 17360 --- [ main] bByTypeAndProcessDefinitionKeyNoTenantId : ==> Preparing: select J.* from ACT_RU_TIMER_JOB J inner join ACT_RE_PROCDEF P on J.PROC_DEF_ID_ = P.ID_ where J.HANDLER_TYPE_ = ? and P.KEY_ = ? and (P.TENANT_ID_ = '' or P.TENANT_ID_ is null)
2023-01-31 09:52:39.444 DEBUG 17360 --- [ main] bByTypeAndProcessDefinitionKeyNoTenantId : ==> Parameters: timer-start-event(String), flow_e8096tma(String)
2023-01-31 09:52:39.446 DEBUG 17360 --- [ main] bByTypeAndProcessDefinitionKeyNoTenantId : <== Total: 0
2023-01-31 09:52:39.447 DEBUG 17360 --- [ main] o.f.c.e.impl.interceptor.LogInterceptor : --- starting GetProcessDefinitionInfoCmd --------------------------------------------------------
2023-01-31 09:52:39.447 DEBUG 17360 --- [ main] o.f.c.s.SpringTransactionInterceptor : Running command with propagation REQUIRED
2023-01-31 09:52:39.447 DEBUG 17360 --- [ main] o.f.c.e.i.i.CommandContextInterceptor : Valid context found. Reusing it for the current command 'org.flowable.engine.impl.cmd.GetProcessDefinitionInfoCmd'
2023-01-31 09:52:39.448 DEBUG 17360 --- [ main] o.f.c.engine.impl.agenda.AbstractAgenda : Operation class org.flowable.engine.impl.interceptor.CommandInvoker$1 added to agenda
2023-01-31 09:52:39.448 DEBUG 17360 --- [ main] o.f.e.impl.interceptor.CommandInvoker : Executing operation class org.flowable.engine.impl.interceptor.CommandInvoker$1
2023-01-31 09:52:39.448 DEBUG 17360 --- [ main] ocessDefinitionInfoByProcessDefinitionId : ==> Preparing: select * from ACT_PROCDEF_INFO where PROC_DEF_ID_ = ?
2023-01-31 09:52:39.449 DEBUG 17360 --- [ main] ocessDefinitionInfoByProcessDefinitionId : ==> Parameters: flow_e8096tma:2:f158cee9-a109-11ed-a95e-d41b81b9a72d(String)
2023-01-31 09:52:39.451 DEBUG 17360 --- [ main] ocessDefinitionInfoByProcessDefinitionId : <== Total: 0
2023-01-31 09:52:39.451 DEBUG 17360 --- [ main] o.f.c.e.impl.interceptor.LogInterceptor : --- GetProcessDefinitionInfoCmd finished --------------------------------------------------------
2023-01-31 09:52:39.451 DEBUG 17360 --- [ main] o.flowable.engine.impl.app.AppDeployer : Processing app deployment 核减流程
2023-01-31 09:52:39.452 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : Flushing dbSqlSession
2023-01-31 09:52:39.452 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : insert ProcessDefinitionEntity[flow_e8096tma:2:f158cee9-a109-11ed-a95e-d41b81b9a72d]
2023-01-31 09:52:39.452 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : insert DeploymentEntity[id=f0e94436-a109-11ed-a95e-d41b81b9a72d, name=核减流程]
2023-01-31 09:52:39.452 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : insert ResourceEntity[id=f0e94437-a109-11ed-a95e-d41b81b9a72d, name=demo.bpmn]
2023-01-31 09:52:39.452 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : insert ResourceEntity[id=f1572138-a109-11ed-a95e-d41b81b9a72d, name=demo.flow_e8096tma.png]
2023-01-31 09:52:39.453 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : flush summary: 4 insert, 0 update, 0 delete.
2023-01-31 09:52:39.453 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : now executing flush...
2023-01-31 09:52:39.453 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : inserting: ProcessDefinitionEntity[flow_e8096tma:2:f158cee9-a109-11ed-a95e-d41b81b9a72d]
2023-01-31 09:52:39.454 DEBUG 17360 --- [ main] o.f.e.i.p.e.P.insertProcessDefinition : ==> Preparing: insert into ACT_RE_PROCDEF(ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_, HAS_GRAPHICAL_NOTATION_ , SUSPENSION_STATE_, DERIVED_FROM_, DERIVED_FROM_ROOT_, DERIVED_VERSION_, TENANT_ID_, ENGINE_VERSION_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2023-01-31 09:52:39.460 DEBUG 17360 --- [ main] o.f.e.i.p.e.P.insertProcessDefinition : ==> Parameters: flow_e8096tma:2:f158cee9-a109-11ed-a95e-d41b81b9a72d(String), http://www.flowable.org/processdef(String), flow_7a7oej0l(String), flow_e8096tma(String), 2(Integer), f0e94436-a109-11ed-a95e-d41b81b9a72d(String), demo.bpmn(String), demo.flow_e8096tma.png(String), null, false(Boolean), true(Boolean), 1(Integer), null, null, 0(Integer), (String), null
2023-01-31 09:52:39.461 DEBUG 17360 --- [ main] o.f.e.i.p.e.P.insertProcessDefinition : <== Updates: 1
2023-01-31 09:52:39.462 DEBUG 17360 --- [ main] o.f.common.engine.impl.db.DbSqlSession : inserting: DeploymentEntity[id=f0e94436-a109-11ed-a95e-d41b81b9a72d, name=核减流程]
2023-01-31 09:52:39.462 DEBUG 17360 --- [ main] o.f.e.i.p.e.D.insertDeployment : ==> Preparing: insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, KEY_, TENANT_ID_, DEPLOY_TIME_, DERIVED_FROM_, DERIVED_FROM_ROOT_, PARENT_DEPLOYMENT_ID_, ENGINE_VERSION_) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2023-01-31 09:52:39.467 DEBUG 17360 --- [ main] o.f.e.i.p.e.D.insertDeployment : ==> Parameters: f0e94436-a109-11ed-a95e-d41b81b9a72d(String), 核减流程(String), 办公流程(String), reduce(String), (String), 2023-01-31 09:52:38.694(Timestamp), null, null, f0e94436-a109-11ed-a95e-d41b81b9a72d(String), null
2023-01-31 09:52:39.469 DEBUG 17360 --- [ main] o.f.e.i.p.e.D.insertDeployment : <== Updates: 1
2023-01-31 09:52:39.472 DEBUG 17360 --- [ main] o.f.e.i.p.e.R.bulkInsertResource : ==> Preparing: INSERT INTO ACT_GE_BYTEARRAY(ID_, REV_, NAME_, BYTES_, DEPLOYMENT_ID_, GENERATED_) VALUES (?, 1, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?)
2023-01-31 09:52:39.475 DEBUG 17360 --- [ main] o.f.e.i.p.e.R.bulkInsertResource : ==> Parameters: f0e94437-a109-11ed-a95e-d41b81b9a72d(String), demo.bpmn(String), java.io.ByteArrayInputStream@17e323fd(ByteArrayInputStream), f0e94436-a109-11ed-a95e-d41b81b9a72d(String), false(Boolean), f1572138-a109-11ed-a95e-d41b81b9a72d(String), demo.flow_e8096tma.png(String), java.io.ByteArrayInputStream@6df0d030(ByteArrayInputStream), f0e94436-a109-11ed-a95e-d41b81b9a72d(String), true(Boolean)
2023-01-31 09:52:39.482 DEBUG 17360 --- [ main] o.f.e.i.p.e.R.bulkInsertResource : <== Updates: 2
2023-01-31 09:52:39.483 DEBUG 17360 --- [ main] o.f.c.e.impl.interceptor.LogInterceptor : --- DeployCmd finished --------------------------------------------------------
可以看到,flowable首先会检查bpmn文件是否有问题,如果有问题就不会导入。
之后根据流程图xml文件中的id去查询是否已经存在该流程:

select * from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null) and DERIVED_FROM_ is null and VERSION_ = (select max(VERSION_) from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null))
参数为:
flow_e8096tma(String), flow_e8096tma(String)
这个SQL语句中有一个子查询:
select max(VERSION_) from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null)
这个子查询的作用是查询key为某个值的流程的最大版本号,关于版本号在后面会提到。
如果没有查到,则向ACT_RE_PROCDEF,ACT_RE_DEPLOYMENT,ACT_GE_BYTEARRAY三张表中插入数据。

可以看到,ACT_RE_PROCDEF中的数据并不是代码中的name和key,而是xml文件中配置的内容。

注意:尽量不要手动修改flowable数据库表格的内容,否则可能造成意想不到的问题。
修改xml文件重新部署

可以看到,重新导入后的数据就是我们想要的数据了。
再次导入修改后的流程图,会发现flowable会在查询到有相同key的流程图存在时会将VERSION_字段加1处理。

可以看到,再次导入key相同的流程图时,因为ACT_RE_PROCDEF中key相同时,flowable会认为是同一份bpmn文件进行了修改,因此会将VERSION_字段加1,因此对于我们以后操作流程的时候,最好使用key值进行操作,这样flowable会自动的筛选出最新的版本供我们使用。

可以看到,这三张表是通过DEPLOYMENT_ID_字段关联在一起的。
到这里流程部署就完成了。
再次运行程序,又会插入两条数据,方便我们查询流程数据。

查询部署的流程的方式也符合先createXXX,再使用的原则,查询代码如下:
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
List<ProcessDefinition> list = processDefinitionQuery.list();
具体查询过程如下:
2023-01-31 14:17:03.680 DEBUG 23452 --- [ main] .selectProcessDefinitionsByQueryCriteria : ==> Preparing: SELECT RES.* from ACT_RE_PROCDEF RES order by RES.ID_ asc
2023-01-31 14:17:03.681 DEBUG 23452 --- [ main] .selectProcessDefinitionsByQueryCriteria : ==> Parameters:
2023-01-31 14:17:03.691 DEBUG 23452 --- [ main] .selectProcessDefinitionsByQueryCriteria : <== Total: 3
其实就是直接从ACT_RE_PROCDEF这个表中将数据查询出来。
如果想要添加查询条件,可以ProcessDefinitionQuery这个类中去查找相关方法。
例如查询key中包含work的流程,可以这样写:
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
.processDefinitionKeyLike("%work%");
List<ProcessDefinition> list = processDefinitionQuery.list();
另外,flowable还提供了分页查询的方法:
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
.processDefinitionKeyLike("%work%");
long count = processDefinitionQuery.count(); //获取总条数
List<ProcessDefinition> processDefinitions = processDefinitionQuery.listPage(0, 1); //从第0条开始,取1条数据
针对查出来的数据,flowable提供了根据id进行修改的api,使用方法如下:
针对已经部署的流程,flowable只允许修改其分类:
String processDefinitionId = "flow_e8096tma:1:eafd8aae-a10b-11ed-a9fb-d41b81b9a72d";
repositoryService.setProcessDefinitionCategory(deploymentId,"办公流程");
因此建议在绘制xml的时候就将相关内容设计好,避免再次修改。
如果想要删除流程,可以调用下面的方法,第二个参数表示是否要级联删除所有相关内容,一般为false,因为我们要保留已经审批的数据做相关查看或者统计。
String processDefinitionId = "flow_e8096tma:1:eafd8aae-a10b-11ed-a9fb-d41b81b9a72d";
repositoryService.deleteDeployment(processDefinitionId,false);
好了,关于流程的增删改查就这些了。

浙公网安备 33010602011771号