Spring Activiti 在完成任务前验证 assignee 或 candidateGroups
Spring Activiti verify assignee or candidateGroups before completing task
我正在与 Spring Acitviti
一起管理项目的工作流程。我是 Activiti 的新手,我正在尝试让它与自定义用户群一起工作。以下是我正在使用的示例项目
https://github.com/ConsciousObserver/AcitvitySpringTest.git
目前我正在尝试限制可以在进程 simple-test-process
中执行特定任务 taskA
的用户。
调用taskService.complete(task.getId())
Activiti 似乎完全忽略了任务分配给谁。由于项目中还没有配置安全性,并且 taskA
被分配给 Hello World
它应该会失败,因为匿名用户正在尝试执行它。
activity是否需要我们在执行任务前手动检查assignee
、candidateUsers
、candidateGroups
?
如果不是,那么我们如何使用指示 Activiti 来仅让特定用户完成任务。
包括下面的相关代码
简单测试-process.bpmn图表
简单测试-process.bpmn
<?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.example.org/test">
<process id="simple-test-process" name="simple-test-process">
<startEvent id="startEvent" name="startEvent"></startEvent>
<sequenceFlow id="sequenceFlow1" targetRef="initTask" sourceRef="startEvent" />
<serviceTask id="initTask" name="initTask" activiti:expression="${myService.init(photos)}"></serviceTask>
<sequenceFlow targetRef="taskA" sourceRef="initTask"></sequenceFlow>
<userTask id="taskA" name="taskA" activiti:assignee="Hello World" ></userTask>
<sequenceFlow id="sequenceFlow2" targetRef="taskB" sourceRef="taskA"></sequenceFlow>
<userTask id="taskB" name="taskB" activiti:assignee="$INITIATOR"></userTask>
<sequenceFlow id="sequenceFlow3" targetRef="endEvent" sourceRef="taskB" />
<endEvent id="endEvent" name="endEvent"></endEvent>
</process>
</definitions>
ActivitiTestApplication.java
package com.example;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class ActivitiTestApplication {
public static void main(String[] args) {
SpringApplication.run(ActivitiTestApplication.class, args);
}
@Bean
InitializingBean usersAndGroupsInitializer(final IdentityService identityService) {
return () -> {
Group group = identityService.newGroup("user");
group.setName("users");
group.setType("security-role");
identityService.saveGroup(group);
User admin = identityService.newUser("admin");
admin.setPassword("admin");
identityService.saveUser(admin);
};
}
}
@RestController
class ProcessRest {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@GetMapping("/start")
public List<Map<String, String>> start() {
List<String> photos = Arrays.asList("photo1", "photo2");
runtimeService.startProcessInstanceByKey("simple-test-process", Collections.singletonMap("photos", photos));
long runningProcessCount = runtimeService.createProcessInstanceQuery().count();
List<ProcessInstance> processes = runtimeService.createProcessInstanceQuery().list();
return processes
.stream()
.map(p -> getMap(p.getId(), p.getProcessInstanceId(), p.getProcessDefinitionName()))
.collect(Collectors.toList());
}
@GetMapping("/getTasks/{processInstanceId}")
public List<Map<String, String>> getTasks(@PathVariable String processInstanceId) {
List<Task> tasks = taskService
.createTaskQuery()
.processInstanceId(processInstanceId)
.list();
return tasks
.stream()
.map(t -> getMap(t.getId(), t.getProcessInstanceId(), t.getName()))
.collect(Collectors.toList());
}
@GetMapping("/completeTask/{processInstanceId}")
public Map<String, String> completeNextTask(@PathVariable String processInstanceId) {
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)
.singleResult();
if(task == null) {
throw new RuntimeException("No pending task for this processInstance");
}
System.out.println("variables: " + task.getProcessVariables());
taskService.complete(task.getId());
return getMap(task.getId(), task.getProcessInstanceId(), task.getName());
}
public Map<String, String> getMap(String id, String instanceId, String name) {
Map<String, String> map = new HashMap<>();
map.put("id", id);
map.put("processInstanceId", instanceId);
map.put("name", name);
return map;
}
}
@Component
class MyService {
public void init(List<String> photos) {
System.out.println("################################### Running Init Task ########################");
for(String photo: photos) {
System.out.println("Photo name: " + photo);
}
}
public String processPhoto(List<String> photos) {
for(String photo: photos) {
System.out.println("Photo name: " + photo);
}
return "processed";
}
}
不幸的是,没有魔法可以为您做到这一点,所以您需要验证这些事情,比如任务的受让人等等。
我打赌你会想要比硬编码 "Hello World" 更动态的东西,所以为了创建更动态的东西,作为一个简单的例子,我会把你的 /start
端点从 GET
到 POST
并检索受让人作为参数。
@PostMapping("/start")
public List<Map<String, String>> start(String assignee) {
并在 processVariables
中传递一个属性
类似于:
Map<String, Object> variables = Collections.singletonMap("photos", photos);
variables.put("person", assignee);
将您的 bpmn 从 activiti:assignee="Hello World"
更改为 activiti:assignee=${person}
并添加一个 TaskListener
来验证用户拥有的每个任务的受托人。
TaskListener
的例子你会发现 here
我正在与 Spring Acitviti
一起管理项目的工作流程。我是 Activiti 的新手,我正在尝试让它与自定义用户群一起工作。以下是我正在使用的示例项目
https://github.com/ConsciousObserver/AcitvitySpringTest.git
目前我正在尝试限制可以在进程 simple-test-process
中执行特定任务 taskA
的用户。
调用taskService.complete(task.getId())
Activiti 似乎完全忽略了任务分配给谁。由于项目中还没有配置安全性,并且 taskA
被分配给 Hello World
它应该会失败,因为匿名用户正在尝试执行它。
activity是否需要我们在执行任务前手动检查assignee
、candidateUsers
、candidateGroups
?
如果不是,那么我们如何使用指示 Activiti 来仅让特定用户完成任务。
包括下面的相关代码 简单测试-process.bpmn图表
简单测试-process.bpmn
<?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.example.org/test">
<process id="simple-test-process" name="simple-test-process">
<startEvent id="startEvent" name="startEvent"></startEvent>
<sequenceFlow id="sequenceFlow1" targetRef="initTask" sourceRef="startEvent" />
<serviceTask id="initTask" name="initTask" activiti:expression="${myService.init(photos)}"></serviceTask>
<sequenceFlow targetRef="taskA" sourceRef="initTask"></sequenceFlow>
<userTask id="taskA" name="taskA" activiti:assignee="Hello World" ></userTask>
<sequenceFlow id="sequenceFlow2" targetRef="taskB" sourceRef="taskA"></sequenceFlow>
<userTask id="taskB" name="taskB" activiti:assignee="$INITIATOR"></userTask>
<sequenceFlow id="sequenceFlow3" targetRef="endEvent" sourceRef="taskB" />
<endEvent id="endEvent" name="endEvent"></endEvent>
</process>
</definitions>
ActivitiTestApplication.java
package com.example;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class ActivitiTestApplication {
public static void main(String[] args) {
SpringApplication.run(ActivitiTestApplication.class, args);
}
@Bean
InitializingBean usersAndGroupsInitializer(final IdentityService identityService) {
return () -> {
Group group = identityService.newGroup("user");
group.setName("users");
group.setType("security-role");
identityService.saveGroup(group);
User admin = identityService.newUser("admin");
admin.setPassword("admin");
identityService.saveUser(admin);
};
}
}
@RestController
class ProcessRest {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@GetMapping("/start")
public List<Map<String, String>> start() {
List<String> photos = Arrays.asList("photo1", "photo2");
runtimeService.startProcessInstanceByKey("simple-test-process", Collections.singletonMap("photos", photos));
long runningProcessCount = runtimeService.createProcessInstanceQuery().count();
List<ProcessInstance> processes = runtimeService.createProcessInstanceQuery().list();
return processes
.stream()
.map(p -> getMap(p.getId(), p.getProcessInstanceId(), p.getProcessDefinitionName()))
.collect(Collectors.toList());
}
@GetMapping("/getTasks/{processInstanceId}")
public List<Map<String, String>> getTasks(@PathVariable String processInstanceId) {
List<Task> tasks = taskService
.createTaskQuery()
.processInstanceId(processInstanceId)
.list();
return tasks
.stream()
.map(t -> getMap(t.getId(), t.getProcessInstanceId(), t.getName()))
.collect(Collectors.toList());
}
@GetMapping("/completeTask/{processInstanceId}")
public Map<String, String> completeNextTask(@PathVariable String processInstanceId) {
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)
.singleResult();
if(task == null) {
throw new RuntimeException("No pending task for this processInstance");
}
System.out.println("variables: " + task.getProcessVariables());
taskService.complete(task.getId());
return getMap(task.getId(), task.getProcessInstanceId(), task.getName());
}
public Map<String, String> getMap(String id, String instanceId, String name) {
Map<String, String> map = new HashMap<>();
map.put("id", id);
map.put("processInstanceId", instanceId);
map.put("name", name);
return map;
}
}
@Component
class MyService {
public void init(List<String> photos) {
System.out.println("################################### Running Init Task ########################");
for(String photo: photos) {
System.out.println("Photo name: " + photo);
}
}
public String processPhoto(List<String> photos) {
for(String photo: photos) {
System.out.println("Photo name: " + photo);
}
return "processed";
}
}
不幸的是,没有魔法可以为您做到这一点,所以您需要验证这些事情,比如任务的受让人等等。
我打赌你会想要比硬编码 "Hello World" 更动态的东西,所以为了创建更动态的东西,作为一个简单的例子,我会把你的 /start
端点从 GET
到 POST
并检索受让人作为参数。
@PostMapping("/start")
public List<Map<String, String>> start(String assignee) {
并在 processVariables
类似于:
Map<String, Object> variables = Collections.singletonMap("photos", photos);
variables.put("person", assignee);
将您的 bpmn 从 activiti:assignee="Hello World"
更改为 activiti:assignee=${person}
并添加一个 TaskListener
来验证用户拥有的每个任务的受托人。
TaskListener
的例子你会发现 here