Activity
version:7
官方网站:https://www.activiti.org/
教程来源: Getting Started - Activiti & Activiti Cloud Developers Guide (gitbook.io)
此快速入门假设:
- 熟悉Maven和Java
- 使用Java的开发环境
以下变量将在本教程中引用
| 变量 | 描述 |
|---|---|
| $mvnProject | maven项目的根位置 |
| $actUnzipedPack | 从http://www.activiti.org/download.html. 下载的解压缩文件的根位置 |
| $quickStartJavaProjectName | 快速启动Java项目的名称。这被推荐为 “ActivitiDeveloperQuickStart” |
| … | 为简洁起见,指的是被跳过的信息 |
| $actVer | 目前正在运行的Activiti版本。 |
导言
此快速入门显示了使用Activiti将业务流程管理 (BPM) 嵌入到应用程序中的简单性。您将构建一个命令行应用程序,该应用程序将基于标准的业务流程建模符号 (BPMN) 逻辑嵌入到您的应用程序中。
Activiti具有先进的流程设计工具,可将更复杂的BPM逻辑嵌入到您的应用程序中。这些工具包括基于Eclipse和基于Web的BPMN编辑器,仅举几例。为简洁起见,此快速入门仅使用Activiti的Java api。
有关其他Activiti BPM工具的介绍,请参见:
简单的入职快速开始
Activiti用户指南
创建和设置Maven项目
创建一个名为 “ActivitiDeveloperQuickStart” 的Java项目 (以后称为 $ quickStartJavaProjectName),具有以下Maven依赖项:
<dependencies><dependency><groupId>org.activiti</groupId><artifactId>activiti-engine</artifactId><version>$actVer</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>1.4.193</version></dependency></dependencies>
当然,$ actVer将被下载的Activiti版本替换。例如,如果您下载的Activiti软件包 “activiti-5.22.0”,则 $ actVer的值将为5.22.0。
请注意以下依赖关系:
- Activiti (org.activiti) – Activiti’s BPM engine
- Database (com.h2database) – the H2 database
- Logging (org.slf4j) – Simple Logging Facade for Java
创建流程引擎
创建一个带有空白main的新Java类, 添加到主要入口点的是流程引擎的创建
public static void main(String[] args) {ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration().setJdbcUrl("jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000").setJdbcUsername("sa").setJdbcPassword("").setJdbcDriver("org.h2.Driver").setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);ProcessEngine processEngine = cfg.buildProcessEngine();String pName = processEngine.getName();String ver = ProcessEngine.VERSION;System.out.println("ProcessEngine [" + pName + "] Version: [" + ver + "]");}
部署流程定义
我们现在准备向Activiti引擎添加额外的BPM逻辑。
为此,正如我们的OnboardingRequest Java类的名称所建议的那样,我们将使用一个简单的Onboarding过程。在这个例子中,我们将输入数据。然后,如果经验年限超过3年,则将发布个性化入职欢迎消息的任务。在该任务中,用户将手动将数据输入到人造后端系统中。如果经验年限为3年或以下,则简单地,一般地,自动地将数据与人造后端系统集成在一起。
Activiti的流程引擎是符合BPMN 2.0的。从视觉上看,上面的过程可以像这样建模:

