Activity7入门学习(二)
官网地址:https://activiti.gitbook.io/activiti-7-developers-guide/getting-started/getting-started-activiti-core
Getting Started - Activiti Core
Getting Started with Activiti Core Runtime APIs
新api的创建有明确的目的,以满足以下需求:
.为我们的云方法提供一条清晰的路径
.隔离内部和外部api以提供向前的向后兼容性
.通过遵循单一责任方法,提供通向模块化的未来路径
.减少以前版本api的混乱
.包括安全和身份管理作为一级公民
.在您希望依赖流行框架提供的约定的常用用例中,减少实现价值的时间
.提供基础服务的替代实现
.让社区在尊重既定契约的同时进行创新
我们没有弃用旧的API,所以您仍然可以自由使用它,但我们强烈建议使用新的API以获得长期支持。
这个API还在测试阶段,这意味着我们可能会在GA发布之前对它进行修改和润色。我们将感谢所有的反馈,我们可以从我们的社区用户,如果你想参与到该项目,请与我们联系。
是时候亲自动手做几个示例项目了。
TaskRuntime API
如果您正在构建业务应用程序,为组织中的用户和组创建task可能会很方便。
TaskRuntime api可以帮助您。
你可以在这里找到一些基本的例子(api-example模块).
本节的代码可以在“activity -api-basic-task-example”maven模块中找到。
如果你在Spring Boot 2应用程序中运行,你只需要添加activity - Spring - Boot -starter依赖和一个DB驱动程序,你可以使用H2作为内存存储。
https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-task-example/pom.xml
<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</groupId> <artifactId>activiti-dependencies</artifactId> <version>7.1.0-M16</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement>
注意:要在这里检查哪个是最新的版本(https://github.com/Activiti/Activiti/releases/tag/7.6.1)
现在让我们切换到DemoApplication.class:
然后您就可以使用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); ... }
例如,你可以这样创建一个任务:
https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplication.java#L60-L65
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类中这样做:(https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplicationConfiguration.java#L40-L62)
这里需要注意的重要一点是,为了以用户的身份与TaskRuntime API交互,您需要拥有角色:actiti_user(授予的权限:role_actiti_user)。
在与REST端点交互时,授权机制将设置当前登录的用户,但为了示例的目的,我们使用的是实用程序类SecurityUtil.java(https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-task-example/src/main/java/org/activiti/examples/SecurityUtil.java)这允许我们在上下文中设置手动选择的用户。
请注意,除非您正在进行尝试,并且希望在不通过REST端点的情况下更改用户,否则永远不应该这样做。查看“web”示例,了解更多不需要此实用程序类的实际场景。
最后需要强调的是任务事件监听器的注册:(https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplication.java#L103-L108)
@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。本节的代码可以在“activity -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交互,当前登录的用户需要具有角色“actiti_user”。
首先,让我们@Autowired我们的ProcessRuntime:(https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-process-example/src/main/java/org/activiti/examples/DemoApplication.java#L48-L52)
@Autowired private ProcessRuntime processRuntime; @Autowired private SecurityUtil securityUtil;
与以前一样,我们需要securityyutil帮助器来定义与api交互的用户。
现在我们可以开始与ProcessRuntime交互了:
https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-process-example/src/main/java/org/activiti/examples/DemoApplication.java#L63-L67
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功能来启动一个进程,每一秒从一个数组中拾取随机值。(https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-process-example/src/main/java/org/activiti/examples/DemoApplication.java#L71-L91)
@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个服务任务。为了为这些服务任务提供实现,你需要定义Connectors:
https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-process-example/src/main/java/org/activiti/examples/DemoApplication.java#L93-L110
@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名称自动连接到ProcessRuntime,在本例中为“processTextConnector”。这个bean名称是从流程定义中的serviceTask元素的实现属性中获取的:(https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-process-example/src/main/resources/processes/categorize-content.bpmn20.xml#L22)
<bpmn:serviceTask id="Task_1ylvdew" name="Process Content" implementation="processTextConnector">
这个新的连接器接口是JavaDelagates的自然进化,新版本的Activiti Core将尝试通过将它们封装在连接器实现中来重用您的JavaDelagates:
public interface Connector { IntegrationContext execute(IntegrationContext integrationContext); }
连接器接收一个带有流程变量的IntegrationContext,并返回一个经过修改的IntegrationContext,其中包含需要映射回流程变量的结果。
在前面的示例中,连接器实现正在接收一个“content”变量,并根据内容处理逻辑添加一个“approved”变量。
在这些连接器中,您可能包括系统到系统的调用,例如REST调用和基于消息的交互。这些交互往往变得越来越复杂,因此,
我们将在以后的教程中看到如何从ProcessRuntime(云连接器)上下文之外的运行中提取这些连接器,以分离ProcessRuntime作用域之外的这些外部交互的责任.
查看maven模块activity -api- Spring -integration-example,查看使用Spring integration基于文件轮询器启动进程的更高级示例。
Full Example
你可以找到一个使用ProcessRuntime和TaskRuntime api来自动化以下过程的例子:本节的代码可以在“activity -api-basic-full-example”maven模块中找到。
作为仅使用ProcessRuntime的示例,这也对一些输入内容进行了分类,但在本例中,流程依赖于一个Human Actor来决定是否批准内容。和前面一样,
我们有一个计划任务,它每5秒创建一个新的流程实例,还有一个模拟用户检查是否有可用的任务。
https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-full-example-bean/src/main/java/org/activiti/examples/DemoApplication.java#L80-L100
和
https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-full-example-bean/src/main/java/org/activiti/examples/DemoApplication.java#L102-L137
UserTask被创建给一组潜在的所有者,在本例中是“actititeam”组。但在本例中,我们没有像第一个示例中那样手动创建任务。流程实例在每次流程启动时为我们创建任务。
属于此组的用户将能够声明并处理该任务。
https://github.com/Activiti/Activiti/blob/develop/activiti-examples/activiti-api-basic-full-example-bean/src/main/resources/processes/categorize-human-content.bpmn20.xml#L38-L46
<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>
我们鼓励您运行这些示例并尝试使用它们,如果您有问题或发现问题,请与我们联系。
Summary
在本教程中,我们已经看到了如何开始使用来自新的Activiti Core Beta项目的新的ProcessRuntime和TaskRuntime API。
我们建议您查看Activiti Examples库,获取更多示例:https://github.com/Activiti/Activiti/tree/develop/activiti-examples
帮助我们编写更多这样的示例可能是一个非常好的初始社区贡献。如果您感兴趣,请联系我们,我们非常乐意为您提供指导。
一如既往,欢迎通过Gitter与我们联系:https://gitter.im/Activiti/Activiti7
更多的博客文章将介绍Runtime Admin api,以及如何调整这些示例,以便在我们新的Activiti Cloud方法中执行。