1 ReceiveTask(接收任务)
任务到达这个节点之后,一般来说,不需要额外做什么事情,但需要用户手动的触发。
带信封图标的任务,就是一个 ReceiveTask,不同于 UserTask,ReceiveTask 是不需要分配人员的。
绘制流程图,部署,启动
启动流程
1
2
3
4
5
6
7
8
| /**
* 启动流程
*/
@Test
public void startProcessInstanceByKey() {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ReceiveTaskDemo");
log.info(")_(" + "id:{}", processInstance.getId());
}
|
流程启动成功后,会停在 统计今日销售额 节点上,触发,进入 发送报表 节点,再触发,结束流程;
1
2
3
4
5
6
7
8
9
10
11
12
13
| /**
* 接收任务触发
*/
@Test
public void trigger() {
String[] activityIds = new String[]{"sid-8E756DDA-8849-49A4-8755-195EA0F9182D", "sid-BA450F64-6F60-47CB-9CA0-9A59025DEDE5"};
String activityId = activityIds[1];
List<Execution> list = runtimeService.createExecutionQuery().activityId(activityId).list();
for (Execution execution : list) {
runtimeService.trigger(execution.getId());
}
}
|
注意:ReceiveTask 是不会被记录在ACT_RU_TASK
表中的,它默认被记录在ACT_RU_EXECUTION
表和ACT_RU_ACTINST
表中。
2 UserTask(用户任务)
Flowable 中使用最多的一种任务类型,流程走到这个节点时,需要用户手动处理。
2.1 设置单个用户
指定 UserTask 的处理人,有四种方式
1. 指定具体用户
启动流程
1
2
3
4
5
6
7
8
9
10
11
| /**
* 启动流程
* act_ru_task
* act_ru_actinst
* act_ru_execution
*/
@Test
public void startProcessInstanceByKey1() {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("UserTaskDemo");
log.info(")_(" + "id:{},name:{}", processInstance.getId(), processInstance.getName());
}
|
流程启动成功后,会自动进入用户审批这个节点,需要用户处理的 UserTask 都保存在ACT_RU_TASK
表中
查询某一个用户需要处理的 Task
1
2
3
4
5
6
7
8
9
10
11
| /**
* 查询某一个用户需要处理的任务
* act_ru_task
*/
@Test
public void queryTaskByAssignee() {
List<Task> list = taskService.createTaskQuery().taskAssignee("yueyazhui").list();
for (Task task : list) {
log.info(")_(" + "name:{},assignee:{}", task.getName(), task.getAssignee());
}
}
|
查询到用户需要处理的任务后,有两种处理思路
- 委派给其他人处理
- 自己处理
1.1 委派给其他人处理
1
2
3
4
5
6
7
8
9
10
11
12
13
| /**
* 将 yueyazhui 需要处理的任务委派给 zhangyanpeng 去处理
* 表:ACT_RU_TASK
* 字段:ASSIGNEE_
*/
@Test
public void setAssignee() {
List<Task> list = taskService.createTaskQuery().taskAssignee("yueyazhui").list();
for (Task task : list) {
// 为某一个 Task 设置处理人
taskService.setAssignee(task.getId(), "zhangyanpeng");
}
}
|
1.2 自己处理
1
2
3
4
5
6
7
8
9
10
| /**
* 自己处理
*/
@Test
public void complete() {
List<Task> list = taskService.createTaskQuery().taskAssignee("yueyazhui").list();
for (Task task : list) {
taskService.complete(task.getId());
}
}
|
2. 通过变量来设置
在设置任务的处理人时,使用变量,${xxx}
XML 内容
1
2
3
4
5
6
7
8
9
10
11
12
| <process id="UserTaskDemo" name="UserTaskDemo" isExecutable="true">
<documentation>UserTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<userTask id="sid-A8A30666-E378-4A28-96AD-E770166891FF" name="用户审批" flowable:assignee="${handler}" flowable:formFieldValidation="true">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<sequenceFlow id="sid-0EB3CCF3-ECB6-492D-A7A7-B0D890A9C00B" sourceRef="startEvent1" targetRef="sid-A8A30666-E378-4A28-96AD-E770166891FF"></sequenceFlow>
<endEvent id="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></endEvent>
<sequenceFlow id="sid-1CC2FA64-563D-4867-8C7B-6FA3DA6A5A79" sourceRef="sid-A8A30666-E378-4A28-96AD-E770166891FF" targetRef="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></sequenceFlow>
</process>
|
启动流程并指定任务的处理人
1
2
3
4
5
6
7
8
9
10
11
12
13
| /**
* 启动流程并指定任务的处理人
* act_ru_task
* act_ru_actinst
* act_ru_execution
*/
@Test
public void startProcessInstanceByKey2() {
Map<String, Object> map = new HashMap<>();
map.put("manager", "yueyazhui");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("UserTaskDemo", map);
log.info(")_(" + "id:{},name:{}", processInstance.getId(), processInstance.getName());
}
|
启动成功后,在ACT_RU_TASK
表中,就可以看到任务的处理人已经是 yueyazhui 了
3. 通过监听器来设置
利用监听器,在一个任务创建的时候,为任务设置处理人
XML 内容
1
2
3
4
5
6
7
8
9
10
11
12
| <process id="UserTaskDemo" name="UserTaskDemo" isExecutable="true">
<documentation>UserTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<userTask id="sid-A8A30666-E378-4A28-96AD-E770166891FF" name="用户审批" flowable:formFieldValidation="true">
<extensionElements>
<flowable:taskListener event="create" class="top.yueyazhui.flowable_process.listener.MyTaskListener"></flowable:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="sid-0EB3CCF3-ECB6-492D-A7A7-B0D890A9C00B" sourceRef="startEvent1" targetRef="sid-A8A30666-E378-4A28-96AD-E770166891FF"></sequenceFlow>
<endEvent id="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></endEvent>
<sequenceFlow id="sid-1CC2FA64-563D-4867-8C7B-6FA3DA6A5A79" sourceRef="sid-A8A30666-E378-4A28-96AD-E770166891FF" targetRef="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></sequenceFlow>
</process>
|
对应的监听器代码
1
2
3
4
5
6
7
8
| public class MyTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
// 设置任务的处理人
delegateTask.setAssignee("yueyazhui");
}
}
|
4. 设置为流程的发起人
在开始节点上,设置流程的发起人
给 UserTask 设置处理人时,设置变量
流程启动并指定流程的发起人
1
2
3
4
5
6
7
8
9
10
| /**
* 启动流程并设置流程的发起人
*/
@Test
public void startProcessInstanceByKey3() {
// 设置流程的发起人
Authentication.setAuthenticatedUserId("yueyazhui");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("UserTaskDemo");
log.info(")_(" + "id:{},name:{}", processInstance.getId(), processInstance.getName());
}
|
或
1
2
3
4
5
6
7
8
9
10
11
12
| @Autowired
IdentityService identityService;
/**
* 启动流程并设置流程的发起人
*/
@Test
public void startProcessInstanceByKey4() {
identityService.setAuthenticatedUserId("yueyazhui");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("UserTaskDemo");
log.info(")_(" + "id:{},name:{}", processInstance.getId(), processInstance.getName());
}
|
2.2 设置多个用户
1. 直接指定
直接指定多个候选用户
XML 内容
1
2
3
4
5
6
7
8
| <process id="UserTaskDemo" name="UserTaskDemo" isExecutable="true">
<documentation>UserTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<userTask id="sid-A8A30666-E378-4A28-96AD-E770166891FF" name="用户审批" flowable:candidateUsers="yueyazhui,zhangyanpeng" flowable:formFieldValidation="true"></userTask>
<sequenceFlow id="sid-0EB3CCF3-ECB6-492D-A7A7-B0D890A9C00B" sourceRef="startEvent1" targetRef="sid-A8A30666-E378-4A28-96AD-E770166891FF"></sequenceFlow>
<endEvent id="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></endEvent>
<sequenceFlow id="sid-1CC2FA64-563D-4867-8C7B-6FA3DA6A5A79" sourceRef="sid-A8A30666-E378-4A28-96AD-E770166891FF" targetRef="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></sequenceFlow>
</process>
|
flowable:candidateUsers="yueyazhui,zhangyanpeng"
就是设置流程可以由多个用户来处理,多个用户之间使用,
隔开
部署并启动流程
这时查询某一个用户需要处理的任务,就不能使用之前的方案,因为当一个 UserTask 有多个用户可以处理时,那么在ACT_RU_TASK
这个表中,是无法完全记录这个 Task 的处理人的,所以此时该表中的ASSIGNEE_
字段就为 NULL
根据用户名去查询该用户能够处理的任务
1
2
3
4
5
6
7
8
9
10
11
12
13
| /**
* 根据候选用户查询任务
* ACT_RU_TASK
* ACT_RU_IDENTITYLINK
* SQL:SELECT RES.* from ACT_RU_TASK RES WHERE RES.ASSIGNEE_ is null and exists(select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TYPE_ = 'candidate' and LINK.TASK_ID_ = RES.ID_ and ( LINK.USER_ID_ = ? ) ) order by RES.ID_ asc
*/
@Test
public void queryTaskByCandidateUser() {
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("yueyazhui").list();
for (Task task : tasks) {
log.info(")_(" + "name:{}", task.getName());
}
}
|
已知流程信息,查询流程的参与人
1
2
3
4
5
6
7
8
9
10
11
12
13
| /**
* 根据流程 ID 查询流程的参与者
* ACT_RU_IDENTITYLINK
*/
@Test
public void queryProcessInstanceIdentityLinks() {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().singleResult();
// 根据流程 ID 查询流程的参与者
List<IdentityLink> links = runtimeService.getIdentityLinksForProcessInstance(processInstance.getId());
for (IdentityLink link : links) {
log.info(")_(" + "流程参与者:{}", link.getUserId());
}
}
|
从以上两个查询中可以看出,ACT_RU_IDENTITYLINK
表的功能
任务认领:
1
2
3
4
5
6
7
8
9
10
11
12
| /**
* 认领任务
* 表:ACT_RU_TASK
* 字段:ASSIGNEE_
*/
@Test
public void claimTask() {
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("yueyazhui").list();
for (Task task : tasks) {
taskService.claim(task.getId(), "yueyazhui");
}
}
|
2. 使用变量或监听器
变量
启动流程并指定候选人
1
2
3
4
5
6
7
8
9
| /**
* 启动流程并指定候选人
*/
@Test
public void startProcessInstanceByKey5() {
Map<String, Object> map = new HashMap<>();
map.put("candidateUsers", "yueyazhui,zhangyanpeng");
runtimeService.startProcessInstanceByKey("UserTaskDemo", map);
}
|
监听器
1
2
3
4
5
6
7
8
9
| public class MyTaskCandidateUsersListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
// 设置任务的候选人
delegateTask.addCandidateUser("yueyazhui");
delegateTask.addCandidateUser("zhangyanpeng");
}
}
|
3. 任务回退
已经认领的任务,退回去
1
2
3
4
5
6
7
8
9
10
11
12
13
| /**
* 任务回退
* 表:ACT_RU_TASK
* 字段:ASSIGNEE_
*/
@Test
public void setAssignee2() {
List<Task> tasks = taskService.createTaskQuery().taskAssignee("yueyazhui").list();
for (Task task : tasks) {
// 设置任务的处理人为 null,就表示任务回退
taskService.setAssignee(task.getId(), null);
}
}
|
4. 任务候选人的添加与删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| /**
* 任务增加候选人
* ACT_RU_IDENTITYLINK
*/
@Test
public void addCandidateUser() {
Task task = taskService.createTaskQuery().singleResult();
taskService.addCandidateUser(task.getId(), "yueya");
taskService.addCandidateUser(task.getId(), "yue");
}
/**
* 任务删除候选人
* ACT_RU_IDENTITYLINK
*/
@Test
public void deleteCandidateUser() {
Task task = taskService.createTaskQuery().singleResult();
taskService.deleteCandidateUser(task.getId(),"yueya");
taskService.deleteCandidateUser(task.getId(),"yue");
}
|
2.3 按照角色分配任务处理人
准备数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| /**
* 创建 yue 和 yueyazhui 两个用户
* 创建 manager 的用户组
* 设置 yue 和 yueyazhui 都属于 manager
*/
@Test
public void createUserAndGroup() {
UserEntityImpl user1 = new UserEntityImpl();
user1.setRevision(0);
user1.setId("yue");
user1.setPassword("123");
user1.setDisplayName("月");
user1.setEmail("yue@yue.com");
identityService.saveUser(user1);
UserEntityImpl user2 = new UserEntityImpl();
user2.setRevision(0);
user2.setId("yueyazhui");
user2.setPassword("123");
user2.setDisplayName("月牙坠");
user2.setEmail("yueyazhui@yueyazhui.com");
identityService.saveUser(user2);
GroupEntityImpl group = new GroupEntityImpl();
group.setRevision(0);
group.setId("manager");
group.setName("经理");
identityService.saveGroup(group);
identityService.createMembership("yue", "manager");
identityService.createMembership("yueyazhui", "manager");
}
|
直接指定名称
XML 内容
1
2
3
4
5
6
7
8
| <process id="UserTaskDemo" name="UserTaskDemo" isExecutable="true">
<documentation>UserTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<userTask id="sid-A8A30666-E378-4A28-96AD-E770166891FF" name="用户审批" flowable:candidateGroups="manager" flowable:formFieldValidation="true"></userTask>
<sequenceFlow id="sid-0EB3CCF3-ECB6-492D-A7A7-B0D890A9C00B" sourceRef="startEvent1" targetRef="sid-A8A30666-E378-4A28-96AD-E770166891FF"></sequenceFlow>
<endEvent id="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></endEvent>
<sequenceFlow id="sid-1CC2FA64-563D-4867-8C7B-6FA3DA6A5A79" sourceRef="sid-A8A30666-E378-4A28-96AD-E770166891FF" targetRef="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></sequenceFlow>
</process>
|
flowable:candidateGroups="manager"
就是用来指定候选组的
根据候选用户查询任务
1
2
3
4
5
6
7
8
9
10
11
12
| /**
* 根据候选人查询任务(可能 yueyazhui 就是候选人,也可能 yueyazhui 属于某一个或某多个用户组,那么此时就需要先查询到 yueyazhui 所属的用户组,然后再根据用户组去查询对应的任务)
* 1. 查询 yueyazhui 所属的用户组
* SELECT RES.* from ACT_ID_GROUP RES WHERE exists(select 1 from ACT_ID_MEMBERSHIP M where M.GROUP_ID_ = RES.ID_ and M.USER_ID_ = ?) order by RES.ID_ asc
* 2. 根据用户组去查询对应的任务
* SELECT RES.* from ACT_RU_TASK RES WHERE RES.ASSIGNEE_ is null and exists(select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TYPE_ = 'candidate' and LINK.TASK_ID_ = RES.ID_ and ( LINK.USER_ID_ = ? or ( LINK.GROUP_ID_ IN ( ? ) ) ) ) order by RES.ID_ asc
*/
@Test
public void queryTaskByCandidateUser2() {
Task task = taskService.createTaskQuery().taskCandidateUser("yueyazhui").singleResult();
log.info(")_(" + "name:{}", task.getName());
}
|
根据候选组查询任务
1
2
3
4
5
6
7
8
9
| /**
* 根据候选用户组查询任务
* SELECT RES.* from ACT_RU_TASK RES WHERE RES.ASSIGNEE_ is null and exists(select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TYPE_ = 'candidate' and LINK.TASK_ID_ = RES.ID_ and ( ( LINK.GROUP_ID_ IN ( ? ) ) ) ) order by RES.ID_ asc
*/
@Test
public void queryTaskByCandidateGroup() {
Task task = taskService.createTaskQuery().taskCandidateGroup("manager").singleResult();
log.info(")_(" + "name:{}", task.getName());
}
|
通过变量来指定
XML 内容
1
2
3
4
5
6
7
8
| <process id="UserTaskDemo" name="UserTaskDemo" isExecutable="true">
<documentation>UserTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<userTask id="sid-A8A30666-E378-4A28-96AD-E770166891FF" name="用户审批" flowable:candidateGroups="${candidateGroups}" flowable:formFieldValidation="true"></userTask>
<sequenceFlow id="sid-0EB3CCF3-ECB6-492D-A7A7-B0D890A9C00B" sourceRef="startEvent1" targetRef="sid-A8A30666-E378-4A28-96AD-E770166891FF"></sequenceFlow>
<endEvent id="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></endEvent>
<sequenceFlow id="sid-1CC2FA64-563D-4867-8C7B-6FA3DA6A5A79" sourceRef="sid-A8A30666-E378-4A28-96AD-E770166891FF" targetRef="sid-188D3FA6-23F8-436C-9F97-7D81433C84E4"></sequenceFlow>
</process>
|
flowable:candidateGroups="${candidateGroups}"
就是用来设置候选组变量的
启动流程并设置用户组变量值
1
2
3
4
5
6
7
8
9
10
| /**
* 启动流程并设置用户组变量值
*/
@Test
public void startProcessInstanceByKey6() {
Map<String, Object> map = new HashMap<>();
map.put("candidateGroups", "manager");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("UserTaskDemo", map);
log.info(")_(" + "id:{},name:{}", processInstance.getId(), processInstance.getName());
}
|
3 ServiceTask(服务任务)
服务任务:系统自动执行完成
3.1 监听类
定义监听类
1
2
3
4
5
6
7
8
9
10
| /**
* 自定义监听类,ServiceTask 执行到这里时,会自动执行该类中的 execute 方法
*/
public class MyServiceTask01 implements JavaDelegate {
@Override
public void execute(DelegateExecution delegateExecution) {
System.out.println("--------- MyServiceTask ---------");
}
}
|
绘制流程图时,为 ServiceTask 配置监听类
XML 内容
1
2
3
4
5
6
7
8
| <process id="ServiceTaskDemo" name="ServiceTaskDemo" isExecutable="true">
<documentation>ServiceTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<sequenceFlow id="sid-3A355604-DF55-4C5D-8249-4EFAE553DCA2" sourceRef="startEvent1" targetRef="sid-15963CD2-01AC-40C6-A254-506BAF753CA6"></sequenceFlow>
<endEvent id="sid-EE02C1CB-A1C2-40F2-87F5-6B03279FB102"></endEvent>
<sequenceFlow id="sid-3A7C3AE6-F12A-4184-87C1-1D2F9DD95744" sourceRef="sid-15963CD2-01AC-40C6-A254-506BAF753CA6" targetRef="sid-EE02C1CB-A1C2-40F2-87F5-6B03279FB102"></sequenceFlow>
<serviceTask id="sid-15963CD2-01AC-40C6-A254-506BAF753CA6" flowable:class="top.yueyazhui.flowable_process.listener.MyServiceTask01"></serviceTask>
</process>
|
关键指令:flowable:class="top.yueyazhui.flowable_process.listener.MyServiceTask01"
流程测试
1
2
3
4
5
6
7
8
9
10
11
12
| @Slf4j
@SpringBootTest
public class FlowableProcessServiceTaskTest {
@Autowired
RuntimeService runtimeService;
@Test
public void startProcessInstanceByKey() {
runtimeService.startProcessInstanceByKey("ServiceTaskDemo");
}
}
|
ServiceTask 在执行的过程中,任务的记录是不会保存到ACT_RU_TASK
表中的。
设置字段
XML 内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <process id="ServiceTaskDemo" name="ServiceTaskDemo" isExecutable="true">
<documentation>ServiceTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<sequenceFlow id="sid-3A355604-DF55-4C5D-8249-4EFAE553DCA2" sourceRef="startEvent1" targetRef="sid-15963CD2-01AC-40C6-A254-506BAF753CA6"></sequenceFlow>
<endEvent id="sid-EE02C1CB-A1C2-40F2-87F5-6B03279FB102"></endEvent>
<sequenceFlow id="sid-3A7C3AE6-F12A-4184-87C1-1D2F9DD95744" sourceRef="sid-15963CD2-01AC-40C6-A254-506BAF753CA6" targetRef="sid-EE02C1CB-A1C2-40F2-87F5-6B03279FB102"></sequenceFlow>
<serviceTask id="sid-15963CD2-01AC-40C6-A254-506BAF753CA6" flowable:class="top.yueyazhui.flowable_process.listener.MyServiceTask01">
<extensionElements>
<flowable:field name="username">
<flowable:string><![CDATA[yueyazhui]]></flowable:string>
</flowable:field>
</extensionElements>
</serviceTask>
</process>
|
接下来,在监听类中,就可以获取到 username 的值了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| /**
* 自定义监听类,ServiceTask 执行到这里时,会自动执行该类中的 execute 方法
*/
public class MyServiceTask01 implements JavaDelegate {
Expression username;
@Override
public void execute(DelegateExecution delegateExecution) {
// 获取 username 的值
System.out.println("username.getExpressionText() = " + username.getExpressionText());
System.out.println("username.getValue(delegateExecution) = " + username.getValue(delegateExecution));
System.out.println("--------- MyServiceTask ---------");
}
}
|
3.2 委托表达式
委托表达式类似于监听类,但是,可以注册到 Spring 容器中;绘制流程图时,配置 Bean 的名称即可
监听类
1
2
3
4
5
6
7
8
| @Component
public class MyServiceTask02 implements JavaDelegate {
@Override
public void execute(DelegateExecution delegateExecution) {
System.out.println("--------- MyServiceTask ---------");
}
}
|
XML 内容
1
2
3
4
5
6
7
8
| <process id="ServiceTaskDemo" name="ServiceTaskDemo" isExecutable="true">
<documentation>ServiceTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<sequenceFlow id="sid-3A355604-DF55-4C5D-8249-4EFAE553DCA2" sourceRef="startEvent1" targetRef="sid-15963CD2-01AC-40C6-A254-506BAF753CA6"></sequenceFlow>
<endEvent id="sid-EE02C1CB-A1C2-40F2-87F5-6B03279FB102"></endEvent>
<sequenceFlow id="sid-3A7C3AE6-F12A-4184-87C1-1D2F9DD95744" sourceRef="sid-15963CD2-01AC-40C6-A254-506BAF753CA6" targetRef="sid-EE02C1CB-A1C2-40F2-87F5-6B03279FB102"></sequenceFlow>
<serviceTask id="sid-15963CD2-01AC-40C6-A254-506BAF753CA6" flowable:delegateExpression="${myServiceTask02}"></serviceTask>
</process>
|
flowable:delegateExpression="${myServiceTask02}"
描述了 ServiceTask 对应的 Bean
3.3 表达式
前面两种,无论是直接配置类的全路径,还是配置 Bean 的名称,都离不开JavaDelegate
接口。
其实一个普通的 Bean,也可以配置为 ServiceTask 的执行类。
1
2
3
4
5
6
7
| @Component
public class MyServiceTask03 {
public void hello() {
System.out.println("--------- MyServiceTask ---------");
}
}
|
在表达式中,指定要执行的 Bean 以及对应的方法。
XML 内容
1
2
3
4
5
6
7
8
| <process id="ServiceTaskDemo" name="ServiceTaskDemo" isExecutable="true">
<documentation>ServiceTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<sequenceFlow id="sid-3A355604-DF55-4C5D-8249-4EFAE553DCA2" sourceRef="startEvent1" targetRef="sid-15963CD2-01AC-40C6-A254-506BAF753CA6"></sequenceFlow>
<endEvent id="sid-EE02C1CB-A1C2-40F2-87F5-6B03279FB102"></endEvent>
<sequenceFlow id="sid-3A7C3AE6-F12A-4184-87C1-1D2F9DD95744" sourceRef="sid-15963CD2-01AC-40C6-A254-506BAF753CA6" targetRef="sid-EE02C1CB-A1C2-40F2-87F5-6B03279FB102"></sequenceFlow>
<serviceTask id="sid-15963CD2-01AC-40C6-A254-506BAF753CA6" flowable:expression="${myServiceTask03.hello()}"></serviceTask>
</process>
|
注意,表达式不可以像监听类似的去设置字段。
4 ScriptTask(脚本任务)
脚本任务和服务任务类似,也是系统自动执行完成的。不同的是,脚本任务的逻辑,是通过一些非 Java 的脚本语言来实现的。
4.1 JavaScript
绘制流程图
- 第一行执行一个加法运算。
- 第二行保存一个流程变量。
XML 内容
1
2
3
4
5
6
7
8
9
10
11
| <process id="ScriptTaskDemo" name="ScriptTaskDemo" isExecutable="true">
<documentation>ScriptTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<sequenceFlow id="sid-781E4B49-2BF6-4E42-B556-8405F970603D" sourceRef="startEvent1" targetRef="sid-F3C21531-8080-421E-8A5D-A92102B8B302"></sequenceFlow>
<endEvent id="sid-1917820C-9059-4AF1-A5B9-A57AEB08DF99"></endEvent>
<sequenceFlow id="sid-169C8661-BCA4-4D67-8F14-D45239E6B3CC" sourceRef="sid-F3C21531-8080-421E-8A5D-A92102B8B302" targetRef="sid-1917820C-9059-4AF1-A5B9-A57AEB08DF99"></sequenceFlow>
<scriptTask id="sid-F3C21531-8080-421E-8A5D-A92102B8B302" scriptFormat="JavaScript" flowable:autoStoreVariables="false">
<script><![CDATA[var sum = a + b;
execution.setVariable("sum", sum);]]></script>
</scriptTask>
</process>
|
注意:不能使用 let 关键字,可以使用 var 关键字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| @Slf4j
@SpringBootTest
public class FlowableProcessScriptTaskTest {
@Autowired
RuntimeService runtimeService;
/**
* act_hi_varinst
*/
@Test
public void startProcessInstanceByKey1() {
Map<String, Object> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
runtimeService.startProcessInstanceByKey("ScriptTaskDemo", map);
}
}
|
4.2 Groovy
Groovy 是基于 JVM 的编程语言
添加依赖
1
2
3
4
5
| <dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>3.0.13</version>
</dependency>
|
XML 内容
1
2
3
4
5
6
7
8
9
10
| <process id="ScriptTaskDemo" name="ScriptTaskDemo" isExecutable="true">
<documentation>ScriptTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<sequenceFlow id="sid-781E4B49-2BF6-4E42-B556-8405F970603D" sourceRef="startEvent1" targetRef="sid-F3C21531-8080-421E-8A5D-A92102B8B302"></sequenceFlow>
<endEvent id="sid-1917820C-9059-4AF1-A5B9-A57AEB08DF99"></endEvent>
<sequenceFlow id="sid-169C8661-BCA4-4D67-8F14-D45239E6B3CC" sourceRef="sid-F3C21531-8080-421E-8A5D-A92102B8B302" targetRef="sid-1917820C-9059-4AF1-A5B9-A57AEB08DF99"></sequenceFlow>
<scriptTask id="sid-F3C21531-8080-421E-8A5D-A92102B8B302" scriptFormat="Groovy" flowable:autoStoreVariables="false">
<script><![CDATA[println("Hello Groovy");]]></script>
</scriptTask>
</process>
|
1
2
3
4
| @Test
public void startProcessInstanceByKey2() {
runtimeService.startProcessInstanceByKey("ScriptTaskDemo");
}
|
4.3 Juel
Juel(Java Unified Expression Language)
表达式 ${xxx} 就是一个 Juel
这个脚本表示执行 Spring 容器中一个名为 myServiceTask03 的 Bean 的 hello 方法
XML 内容
1
2
3
4
5
6
7
8
9
10
| <process id="ScriptTaskDemo" name="ScriptTaskDemo" isExecutable="true">
<documentation>ScriptTaskDemo</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
<sequenceFlow id="sid-781E4B49-2BF6-4E42-B556-8405F970603D" sourceRef="startEvent1" targetRef="sid-F3C21531-8080-421E-8A5D-A92102B8B302"></sequenceFlow>
<endEvent id="sid-1917820C-9059-4AF1-A5B9-A57AEB08DF99"></endEvent>
<sequenceFlow id="sid-169C8661-BCA4-4D67-8F14-D45239E6B3CC" sourceRef="sid-F3C21531-8080-421E-8A5D-A92102B8B302" targetRef="sid-1917820C-9059-4AF1-A5B9-A57AEB08DF99"></sequenceFlow>
<scriptTask id="sid-F3C21531-8080-421E-8A5D-A92102B8B302" scriptFormat="juel" flowable:autoStoreVariables="false">
<script><![CDATA[${myServiceTask03.hello()}]]></script>
</scriptTask>
</process>
|
1
2
3
4
| @Test
public void startProcessInstanceByKey2() {
runtimeService.startProcessInstanceByKey("ScriptTaskDemo");
}
|