Activiti Core
新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用于内存中存储。
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
建议使用BOM。
<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 Security模块。因为在Spring Boot应用程序内部,所以可以使用UserDetailsService
来配置可用用户及其各自的组和角色,目前在@Configuration
类中执行此操作:
这里需要注意的重要一点是,为了作为用户与TaskRuntime API进行交互,你需要拥有角色:ACTIVITI_USER(授予的权限:ROLEACTIVITIUSER)。
与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());
}
你可以根据需要注册任意多个TaskRuntimeEventListener,当服务触发运行时事件时,这将使你的应用程序得到通知。
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个服务任务,为了提供这些服务任务的实现,你需要定义Connector
:
@Bean
public Connector processTextConnector() {
return integrationContext -> {
Map inBoundVariables = integrationContext.getInBoundVariables();
String contentToProcess = (String) inBoundVariables.get("content")
// Logic Here to decide if content is approved or not
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名称(在此示例中为“processTextConnector”)自动连接到ProcessRuntime
,此bean名称是从流程定义内的serviceTask元素的implementation属性中选取的:
<bpmn:serviceTask id="Task_1ylvdew" name="Process Content" implementation="processTextConnector">
这个新的Connector
接口是JavaDelegate
的自然演变,新版本的Activiti Core将通过将它们包装在Connector
实现中来尝试重用JavaDelagate
:
public interface Connector {
IntegrationContext execute(IntegrationContext integrationContext);
}
连接器接收带有流程变量的IntegrationContext
,并返回修改后的IntegrationContext
,其结果需要映射回流程变量。
在前面的示例中,连接器实现正在接收“content”变量,并基于内容处理逻辑添加“approved”变量。
在这些连接器内,你可能会包含系统到系统的调用,例如REST调用和基于消息的交互。
查看Maven模块activiti-api-spring-integration-example以获取更高级的示例,该示例使用Spring Integrations基于文件轮询器启动流程。
完整示例
你可以找到使用ProcessRuntime
和TaskRuntime
API来自动执行以下流程的示例:
该部分的代码可以在“activiti-api-basic-full-example” maven模块内找到。
作为仅ProcessRuntime
的示例,它还对一些输入内容进行了分类,但是在这种情况下,该过程依赖于人工来决定是否批准内容。与之前一样,有一个调度任务,该任务每5秒创建一个新的流程实例,并且模拟用户检查是否有可用的任务要处理。
和
将UserTask创建给一个potentialOwner,在本示例中为“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>
属于该组的用户将可以领取任务并处理任务。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。