Activiti7 多种任务类型【十八】

Activiti 7系列文章目录

文章代码下载

Activiti7 工作流设计器【一】
Activiti7 创建表【二】
Activiti7 表结构介绍 【三】
Activiti7 设计器创建流程 【四】
Activiti7 部署流程【五】
Activiti7 查询流程【六】
Activiti7 删除流程【七】
Activiti7 生成SVG图片【八】
Activiti7 发起任务【九】
Activiti7 查询任务执行流程图【十】
Activiti7 完成任务【十一】
Activiti7 历史数据【十二】
Activiti7 任务办理人、委派、转办、持有人、候选人、候选人组、审批意见【十三】
Activiti7 监听器【十四】
Activiti7 流程变量【十五】
Activiti7 网关Gateway【十六】
Activiti7 整合SpringBoot【十七】
Activiti7 多种任务类型【十八】
Activiti7 子流程【十九】
Activiti7 流程回退、流程拒绝【二十】

流程文件中

在ServiceTask上设置Expression=${myTaskService.hasRole(execution)},其中myTaskService是Bean中的Id值,【方法参数名必须是execution不能修改】。

在ServiceTask执行一些逻辑,计算出来一些值,然后将这些值设置为变量,然后供后面的流程来使用。
image.png
image.png
image.png

自定义Task类

@Service如果没有指定名字,默认是类名的首字母小写,即myTaskService。

package com.boot.service;

import org.activiti.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Service;

@Service
public class MyServiceTask {
    public void hasRole(DelegateExecution delegateExecution){
        Integer day = Integer.parseInt(delegateExecution.getVariable("day").toString());
        if(day > 3){
            delegateExecution.setVariable("type",1);
        }else{
            delegateExecution.setVariable("type",0);
        }
    }
}

测试

//发起流程
@Test
public void test05(){
    Map<String,Object> variables = new HashMap<>();
    variables.put("day",10);

    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("MyServiceTask",variables);
    System.out.println("processInstance.getId() = " + processInstance.getId());
    System.out.println("processInstance.getName() = " + processInstance.getName());
    System.out.println("processInstance.getDescription() = " + processInstance.getDescription());
}

结果

当我们发起流程,直接走到【CEO审批】这里不会走到【经理处理】实际开发中需要注意!
image.png

流程定义文件

MyServiceTask.bpmn20.xml

image.png
image.png

  • Script Format:脚本类型,groovy
  • Script:脚本代码
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
  <process id="MyScriptTask" name="MyScriptTask" isExecutable="true">
    <documentation>MyScriptTask</documentation>
    <startEvent id="startEvent1" name="StartEvent
"></startEvent>
    <endEvent id="sid-B1B0E762-1A1E-4501-805C-98F1D7D7F550" name="EndEvent"></endEvent>
    <scriptTask id="sid-B0210B6B-4040-41CB-A715-210EA0C18D9A" name="Script Task" scriptFormat="groovy" activiti:autoStoreVariables="false">
      <script><![CDATA[sum = 0
for (i in inputArray) {       
   sum += i 
}     
execution.setVariable("result", sum);]]></script>
    </scriptTask>
    <sequenceFlow id="sid-A51FCF6D-D18C-4544-94EE-E10DF92BCD8E" sourceRef="startEvent1" targetRef="sid-B0210B6B-4040-41CB-A715-210EA0C18D9A"></sequenceFlow>
    <sequenceFlow id="sid-72B7EA1A-E6B2-4AB3-BA96-D73BC4F7B4A1" sourceRef="sid-B0210B6B-4040-41CB-A715-210EA0C18D9A" targetRef="sid-B1B0E762-1A1E-4501-805C-98F1D7D7F550"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_MyScriptTask">
    <bpmndi:BPMNPlane bpmnElement="MyScriptTask" id="BPMNPlane_MyScriptTask">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="90.0" y="174.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-B1B0E762-1A1E-4501-805C-98F1D7D7F550" id="BPMNShape_sid-B1B0E762-1A1E-4501-805C-98F1D7D7F550">
        <omgdc:Bounds height="28.0" width="28.0" x="435.0" y="175.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-B0210B6B-4040-41CB-A715-210EA0C18D9A" id="BPMNShape_sid-B0210B6B-4040-41CB-A715-210EA0C18D9A">
        <omgdc:Bounds height="80.0" width="100.0" x="225.0" y="149.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-A51FCF6D-D18C-4544-94EE-E10DF92BCD8E" id="BPMNEdge_sid-A51FCF6D-D18C-4544-94EE-E10DF92BCD8E">
        <omgdi:waypoint x="120.0" y="189.0"></omgdi:waypoint>
        <omgdi:waypoint x="225.0" y="189.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-72B7EA1A-E6B2-4AB3-BA96-D73BC4F7B4A1" id="BPMNEdge_sid-72B7EA1A-E6B2-4AB3-BA96-D73BC4F7B4A1">
        <omgdi:waypoint x="325.0" y="189.0"></omgdi:waypoint>
        <omgdi:waypoint x="435.0" y="189.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
