💖专栏简介
✔️本专栏将从Camunda(卡蒙达) 7中的关键概念到实现中国式工作流相关功能。
✔️文章中只包含演示核心代码及测试数据,完整代码可查看作者的开源项目snail-camunda
✔️请给snail-camunda 点颗星吧😘
💖什么是委托代码
委托代码是在流程执行过程中发生某些事件时执行外部Java代码、脚本或求值表达式。在Camunda中分为如下4种:
- Java Delegate 【Java委托】
- Delegate Variable Mapping 【委托变量映射】
- Execution Listener 【执行监听器】
- Task Listener 【任务监听器】
💖Java Delegate
要实现一个可以在流程执行期间调用的类,该类需要实现org.camunda.bpm.engine.delegate.JavaDelegate 接口,并在execute方法中提供所需的逻辑。当流程执行到达这个特定步骤时,它将执行在该方法中定义的逻辑,并以默认的BPMN 2.0方式离开活动。
接下来通过Send Task发送邮件来演示:
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_19cqxxj" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.19.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="Process_0cu2yds" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0yf2ndo</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0yf2ndo" sourceRef="StartEvent_1" targetRef="Activity_1jxjk7q" />
<bpmn:userTask id="Activity_1jxjk7q" name="发起人" camunda:assignee="${initiator}">
<bpmn:incoming>Flow_0yf2ndo</bpmn:incoming>
<bpmn:outgoing>Flow_0ti4nj0</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0ti4nj0" sourceRef="Activity_1jxjk7q" targetRef="Activity_0g9hruk" />
<bpmn:sendTask id="Activity_0g9hruk" name="戴宗报信" camunda:class="com.lonewalker.snail.delegate.SendEmailDelegate">
<bpmn:incoming>Flow_0ti4nj0</bpmn:incoming>
<bpmn:outgoing>Flow_0mub7f0</bpmn:outgoing>
</bpmn:sendTask>
<bpmn:sequenceFlow id="Flow_0mub7f0" sourceRef="Activity_0g9hruk" targetRef="Activity_111hike" />
<bpmn:userTask id="Activity_111hike" name="宋江" camunda:assignee="${head}">
<bpmn:incoming>Flow_0mub7f0</bpmn:incoming>
<bpmn:outgoing>Flow_1kv7i02</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_037pynp">
<bpmn:incoming>Flow_1kv7i02</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1kv7i02" sourceRef="Activity_111hike" targetRef="Event_037pynp" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0cu2yds">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0mqjfh8_di" bpmnElement="Activity_1jxjk7q">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1tg1kpv_di" bpmnElement="Activity_0g9hruk">
<dc:Bounds x="430" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1mr4xv3_di" bpmnElement="Activity_111hike">
<dc:Bounds x="590" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_037pynp_di" bpmnElement="Event_037pynp">
<dc:Bounds x="752" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0yf2ndo_di" bpmnElement="Flow_0yf2ndo">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ti4nj0_di" bpmnElement="Flow_0ti4nj0">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0mub7f0_di" bpmnElement="Flow_0mub7f0">
<di:waypoint x="530" y="117" />
<di:waypoint x="590" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1kv7i02_di" bpmnElement="Flow_1kv7i02">
<di:waypoint x="690" y="117" />
<di:waypoint x="752" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
还是一样的将类路径替换为自己的。
此外,通过field injection【字段注入】设置目标邮箱,字段注入的Name建议使用驼峰命名,因为我们在代码中需要使用。
关于邮箱的设置可查看此篇【Springboot发送邮件】
在配置文件中新增邮件相关配置
###邮件相关配置
#邮箱服务器地址
spring.mail.host=smtp.163.com
#邮箱用户名
spring.mail.username=xxx@163.com
#邮箱密码(注意:qq邮箱应该使用独立密码,去qq邮箱设置里面获取 163邮箱使用设置的授权码)
#这里把授权码改为自己的
spring.mail.password=QJBFXYUNMQYRCGSU
##编码格式
spring.mail.default-encoding=UTF-8
##端口号 465或者994
spring.mail.port=465
spring.mail.protocol=smtps
##发送邮件地址
spring.mail.from=xxx@163.com
新增发送邮件的委托代码
@RequiredArgsConstructor
@Slf4j
@Component
public class SendEmailDelegate implements JavaDelegate {
private final JavaMailSender mailSender;
@Value("${spring.mail.from}")
private String addresser;
private Expression sendingTarget;
@Override
public void execute(DelegateExecution execution) throws Exception {
String initiator = (String) execution.getVariable("initiator");
String processInstanceId = execution.getProcessInstanceId();
String content = initiator+"--发起的审批流程抄送给您["+processInstanceId+"]";
//获取收件人,也可以在表单设计时存入数据库
String recipient = String.valueOf(sendingTarget.getValue(execution));
//改成自己的邮箱账号调试
SimpleMailMessage mailMessage = new SimpleMailMessage();
//设置发件人
mailMessage.setFrom(addresser);
//设置收件人
mailMessage.setTo(recipient);
//设置主题
mailMessage.setSubject("审批抄送");
//设置内容
mailMessage.setText(content);
//发送邮件
mailSender.send(mailMessage);
}
}
测试结果:
在流程定义中引用的类(例如上述的com.lonewalker.demo.delegate.SendEmailDelegate)不会在部署期间实例化。只有当流程执行到达流程中第一次使用该类的点时才会创建该类的实例。如果找不到该类,将抛出ProcessEngineException。
每次执行委托类引用活动时,将创建该类的一个单独实例。这意味着每次执行一个活动时,都会使用类的另一个实例来调用execute(DelegateExecution)。
💖Field Injection
在上述流程定义设计时已经演示了如何使用Field Injection。实际上就是把我们需要的值注入到委托类的字段中。
如果可用,则通过委托类上的公共setter方法注入该值,遵循Java Bean命名约定。
不管在流程定义中声明的值的类型是什么,注入目标上的字段的类型应该始终是
org. camunda.bbpm .engine.delegate. expression
💖其他
委托变量映射很少用就略过了,而执行监听器和任务监听器是重点,放在下一篇详细讲解Camunda执行监听器与任务监听器-CSDN博客