一:Java class
Java class实现JavaDelegate接口,只需要配置类的全限定名即可,不需要被Spring容器管理。
public class JavaClassServiceTask implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
System.out.println("JavaClassServiceTask");
String currentActivityId = execution.getCurrentActivityId();
execution.setVariable(currentActivityId, "ok");
}
}
二:Delegate expression
实现JavaDelegate接口,配置成Bean的名字即可。
@Service
public class DelegateExpressionServiceTask implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
System.out.println(execution.getVariable("JavaClass"));
System.out.println("DelegateExpressionServiceTask");
}
}
三:Expression
配置成普通的方法调用,可以是任意类的任意方法,方法的返回值会赋值给Result variable变量,该变量可以从下一个节点获取。
@Service
public class ExpressionServiceTask {
public boolean execute(DelegateExecution execution) {
System.out.println("ExpressionServiceTask");
return true;
}
}
四:External
@Configuration
public class CamundaHandlerConfig {
@Bean
@ExternalTaskSubscription(topicName = "java_external_task_topic",
processDefinitionKeyIn = {"ServiceTaskProcess"},
lockDuration = 5000)
public ExternalTaskHandler externalTaskHandler() {
return (ExternalTask externalTask, ExternalTaskService externalTaskService) -> {
boolean expressionResult = (boolean)externalTask.getVariable("expressionResult");
// 处理业务逻辑...
if (!expressionResult) {
externalTaskService.handleFailure(externalTask, "error msg...", "error detail...", 0, 5000);
}
Map<String, Object> variables = new HashMap<>();
variables.put("result", 1);
externalTaskService.complete(externalTask, variables);
};
}
}
# pip3 install camunda-external-task-client-python3
# pip3 install pydantic
from camunda.external_task.external_task import ExternalTask, TaskResult
from camunda.external_task.external_task_worker import ExternalTaskWorker
default_config = {
"maxTasks": 1, # 一次只拉一个任务,这样多实例处理就不会所有任务被一个实例锁住
"lockDuration": 10000, # 锁任务的时间
"asyncResponseTimeout": 30000,
"retries": 0,
"retryTimeout": 5000,
"sleepSeconds": 30000, # 每次拉取的间隔时间
"auth_basic": {"username": "admin", "password": "123456"}
}
def handle_task(task: ExternalTask) -> TaskResult:
result = task.get_variable("result")
if result:
return task.failure(error_message="error_message",
error_details="error_details 如异常堆栈信息",
max_retries=0, retry_timeout=5000)
return task.complete()
if __name__ == '__main__':
worker = ExternalTaskWorker(worker_id="python-client",
base_url="http://localhost:8080/engine-rest",
config=default_config).subscribe("python_external_task_topic", handle_task)
五:运行
- 启动工作流引擎
- 启动Java客户端
- 启动Python客户端
repositoryService.createDeployment()
.name("服务任务流程")
.addClasspathResource("bpmn/service_task.bpmn")
.deploy();
identityService.setAuthenticatedUserId("huihui");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ServiceTaskProcess");
System.out.println("processInstance=" + processInstance.getId());
五:连接器 Connector
连接器Connector就是内置apache的http client 就是在执行这个节点时发送一个http请求,对结果进行响应,感觉非常鸡肋的功能,我用UserTask或者其他ServiceTask在代码里调用不香吗,我可以在代码中写复杂的逻辑,组装复杂的请求参数,打印日志,记录请求结果等其它操作,这玩意也就适用最简单的方法调用,有大量参数时光组装参数就没法玩。
5.1 pom.xml
<dependency>
<groupId>org.camunda.bpm</groupId>
<artifactId>camunda-engine-plugin-connect</artifactId>
<version>${camunda.spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.camunda.connect</groupId>
<artifactId>camunda-connect-connectors-all</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>org.camunda.bpm</groupId>
<artifactId>camunda-engine-plugin-spin</artifactId>
<version>${camunda.spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.camunda.spin</groupId>
<artifactId>camunda-spin-dataformat-json-jackson</artifactId>
<version>1.17.0</version>
</dependency>
5.2 config
public class HttpConnectorConfigurator implements ConnectorConfigurator<HttpConnector> {
public Class<HttpConnector> getConnectorClass() {
return HttpConnector.class;
}
public void configure(HttpConnector connector) {
CloseableHttpClient client = HttpClients.custom()
.setMaxConnPerRoute(10)
.setMaxConnTotal(200)
.build();
((AbstractHttpConnector) connector).setHttpClient(client);
}
}
5.3 SPI
在文件src/main/resources/META-INF/services/org.camunda.connect.spi.ConnectorConfigurator中配置以下完全限制类。
com.example.camunda.config.HttpConnectorConfigurator
5.3 Controller
@RestController
public class UserController {
@GetMapping("/user/{userId}")
public Map<String, Object> user(@PathVariable("userId") String userId) {
Map<String, Object> map = new HashMap<>();
map.put("code", "200");
map.put("result", "success");
map.put("data", userId);
return map;
}
}
5.5 bpmn
<?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_042u8vr" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.18.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="ConnectorProcess" name="HttpClient服务" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1" camunda:initiator="userId">
<bpmn:outgoing>Flow_1q9dey8</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1q9dey8" sourceRef="StartEvent_1" targetRef="Activity_1nr3626" />
<bpmn:serviceTask id="Activity_1nr3626" name="http-connector">
<bpmn:extensionElements>
<camunda:connector>
<camunda:inputOutput>
<camunda:inputParameter name="headers">
<camunda:map>
<camunda:entry key="Content-Type">application/json</camunda:entry>
</camunda:map>
</camunda:inputParameter>
<camunda:inputParameter name="method">GET</camunda:inputParameter>
<camunda:inputParameter name="url">http://localhost:8081/user/${userId}</camunda:inputParameter>
<camunda:outputParameter name="response">
<camunda:script scriptFormat="JavaScript">var res = connector.getVariable("response");
res;</camunda:script>
</camunda:outputParameter>
</camunda:inputOutput>
<camunda:connectorId>http-connector</camunda:connectorId>
</camunda:connector>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1q9dey8</bpmn:incoming>
<bpmn:outgoing>Flow_0bklhmm</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_0bklhmm" sourceRef="Activity_1nr3626" targetRef="UserTask1" />
<bpmn:userTask id="UserTask1" name="UserTask1">
<bpmn:incoming>Flow_0bklhmm</bpmn:incoming>
<bpmn:outgoing>Flow_1w1qnew</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="end">
<bpmn:incoming>Flow_1w1qnew</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1w1qnew" sourceRef="UserTask1" targetRef="end" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="ConnectorProcess">
<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_1npa7km_di" bpmnElement="Activity_1nr3626">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1neh381_di" bpmnElement="UserTask1">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_199n12t_di" bpmnElement="end">
<dc:Bounds x="592" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1q9dey8_di" bpmnElement="Flow_1q9dey8">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0bklhmm_di" bpmnElement="Flow_0bklhmm">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1w1qnew_di" bpmnElement="Flow_1w1qnew">
<di:waypoint x="530" y="117" />
<di:waypoint x="592" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
5.6 test
repositoryService.createDeployment()
.name("HttpClient服务")
.addClasspathResource("bpmn/connector.bpmn")
.deploy();
identityService.setAuthenticatedUserId("huihui");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ConnectorProcess");
5.7 db