<dependency>
	<groupId>org.codehaus.groovy</groupId>
	<artifactId>groovy-all</artifactId>
	<version>3.0.9</version>
	<type>pom</type>
</dependency>

@Test
void testStartAndComplete() {
    Map<String, Object> map = new HashMap<>();
    map.put("inputArray", Arrays.asList(1, 2));
    runtimeService.startProcessInstanceByKey("MyScriptTask", map);
}

脚本任务是自动执行的,不需要调用 taskService.complete();
image.png

MyScriptTask.bpmn20.xml

ReceiveTask 称之为接收任务、等待任务等。当执行流进入ReceiveTask时会先执行执行监听器,然后整个执行流进入wait等待状态,而且在act_ru_task中不没有当前正在进行中的任务,当执行流执行trigger()方法时才会触发正在睡眠的ReceiveTask,进入下一个节点。
image.png
image.png

  <process id="MyReceiveTask" name="MyReceiveTask" isExecutable="true">
    <documentation>MyReceiveTask</documentation>
    <startEvent id="startEvent1"></startEvent>
    <userTask id="sid-CCC8DD61-9250-49F5-B660-1B5792A66DFA"></userTask>
    <userTask id="sid-D8B690BF-209B-4984-AF12-1354C2741106"></userTask>
    <endEvent id="sid-EB7C8C79-2CB0-43D2-84BE-58F4C60E55EE"></endEvent>
    <receiveTask id="sid-9DBEE1C0-74E7-40B2-82CE-540AFF901F9B">
      <extensionElements>
        <activiti:executionListener event="start" class="com.boot.service.ReceiveTaskDelegate"></activiti:executionListener>
        <activiti:executionListener event="start" class="com.boot.service.ReceiveTaskDelegate"></activiti:executionListener>
      </extensionElements>
    </receiveTask>
    <sequenceFlow id="sid-C9B5E8CA-269B-4C12-900E-0A6A45300B97" sourceRef="startEvent1" targetRef="sid-CCC8DD61-9250-49F5-B660-1B5792A66DFA"></sequenceFlow>
    <sequenceFlow id="sid-6C92D43F-0A33-4EF4-8AFB-A668B99918F8" sourceRef="sid-CCC8DD61-9250-49F5-B660-1B5792A66DFA" targetRef="sid-9DBEE1C0-74E7-40B2-82CE-540AFF901F9B"></sequenceFlow>
    <sequenceFlow id="sid-B6C946C0-0373-4FDD-847C-E47DE0A63FC9" sourceRef="sid-9DBEE1C0-74E7-40B2-82CE-540AFF901F9B" targetRef="sid-D8B690BF-209B-4984-AF12-1354C2741106"></sequenceFlow>
    <sequenceFlow id="sid-5856EDD0-4A4D-4CC4-8D9C-54C1940D75CC" sourceRef="sid-D8B690BF-209B-4984-AF12-1354C2741106" targetRef="sid-EB7C8C79-2CB0-43D2-84BE-58F4C60E55EE"></sequenceFlow>
  </process>