这个例子是故意简单的。并且,根据需求,可以通过几种不同的方式对其进行建模。虽然它也可以编排简单的流程,但请注意,Activiti可以处理数十,数百甚至数千个步骤的非常复杂的流程。
上面的可视化过程模型的基础是BPMN的XML结构。本例中的XML文档为onboarding.bpmn20.xml此快速入门不会深入底层XML BPMN结构的深度,而专注于针对Activiti api进行开发并将Activiti嵌入到应用程序中的机制。然而,为了支持以下逻辑,这里是相关的BPMN形状和底层XML中编码的定义逻辑的摘要:
| 图形 | 注释 |
|---|---|
| 开始事件 | |
| 用户任务收集2个表单属性: “fullName” 和 “yearsOfExperience”。注意第9行的候选组设置为 “managers”。 | |
| 用户任务收集1个表单属性: “personalWelcomeTime”。注意第22行的候选组设置为 “managers”。 | |
| 脚本任务表示自动输入数据到人造后端。注意虽然简单,但有一个简单的脚本,它设置了一个过程变量autoWelcomeTime (第34-35行): var dateAsString = new Date().toString(); execution.setVariable(“autoWelcomeTime”, dateAsString); |
|
| 定义 “Years of Experience” 排他网关。(一个决定将产生一条或另一条路径。) 使用yearsOfExperience变量表示 “>3” 逻辑:${yearsOfExperience > 3} 在排他网关上,注意默认节,该节指向 “automatedIntroPath ”,表示逻辑上的 “其他”,表示条件 “>3”。 |
|
| 结束事件 |
onboarding.bpmn20.xml
<?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="onboarding" name="Onboarding" isExecutable="true"><startEvent id="startOnboarding" name="Start" activiti:initiator="initiator"></startEvent><userTask id="enterOnboardingData" name="Enter Data" activiti:assignee="${initiator}" activiti:candidateGroups="managers"><extensionElements><activiti:formProperty id="fullName" name="Full Name" type="string"></activiti:formProperty><activiti:formProperty id="yearsOfExperience" name="Years of Experience" type="long" required="true"></activiti:formProperty></extensionElements></userTask><sequenceFlow id="sid-1337EA98-7364-4198-B5D9-30F5341D6918" sourceRef="startOnboarding" targetRef="enterOnboardingData"></sequenceFlow><exclusiveGateway id="decision" name="Years of Experience" default="automatedIntroPath"></exclusiveGateway><sequenceFlow id="sid-42BE5661-C3D5-4DE6-96F5-73D34822727A" sourceRef="enterOnboardingData" targetRef="decision"></sequenceFlow><userTask id="personalizedIntro" name="Personalized Introduction and Data Entry" activiti:assignee="${initiator}" activiti:candidateGroups="managers"><extensionElements><activiti:formProperty id="personalWelcomeTime" name="Personal Welcome Time" type="date" datePattern="MM-dd-yyyy hh:mm"></activiti:formProperty></extensionElements></userTask><endEvent id="endOnboarding" name="End"></endEvent><sequenceFlow id="sid-37A73ACA-2E23-400B-96F3-71F77738DAFA" sourceRef="automatedIntro" targetRef="endOnboarding"></sequenceFlow><scriptTask id="automatedIntro" name="Generic and Automated Data Entry" scriptFormat="javascript" activiti:autoStoreVariables="false"><script><![CDATA[var dateAsString = new Date().toString();execution.setVariable("autoWelcomeTime", dateAsString);]]></script></scriptTask><sequenceFlow id="automatedIntroPath" sourceRef="decision" targetRef="automatedIntro"></sequenceFlow><sequenceFlow id="personalizedIntroPath" name=">3" sourceRef="decision" targetRef="personalizedIntro"><conditionExpression xsi:type="tFormalExpression"><![CDATA[${yearsOfExperience > 3}]]></conditionExpression></sequenceFlow><sequenceFlow id="sid-BA6F061B-47B6-428B-8CE6-739244B14BD6" sourceRef="personalizedIntro" targetRef="endOnboarding"></sequenceFlow></process><bpmndi:BPMNDiagram id="BPMNDiagram_onboarding"><bpmndi:BPMNPlane bpmnElement="onboarding" id="BPMNPlane_onboarding"><bpmndi:BPMNShape bpmnElement="startOnboarding" id="BPMNShape_startOnboarding"><omgdc:Bounds height="30.0" width="30.0" x="155.0" y="145.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="enterOnboardingData" id="BPMNShape_enterOnboardingData"><omgdc:Bounds height="80.0" width="100.0" x="240.0" y="120.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="decision" id="BPMNShape_decision"><omgdc:Bounds height="40.0" width="40.0" x="385.0" y="140.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="personalizedIntro" id="BPMNShape_personalizedIntro"><omgdc:Bounds height="80.0" width="100.0" x="519.0" y="15.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="endOnboarding" id="BPMNShape_endOnboarding"><omgdc:Bounds height="28.0" width="28.0" x="725.0" y="165.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNShape bpmnElement="automatedIntro" id="BPMNShape_automatedIntro"><omgdc:Bounds height="80.0" width="100.0" x="520.0" y="255.0"></omgdc:Bounds></bpmndi:BPMNShape><bpmndi:BPMNEdge bpmnElement="sid-37A73ACA-2E23-400B-96F3-71F77738DAFA" id="BPMNEdge_sid-37A73ACA-2E23-400B-96F3-71F77738DAFA"><omgdi:waypoint x="570.0" y="255.0"></omgdi:waypoint><omgdi:waypoint x="570.0" y="179.0"></omgdi:waypoint><omgdi:waypoint x="725.0" y="179.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="sid-1337EA98-7364-4198-B5D9-30F5341D6918" id="BPMNEdge_sid-1337EA98-7364-4198-B5D9-30F5341D6918"><omgdi:waypoint x="185.0" y="160.0"></omgdi:waypoint><omgdi:waypoint x="240.0" y="160.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="automatedIntroPath" id="BPMNEdge_automatedIntroPath"><omgdi:waypoint x="405.0" y="180.0"></omgdi:waypoint><omgdi:waypoint x="405.0" y="295.0"></omgdi:waypoint><omgdi:waypoint x="520.0" y="295.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="personalizedIntroPath" id="BPMNEdge_personalizedIntroPath"><omgdi:waypoint x="405.0" y="140.0"></omgdi:waypoint><omgdi:waypoint x="405.0" y="55.0"></omgdi:waypoint><omgdi:waypoint x="519.0" y="55.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="sid-42BE5661-C3D5-4DE6-96F5-73D34822727A" id="BPMNEdge_sid-42BE5661-C3D5-4DE6-96F5-73D34822727A"><omgdi:waypoint x="340.0" y="160.0"></omgdi:waypoint><omgdi:waypoint x="385.0" y="160.0"></omgdi:waypoint></bpmndi:BPMNEdge><bpmndi:BPMNEdge bpmnElement="sid-BA6F061B-47B6-428B-8CE6-739244B14BD6" id="BPMNEdge_sid-BA6F061B-47B6-428B-8CE6-739244B14BD6"><omgdi:waypoint x="619.0" y="55.0"></omgdi:waypoint><omgdi:waypoint x="739.0" y="55.0"></omgdi:waypoint><omgdi:waypoint x="739.0" y="165.0"></omgdi:waypoint></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram></definitions>
加载流程定义
RepositoryService repositoryService = processEngine.getRepositoryService();
//加载提供的BPMN模型并将其部署到Activiti进程引擎。
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("onboarding.bpmn20.xml").deploy();
//检索已部署的模型,证明它在Activiti存储库中。
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId(deployment.getId()).singleResult();
System.out.println(
"Found process definition ["
+ processDefinition.getName() + "] with id ["
+ processDefinition.getId() + "]");
运行进程实例
部署的进程可以使用Activiti API来启动、运行、查看历史记录,并以其他方式管理进程实例。此快速启动使用Java代码运行进程实例。
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("onboarding");
System.out.println("Onboarding process started with process instance id ["
+ processInstance.getProcessInstanceId()
+ "] key [" + processInstance.getProcessDefinitionKey() + "]");
TaskService taskService = processEngine.getTaskService();
FormService formService = processEngine.getFormService();
HistoryService historyService = processEngine.getHistoryService();
Scanner scanner = new Scanner(System.in);
while (processInstance != null && !processInstance.isEnded()) {
List<Task> tasks = taskService.createTaskQuery()
.taskCandidateGroup("managers").list();
System.out.println("Active outstanding tasks: [" + tasks.size() + "]");
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
System.out.println("Processing Task [" + task.getName() + "]");
Map<String, Object> variables = new HashMap<String, Object>();
FormData formData = formService.getTaskFormData(task.getId());
for (FormProperty formProperty : formData.getFormProperties()) {
if (StringFormType.class.isInstance(formProperty.getType())) {
System.out.println(formProperty.getName() + "?");
String value = scanner.nextLine();
variables.put(formProperty.getId(), value);
} else if (LongFormType.class.isInstance(formProperty.getType())) {
System.out.println(formProperty.getName() + "? (Must be a whole number)");
Long value = Long.valueOf(scanner.nextLine());
variables.put(formProperty.getId(), value);
} else if (DateFormType.class.isInstance(formProperty.getType())) {
System.out.println(formProperty.getName() + "? (Must be a date m/d/yy)");
DateFormat dateFormat = new SimpleDateFormat("m/d/yy");
Date value = dateFormat.parse(scanner.nextLine());
variables.put(formProperty.getId(), value);
} else {
System.out.println("<form type not supported>");
}
}
taskService.complete(task.getId(), variables);
HistoricActivityInstance endActivity = null;
List<HistoricActivityInstance> activities =
historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstance.getId()).finished()
.orderByHistoricActivityInstanceEndTime().asc()
.list();
for (HistoricActivityInstance activity : activities) {
if (activity.getActivityType() == "startEvent") {
System.out.println("BEGIN " + processDefinition.getName()
+ " [" + processInstance.getProcessDefinitionKey()
+ "] " + activity.getStartTime());
}
if (activity.getActivityType() == "endEvent") {
// Handle edge case where end step happens so fast that the end step
// and previous step(s) are sorted the same. So, cache the end step
//and display it last to represent the logical sequence.
endActivity = activity;
} else {
System.out.println("-- " + activity.getActivityName()
+ " [" + activity.getActivityId() + "] "
+ activity.getDurationInMillis() + " ms");
}
}
if (endActivity != null) {
System.out.println("-- " + endActivity.getActivityName()
+ " [" + endActivity.getActivityId() + "] "
+ endActivity.getDurationInMillis() + " ms");
System.out.println("COMPLETE " + processDefinition.getName() + " ["
+ processInstance.getProcessDefinitionKey() + "] "
+ endActivity.getEndTime());
}
}
// Re-query the process instance, making sure the latest state is available
processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstance.getId()).singleResult();
}
scanner.close();
快速启动
此快速入门旨在帮助您启动并运行Activiti核心和Activiti云。我们的教程提供了Activiti过程自动化项目基础知识的演练。
步骤1 :( 先决条件)-设置您的环境
步骤2: 部署Activiti运行时应用程序
步骤3: 测试Activiti应用程序示例
入门
入门-活动核心
Activiti核心运行时api入门
创建新的api具有明确的目的,以满足以下要求:
- 为我们的云方法提供清晰的路径
- 隔离内部和外部api,以提供向前的向后兼容性
- 通过遵循单一责任方法提供模块化的未来路径
- 减少以前版本的api的混乱
- 包括安全和身份管理作为一流公民
- 减少常见用例的价值时间,在这些用例中,您希望依赖流行框架提供的约定
- 提供底层服务的替代实现
- 使社区能够在尊重既定合同的同时进行创新
我们还没有弃用旧的API,所以您仍然可以自由使用它,但是我们强烈建议使用新的API来获得长期支持。
此API处于beta审查中,这意味着我们可能会在GA发布之前对其进行更改和完善。我们将感谢我们从社区用户那里得到的所有反馈,如果您想参与该项目,请与我们联系。
是时候用几个示例项目弄脏我们的手了。
TaskRuntime API
如果您正在构建业务应用程序,那么为组织中的用户和组创建任务可能会很方便。
TaskRuntime api在这里为您提供帮助。
您可以从GitHub克隆此示例: https://github.com/Activiti/activiti-examples
本节中的代码可以在 “activiti-api-basic-task-example” maven模块中找到。
如果您在Spring Boot 2应用程序中运行,则只需添加activiti-spring-boot-starter依赖项和可以将H2用于内存存储的DB驱动程序。
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
我们建议使用我们的物料清单 (物料清单)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti.dependencies</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.1.0.M5</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
注意: 可以使用此链接检索最新版本 https://search.maven.org/search?q=activiti-dependencies
现在让我们切换到我们的DemoApplication.class: https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplication.java#L25
然后,您将能够使用TaskRuntime
@Autowired
private TaskRuntime taskRuntime;
将bean注入应用程序后,您应该能够创建任务并与任务进行交互
public interface TaskRuntime {
TaskRuntimeConfiguration configuration();
Task task(String taskId);
Page tasks(Pageable pageable);
Page tasks(Pageable pageable, GetTasksPayload payload);
Task create(CreateTaskPayload payload);
Task claim(ClaimTaskPayload payload);
Task release(ReleaseTaskPayload payload);
Task complete(CompleteTaskPayload payload);
Task update(UpdateTaskPayload payload);
Task delete(DeleteTaskPayload payload);
...
}
例如,您可以通过执行以下操作来创建任务:
taskRuntime.create(
TaskPayloadBuilder.create()
.withName("First Team Task")
.withDescription("This is something really important")
.withGroup("activitiTeam")
.withPriority(10)
.build());
此任务仅由属于activitiTeam的用户和所有者 (当前登录用户) 可见。
您可能已经注意到,您可以使用TaskPayloadBuilder以流畅的方式对将要发送到TaskRuntime的信息进行参数化。
为了处理安全性,角色和组,我们依靠Spring安全模块。因为我们在Spring Boot应用程序中,所以我们可以使用UserDetailsService来配置可用用户及其各自的组和角色。我们目前正在 @ Configuration类中执行此操作:
这里要注意的重要一点是,为了以用户身份与TaskRuntime API进行交互,您需要具有以下角色: ACTIVITI_USER (授予权限: ROLE_ACTIVITI_USER)。
在与REST端点交互时,授权机制将设置当前登录的用户,但是为了示例,我们使用的是实用程序类 (https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/SecurityUtil.java#L26 ) 这使我们可以在上下文中设置手动选择的用户。请注意,除非您正在尝试并希望在不通过REST端点的情况下更改用户,否则您永远不应该这样做。查看 “web” 示例,以查看根本不需要此实用程序类的更多真实场景。
从示例中要强调的最后一件事是任务事件侦听器的注册:
@Bean
public TaskRuntimeEventListener taskAssignedListener() {
return taskAssigned
-> logger.info(
">>> Task Assigned: '"
+ taskAssigned.getEntity().getName()
+"' We can send a notification to the assignee: "
+ taskAssigned.getEntity().getAssignee());
}
您可以根据需要注册任意数量的TaskRuntimeEventListeners。这将使您的应用程序能够在服务触发运行时事件时得到通知。
ProcessRuntime API
以类似的方式,如果要开始使用ProcessRuntime api,则需要包含与以前相同的依赖项。我们的目标是在未来提供更多的灵活性和单独的运行时,但目前相同的Spring Boot Starter提供TaskRuntime和ProcessRuntime API。
本节中的代码可以在 “activiti-api-basic-process-example” maven模块中找到。
public interface ProcessRuntime {
ProcessRuntimeConfiguration configuration();
ProcessDefinition processDefinition(String processDefinitionId);
Page processDefinitions(Pageable pageable);
Page processDefinitions(Pageable pageable,
GetProcessDefinitionsPayload payload);
ProcessInstance start(StartProcessPayload payload);
Page processInstances(Pageable pageable);
Page processInstances(Pageable pageable,
GetProcessInstancesPayload payload);
ProcessInstance processInstance(String processInstanceId);
ProcessInstance suspend(SuspendProcessPayload payload);
ProcessInstance resume(ResumeProcessPayload payload);
ProcessInstance delete(DeleteProcessPayload payload);
void signal(SignalPayload payload);
...
}
与TaskRuntime API类似,为了与ProcessRuntime API交互,当前登录的用户必须具有角色 “ACTIVITI_USER”。
首先,让我们自动注入我们的ProcessRuntime:
@Autowired
private ProcessRuntime processRuntime;
@Autowired
private SecurityUtil securityUtil;
和以前一样,我们需要我们的SecurityUtil助手来定义我们与api交互的用户。
现在我们可以开始与ProcessRuntime交互:
Page processDefinitionPage = processRuntime
.processDefinitions(Pageable.of(0, 10));
logger.info("> Available Process definitions: " +
processDefinitionPage.getTotalItems());
for (ProcessDefinition pd : processDefinitionPage.getContent()) {
logger.info("\t > Process definition: " + pd);
}
进程定义需要放在/src/main/resources/processes/内部。对于此示例,我们定义了以下过程:
我们正在使用Spring Scheduling功能每秒启动一个过程,从数组中获取随机值以进行处理:
@Scheduled(initialDelay = 1000, fixedDelay = 1000)
public void processText() {
securityUtil.logInAs("system");
String content = pickRandomString();
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yy HH:mm:ss");
logger.info("> Processing content: " + content
+ " at " + formatter.format(new Date()));
ProcessInstance processInstance = processRuntime
.start(ProcessPayloadBuilder
.start()
.withProcessDefinitionKey("categorizeProcess")
.withProcessInstanceName("Processing Content: " + content)
.withVariable("content", content)
.build());
logger.info(">>> Created Process Instance: " + processInstance);
}
与以前相同,我们正在使用ProcessPayloadBuilder来以流畅的方式参数化我们要启动的流程以及使用哪些流程变量。
现在,如果我们回顾一下流程定义,您将发现3个服务任务。为了提供这些服务任务的实现,您需要定义连接器:
@Bean
public Connector processTextConnector() {
return integrationContext -> {
Map inBoundVariables = integrationContext.getInBoundVariables();
String contentToProcess = (String) inBoundVariables.get("content")
// 这里的逻辑决定内容是否被接受
if (contentToProcess.contains("activiti")) {
logger.info("> Approving content: " + contentToProcess);
integrationContext.addOutBoundVariable("approved",true);
} else {
logger.info("> Discarding content: " + contentToProcess);
integrationContext.addOutBoundVariable("approved",false);
}
return integrationContext;
};
}
这些连接器使用Bean名称自动连接到ProcessRuntime,在本例中为 “processTextConnector”。这个bean名称是从我们的流程定义中的serviceTask元素的实现属性中提取的:
<bpmn:serviceTask id="Task_1ylvdew" name="Process Content" implementation="processTextConnector">
这个新的连接器接口是JavaDelegates的自然进化,新版本的Activiti核心将尝试通过将它们包装在连接器实现中来重用JavaDelagates:
public interface Connector {
IntegrationContext execute(IntegrationContext integrationContext);
}
连接器接收带有流程变量的IntegrationContext,并返回经过修改的IntegrationContext,其结果需要映射回流程变量。
在前面的示例中,连接器实现正在接收 “ content ” 变量并基于内容处理逻辑添加 “ approved ” 变量。
在这些连接器中,您可能会包括系统到系统的调用,例如REST调用和基于消息的交互。这些交互往往变得越来越复杂,因此,我们将在未来的教程中看到如何从ProcessRuntime (云连接器) 的上下文外部运行中提取这些连接器,以解耦在ProcessRuntime范围之外的此类外部交互的责任。
检查maven模块 activiti-api-spring-integration-example ,以获取更高级的示例,其中使用Spring集成来基于文件轮询器的启动进程。
完整示例
您可以找到一个使用ProcessRuntime和TaskRuntime api来自动化以下过程的示例:
本节中的代码可以在 “activiti-api-basic-full-example” maven模块中找到。
作为ProcessRuntime的唯一示例,这也对某些输入内容进行了分类,但是在这种情况下,该过程依赖于人类参与者来决定是否批准该内容。我们像以前一样有一个计划任务,每5秒创建一次新的流程实例,并由模拟用户检查是否有可用的任务要处理。
和
将UserTask创建给一组潜在所有者,在本示例中为 “activitiTeam” 组。但是在这种情况下,我们不会像第一个示例那样手动创建任务。每次启动流程时,流程实例都会为我们创建任务。
<bpmn:userTask id="Task_1ylvdew" name="Process Content">
<bpmn:incoming>SequenceFlow_09xowo4</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_1jzbgkj</bpmn:outgoing>
<bpmn:potentialOwner>
<bpmn:resourceAssignmentExpression>
<bpmn:formalExpression>activitiTeam</bpmn:formalExpression>
</bpmn:resourceAssignmentExpression>
</bpmn:potentialOwner>
</bpmn:userTask>
属于该组的用户将能够声明并处理该任务。
我们鼓励您运行这些示例并进行实验,如果您有问题或发现问题,请与他们联系。
总结
在本教程中,我们已经了解了如何从新的Activiti Core Beta项目开始使用新的ProcessRuntime和TaskRuntime API。
我们建议您检查Activiti示例存储库,了解更多示例: https://github.com/Activiti/activiti-examples
