flowable各个事件、网关、任务的使用详解
既然网上没有合适的教程,那就力求达到先会用,再理解。
当然各个事件有一些功能是重复的,比如事件和任务都有执行监听器,这个等说到任务的时候就会提一下,然后带过。
今天只看“开始事件”的相关配置
这是若依框架和flowableui官方文档针对“开始事件”做的一个对比截图,还是能一目了然的看清楚两个前端框架实际实现的功能都是差不多的:比如都有ID、名称、表单、执行监听器这些....
一、表单
我们可以看到上面两张图里面都有表单的引用,这个表单的引用是干嘛的?
结合实际:我们正常需要请假的时候,首先是会填一下请假天数、请假事由等等信息。这个表单引用就是对应的我们填写的表单信息的id。flowable自动生成的act_*相关的表中并没有存储表单的数据库表。
所以若依框架的作者是自己建了一个动态拖拽的表单设计器数据库表。
当然只要有这张表就行,能获取到这个表单信息,并不一定非得是动态表单,也可以自己画好页面,然后把代码复制进来,一样的效果。但此时还是先按照已有的进行学习。
首先,我们点击开始节点,然后在右侧表单选择之前设计好的表单。这样在实际发起流程的时候就能查询出来这个表单,并且让用户进行填写。
(其中需要明白的是:用户填的这些参数,在整个流程中都是属于“流程变量”,当然也可以设置一些隐藏的不在表单中展示的流程变量。一般填写好都不会改变,但是下面监听器的演示会提到流程变量的概念,提前知道一下)
二、执行监听器
“监听器”在flowable中主要分成两种,一个是执行监听器、一个是任务监听器。任务主要是像一些审批节点的算是任务,startEvent属于事件,所以在开始事件中只有执行监听器没有任务监听器。
执行监听器为什么存在?主要我们可以动态的去设置一些事情:
动态分配节点的处理人;
流程到哪个节点了,我要动态的去通知一些人,比如发邮件;
处理一些其他的业务等等
执行监听器一般有三个类型:start、take、end
<flowable:executionListener class="com.ruoyi.system.listener.StartEventListener" event="start">
<flowable:executionListener class="com.ruoyi.system.listener.EndEventListener" event="end" />
<flowable:executionListener class="com.ruoyi.system.listener.TakeEventListener" event="take" />
start:开始 end:结束 take:执行过程中(我的理解是触发)
(有人说start和end是用于任务和节点上的,而take是用在连线上的)
但是,使用若依的时候会发现,无论点哪个事件或者连线都只有start和end两种类型。
也很好理解,take和start的作用可以说是基本一致,都是在节点开始或者被触发的时候会调用。所以你如果加入一个take类型也是一样的,但是如果全被start代替会显得更加简单。
执行监听器实现
可以从下图看到监听器有几种实现方式
官方:java类、表达式、委托表达式
若依:java类、表达式、代理表达式、脚本(脚本后续在任务其他节点进行讲解)
前三个一样,只不过多了一个脚本。
我们接下来看看具体怎么使用。
1、Java类实现
在Spring项目中,执行监听器只需要在你创建的类上面实现ExecutionListener即可。如下:
这是我创建的start和end类型的监听器,同时绑定在了开始事件上。里面的参数(name、age)先不用管。
我分给startEvent绑定了两个监听器,也就是提交任务的时候会触发两次。
package com.ruoyi.system.listener;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.impl.el.FixedValue;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Data
public class StartEventListener implements ExecutionListener {
private FixedValue name;
private Expression age;
@Override
public void notify(DelegateExecution execution) {
log.info("execution>>>>>>>>>>>>>>>>>>>>>>:{}", execution.getProcessDefinitionId());
log.info("name>>>>>>>>>>>>>>>>>>>>>>:{}", name.getValue(execution));
log.info("age>>>>>>>>>>>>>>>>>>>>>>:{}", age.getValue(execution));
}
}
package com.ruoyi.system.listener;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Data
public class EndEventListener implements ExecutionListener {
@Override
public void notify(DelegateExecution execution) {
log.info("execution>>>>>>>>>>>>>>>>>>>>>>:{}", execution.getProcessDefinitionId());
}
}
可以看到DelegateExecution里面就包含了流程实例id等其他信息,可以做一些处理。后面讲
等start事件处理完后就条转到了end执行器
上面就是java类方式的执行监听器实现方法,可能大家也注意到了,我的start监听器里面还配置了参数。那么参数具体是做什么用的呢?
下面来看看官方和若依的界面区别
可以看到,就是我触发了这个执行器后,要带进来哪些自定义的参数。主要还是为了实现个性化处理,流程图一般都是固定的,但是我不同的分支带进来不同的参数,我就可以根据参数处理不同的业务。
private FixedValue name;//用于接收字符串 private Expression days;//用于接收表达式
字符串如下:
此时你看 我就可以根据动态传进来的name判断处理不同的逻辑
有人会说了,你都固定写死了张三 那还有什么逻辑可分?
当然不是了,你要知道这个监听器是可以绑定在任意一个节点上的。如下图,就会发现如果两个节点分别都关联了同一个监听器。那么他们一个配置name是张三一个配置name是李四,是不是就不一样了?
表达式如下:
表达式必须是el表达式${param==1},就是跟上面的原理差不多,不同的节点可以传不同的值,我目前发现还是字符串用的多,简单还不需要解析,你看表达式还得单独处理,麻烦!!!
2、表达式
执行监听器-表达式方式处理。
他的xml流程是这样的
<flowable:executionListener expression="${execution.setVariable("days",10)}" event="end" />
由下图可以看出,我在设计图上是用户填完请假表单,会通过一个排他网关(就是哪个X)。他会判断我的表单里面输入的天数是几,如果>3就走上面的流程,如果<3就走下面的流程。
比如:下面是一个正常的流程
我们可以看到具体的实例走向:
但此时如果我在排他网关前面加一个表达式触发器,就可以直接改变这个走向:
也就是开始事件结束后就会触发这个表达式,表达式的内容是${execution.setVariable("days",10)}。为什么这么写,我们待会再说,先看效果。
可以明显看到他走到了另外一个分支上去了,也就是${execution.setVariable("days",10)}这个表达式把流程参数days改成了10。
至于为什么这么写可以看下代码:
我们前面手动添加的监听器都是继承了ExecutionListener.java
但是表达式可以发现,他里面并没有引用java类,那他到底怎么实现的呢?我们可以先看一下这个父类具体有哪些实现类:
那有人会问,为什么这么写呢execution?不妨点进去看一下:
execution就是他的默认参数就代表DelegateExecution。
然后我们再看一下DelegateExecution里面的默认方法有多少,可以看到我们上面表达式就是用的这个方法setVariable(),可以改变流程变量的值。这里面的方法都是可以使用的。
其实有人可能也会发现,表达式监听器也可以带参数,只不过我目前发现并没有多大的作用。它实际的使用可以是这样:
但是这么使用倒不如直接把张三写在上面了!!!可能是我目前还没遇到具体的场景,先记住 后续遇到再说。
3、代理表达式
其实表达式和代理表达式都是在整个流程过程中,动态的去处理一些旁支业务。但是
表达式更倾向于去判断某个值,或者计算某个值从而达到动态的更改流程的分支走向。
代理表达式则是倾向于指定服务运行哪个javabean或者bean.方法。
他的实现主要就是自定义一个类然后实现implements JavaDelegate。但是此时我要写一个更加直观的方式:
其实到这里今天的差不多写完了,但是抬头看了一下标题:
“今天只讲开始事件”
貌似今天的大部分内容并不全是开始事件特有的,也别是执行监听器,任何一个节点都可以配置。这也是我今天的收获。至少知道了怎么使用几种表监听器。其实问了一下朋友,他们说平时用的比较多的就是java类实现方式和表达式这两种。
那么后续如果涉及到的例子中,我也尽量多使用这两种方式进行测试。
希望,对你能有一点点的启发。