package com.boot.service;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;

import java.util.Map;

public class ReceiveTaskDelegate implements ExecutionListener {
    @Override
    public void notify(DelegateExecution execution) {
        Map<String, Object> variables = execution.getVariables();
        System.out.println(execution.getEventName() + "-" + execution.getCurrentFlowElement().getId());
    }
}


启动任务

//发起流程
@Test
public void test05(){
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("MyReceiveTask");
    System.out.println("processInstance.getId() = " + processInstance.getId());
    System.out.println("processInstance.getName() = " + processInstance.getName());
    System.out.println("processInstance.getDescription() = " + processInstance.getDescription());
}

启动流程实例,UserTask1进入当前任务。

完成UserTask

@Test
void testCompleteUserTask1() {
    List<Task> list = taskService.createTaskQuery().list();
    for (Task task : list) {
        System.out.println("task.getId() = " + task.getId());
        System.out.println("task.getName() = " + task.getName());
        System.out.println("task.getAssignee() = " + task.getAssignee());
        taskService.complete(task.getId());
    }
}

当UserTask1完成后进入ReceiveTask,执行了ReceiveTask对应的代理ReceiveTaskDelegate,
act_ru_task中竟然没有数据,而act_ru_exectuion中当然活动竟然是receiveTask。
image.png
下面查询任务也是没有任何内容输出的

@Test
void testCompleteUserTask1() {
    List<Task> list = taskService.createTaskQuery().list();
    for (Task task : list) {
        System.out.println("task.getId() = " + task.getId());
        System.out.println("task.getName() = " + task.getName());
        System.out.println("task.getAssignee() = " + task.getAssignee());
    }
}

act_ru_execution表中有数据
image.png
查询act_ru_execution表

@Test
public void testExecution(){
    List<Execution> executions = runtimeService.createExecutionQuery().list();
    for (Execution execution : executions) {
        System.out.println("execution.getId() = " + execution.getId());
        System.out.println("execution.getName() = " + execution.getName());
        System.out.println("execution.getProcessInstanceId() = " + execution.getProcessInstanceId());
    }
}

image.png

trigger

@Test
void testTriggeReceiveTask() {
    List<Execution> executions = runtimeService.createExecutionQuery().list();
    for (Execution execution : executions) {
        runtimeService.trigger(execution.getId());
    }
}

ReceiveTask就像多线程中的wait(), 而trigger()就像多线程中的notify()了。
act_ru_task中有数据了
image.png
查看当前流程图已经到下个任务了。
image.png

流程定义文件

MyReceiveTask.bpmn20.xml

方法之间可以相互调用,同理,流程定义之间也可以相关调用,达到流程定义复用的目的。

流程定义Process1

image.png

流程定义Process2

Called Element: 调用其它流程,值为其它流程Id:Process1
image.png

部署流程

image.png

发起流程:Process2

这里是发起流程Process2

//发起流程
@Test
public void test05(){
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process2");
    System.out.println("processInstance.getId() = " + processInstance.getId());
    System.out.println("processInstance.getName() = " + processInstance.getName());
    System.out.println("processInstance.getDescription() = " + processInstance.getDescription());
}

发起流程任务Task还是在Process2流程上
image.png

image.png

处理任务

处理完【发起申请】会触发Process1的【经理审批】

@Test
public void testApplyTask() {
    Task task = taskService
            .createTaskQuery()
            .singleResult();
    taskService.setAssignee(task.getId(), "zhangsan");
    taskService.complete(task.getId());
}

目前已经调用Process1的流程了:走到了【经理审批】
image.png
image.png

执行完任务

【经理审批】完继续走到Process2【财务审批】
image.png

流程定义文件

Process1.bpmn20.xmlProcess2.bpmn20.xml

授权码、POP3/SMTP服务

我这里用的是新浪邮箱,大家也可以切换其他邮箱,操作类似。。。
image.png

邮件TASK

这里使用表达式比较好,直接写死也可以的,但是不够灵活
image.png

配置文件

  activiti:
    database-schema-update: true
    history-level: full
    check-process-definitions: false #是否检测resources/processes 目录
    db-history-used: true #是否创建history表
    use-strong-uuids: false
    mail-server-host: smtp.sina.cn
    mail-server-port: 994
    mail-server-default-from: beyond_world@sina.cn
    mail-server-user-name: beyond_world
    # 注意这里的密码不是邮箱的登录密码, 邮箱客户端授权码
    mail-server-password: 1a01100034a4ff47
    mail-server-use-ssl: true

BPM文件

<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
  <process id="EmailTask" name="EmailTask" isExecutable="true">
    <documentation>EmailTask</documentation>
    <startEvent id="startEvent1" name="StartEvent"></startEvent>
    <serviceTask id="sid-A4B24F6A-78AD-4544-9B79-EF120CB24BC1" name="EmailTask" activiti:type="mail">
      <extensionElements>
        <activiti:field name="to">
          <activiti:expression><![CDATA[${to}]]></activiti:expression>
        </activiti:field>
        <activiti:field name="from">
          <activiti:expression><![CDATA[${from}]]></activiti:expression>
        </activiti:field>
        <activiti:field name="subject">
          <activiti:expression><![CDATA[${subject}]]></activiti:expression>
        </activiti:field>
        <activiti:field name="text">
          <activiti:expression><![CDATA[${text}]]></activiti:expression>
        </activiti:field>
        <activiti:field name="charset">
          <activiti:string>UTF-8</activiti:string>
        </activiti:field>
      </extensionElements>
    </serviceTask>
    <endEvent id="sid-DD3E2955-B10C-41E5-A7EC-B15CDFF3BF21" name="EndEvent"></endEvent>
    <sequenceFlow id="sid-8BEA43C4-ACF6-45E7-BFA7-D445B1409DE0" sourceRef="startEvent1" targetRef="sid-A4B24F6A-78AD-4544-9B79-EF120CB24BC1"></sequenceFlow>
    <sequenceFlow id="sid-CAF89079-3801-472D-B52E-BB5C4FC52F56" sourceRef="sid-A4B24F6A-78AD-4544-9B79-EF120CB24BC1" targetRef="sid-DD3E2955-B10C-41E5-A7EC-B15CDFF3BF21"></sequenceFlow>
  </process>

EmailTask.bpmn20.xml

测试代码

//发起流程
@Test
public void test05(){
    Map<String, Object> variables = new HashMap<>();
    variables.put("from", "beyond_world@sina.cn");
    variables.put("to", "4407509@qq.com");
    variables.put("subject", "Hello World");
    variables.put("text", "欢迎学习Activiti邮件发送功能!");

    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("EmailTask",variables);
    System.out.println("processInstance.getId() = " + processInstance.getId());
    System.out.println("processInstance.getName() = " + processInstance.getName());
    System.out.println("processInstance.getDescription() = " + processInstance.getDescription());
}

结果

image.png

手动任务

手动任务是在没有任何业务流程执行引擎或任何应用程序帮助的情况下执行的任务。

下面的示例显示了购物车检查的过程。关于签核的任务都是手动任务,无需借助任何流程执行引擎或软件系统即可执行。

当我们完成【经理审批】会自动执行【手工任务】后到达【人事审批】:手工任务主要是能自动执行一些逻辑,比如我们可以在手工任务上加上一些监听等等。
image.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员一灯

请给我打钱!!!谢谢,不客气!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值