在本教程中,我们将演示Spring Boot + Activiti示例。Activiti是一个开源工作流引擎,可以执行 BPMN 2.0中 描述的业务流程。Activiti引擎的核心目标是采用由人工任务和服务调用组成的流程定义,并按特定顺序执行。
在这里,我们将设计一个 BMPN工作流程图 和Spring Boot应用程序,它有助于管理流程,如下所示:
然后我们将使用Spring JPA创建员工列表并将其详细信息存储到数据库中,并通过调用Activiti API将任务分配给员工。员工将完成第一项任务和第二项任务。
技术列表:
使用Spring Boot + Activiti工作流流程引擎需要以下依赖项。将以下内容添加到您的pom.xml中。
<properties> <java.version>1.8</java.version> <activiti.version>5.22.0</activiti.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter-basic</artifactId> <version>${activiti.version}</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter-jpa</artifactId> <version>${activiti.version}</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> </dependencies>
BPMN流程定义
将BPMN 2.0流程定义放入src / main / resources / processes文件夹中。此处放置的所有进程将自动部署(即解析并使其可执行)到Activiti引擎。流程定义文件扩展名可以是bpmn20.xml或bpmn,如simple-process.bpmn20.xml或simple-process.bpmn。(这是由Activiti可视化界面生成的xml文件)
<?xml version=<font>"1.0"</font><font> encoding=</font><font>"UTF-8"</font><font>?> <definitions xmlns=</font><font>"http://www.omg.org/spec/BPMN/20100524/MODEL"</font><font> xmlns:xsi=</font><font>"http://www.w3.org/2001/XMLSchema-instance"</font><font> xmlns:xsd=</font><font>"http://www.w3.org/2001/XMLSchema"</font><font> xmlns:activiti=</font><font>"http://activiti.org/bpmn"</font><font> xmlns:bpmndi=</font><font>"http://www.omg.org/spec/BPMN/20100524/DI"</font><font> xmlns:omgdc=</font><font>"http://www.omg.org/spec/DD/20100524/DC"</font><font> xmlns:omgdi=</font><font>"http://www.omg.org/spec/DD/20100524/DI"</font><font> typeLanguage=</font><font>"http://www.w3.org/2001/XMLSchema"</font><font> expressionLanguage=</font><font>"http://www.w3.org/1999/XPath"</font><font> targetNamespace=</font><font>"Examples"</font><font>> <process id=</font><font>"simple-process"</font><font> name=</font><font>"Simple Process"</font><font> isExecutable=</font><font>"true"</font><font>> <startEvent id=</font><font>"start"</font><font> name=</font><font>"Start"</font><font>></startEvent> <userTask id=</font><font>"userTask1"</font><font> name=</font><font>"User Task 1"</font><font> activiti:assignee=</font><font>"${employee.name}"</font><font>> <documentation>Complete user task 1 first.</documentation> </userTask> <userTask id=</font><font>"userTask2"</font><font> name=</font><font>"User Task 2"</font><font> activiti:assignee=</font><font>"${employee.name}"</font><font>> <documentation>Work <b>for</b> the second task.</documentation> </userTask> <endEvent id=</font><font>"theEnd"</font><font>></endEvent> <sequenceFlow id=</font><font>"flow1"</font><font> sourceRef=</font><font>"userTask2"</font><font> targetRef=</font><font>"theEnd"</font><font>></sequenceFlow> <sequenceFlow id=</font><font>"flow3"</font><font> sourceRef=</font><font>"userTask1"</font><font> targetRef=</font><font>"userTask2"</font><font>></sequenceFlow> <sequenceFlow id=</font><font>"flow4"</font><font> sourceRef=</font><font>"start"</font><font> targetRef=</font><font>"userTask1"</font><font>></sequenceFlow> </process> </definitions> </font>
activiti:assignee属性 ${employee.name}是被分配到任务的雇员。
模型和存储库类
创建Employee数据模型类。
@Entity <b>public</b> <b>class</b> Employee { @Id @GeneratedValue <b>private</b> Long id; <b>private</b> String name; <b>private</b> String designation; <font><i>// generate getters and setters...</i></font><font> <b>public</b> Employee() { } <b>public</b> Employee(String name, String designation) { <b>this</b>.name = name; <b>this</b>.designation = designation; } } </font>
创建EmployeeRepository实现接口JpaRepository<T, ID>的findByName(String name )Employee方法,实现从数据库查询的雇员。
<b>public</b> <b>interface</b> EmployeeRepository <b>extends</b> JpaRepository<Employee, Long> { <b>public</b> Employee findByName(String name); }
服务类
EmployeeService班负责员工加入到数据库中。应用程序启动时将调用此服务类。
@Service <b>public</b> <b>class</b> EmployeeService { @Autowired <b>private</b> EmployeeRepository employeeRepository; <font><i>// create the list of Employees into the database who perform the task</i></font><font> <b>public</b> <b>void</b> createEmployee() { <b>if</b> (employeeRepository.findAll().size() == 0) { employeeRepository.save(<b>new</b> Employee(</font><font>"Prince"</font><font>, </font><font>"Software Enginner"</font><font>)); employeeRepository.save(<b>new</b> Employee(</font><font>"Gaurav"</font><font>, </font><font>"Technical Lead"</font><font>)); employeeRepository.save(<b>new</b> Employee(</font><font>"Abhinav"</font><font>, </font><font>"Test Lead"</font><font>)); } } } </font>
而ProcessService类是负责启动的过程中,给员工分配任务,检索分配给员工的任务,并通过ID完成特定的任务。
@Service <b>public</b> <b>class</b> ProcessService { @Autowired <b>private</b> EmployeeRepository employeeRepository; @Autowired <b>private</b> RuntimeService runtimeService; @Autowired <b>private</b> TaskService taskService; @Autowired <b>private</b> RepositoryService repositoryService; <font><i>// start the process and set employee as variable</i></font><font> <b>public</b> String startTheProcess(String assignee) { Employee employee = employeeRepository.findByName(assignee); Map<String, Object> variables = <b>new</b> HashMap<>(); variables.put(</font><font>"employee"</font><font>, employee); runtimeService.startProcessInstanceByKey(</font><font>"simple-process"</font><font>, variables); <b>return</b> processInformation(); } </font><font><i>// fetching process and task information</i></font><font> <b>public</b> String processInformation() { List<Task> taskList = taskService.createTaskQuery().orderByTaskCreateTime().asc().list(); StringBuilder processAndTaskInfo = <b>new</b> StringBuilder(); processAndTaskInfo.append(</font><font>"Number of process definition available: "</font><font> + repositoryService.createProcessDefinitionQuery().count() + </font><font>" | Task Details= "</font><font>); taskList.forEach(task -> { processAndTaskInfo.append(</font><font>"ID: "</font><font> + task.getId() + </font><font>", Name: "</font><font> + task.getName() + </font><font>", Assignee: "</font><font> + task.getAssignee() + </font><font>", Description: "</font><font> + task.getDescription()); }); <b>return</b> processAndTaskInfo.toString(); } </font><font><i>// fetch task assigned to employee</i></font><font> <b>public</b> List<Task> getTasks(String assignee) { <b>return</b> taskService.createTaskQuery().taskAssignee(assignee).list(); } </font><font><i>// complete the task</i></font><font> <b>public</b> <b>void</b> completeTask(String taskId) { taskService.complete(taskId); } } </font>
控制器类
ProcessController类处理HTTP请求,调用相应的ProcessService类的方法,和响应的具体结果。
@RestController <b>public</b> <b>class</b> ProcessController { @Autowired <b>private</b> ProcessService processService; <font><i>/* * Method will start the Activiti process engine and set employee to perform * the task */</i></font><font> @RequestMapping(value = </font><font>"/process"</font><font>) <b>public</b> String startProcessInstance(@RequestParam String assignee) { <b>return</b> processService.startTheProcess(assignee); } </font><font><i>// Retrieve the tasks assigned to an employee</i></font><font> @RequestMapping(value = </font><font>"/tasks"</font><font>) <b>public</b> String getTasks(@RequestParam String assignee) { List<Task> tasks = processService.getTasks(assignee); <b>return</b> tasks.toString(); } </font><font><i>// Complete the task by their ID</i></font><font> @RequestMapping(value = </font><font>"/completetask"</font><font>) <b>public</b> String completeTask(@RequestParam String taskId) { processService.completeTask(taskId); <b>return</b> </font><font>"Task with id "</font><font> + taskId + </font><font>" has been completed!"</font><font>; } } </font>
运行应用程序
最后,创建一个App类,该类调用在启动应用程序时创建员工EmployeeSerice的createEmployee()方法。
@SpringBootApplication <b>public</b> <b>class</b> App { <b>public</b> <b>static</b> <b>void</b> main(String[] args) { SpringApplication.run(App.<b>class</b>, args); } @Bean <b>public</b> CommandLineRunner init(<b>final</b> EmployeeService employeeService) { <b>return</b> <b>new</b> CommandLineRunner() { <b>public</b> <b>void</b> run(String... strings) throws Exception { employeeService.createEmployee(); } }; } }
要使用用户标识和密码保护您的应用程序,请在App类中添加以下代码。
@Bean InitializingBean usersAndGroupsInitializer(<b>final</b> IdentityService identityService) { <b>return</b> <b>new</b> InitializingBean() { <b>public</b> <b>void</b> afterPropertiesSet() throws Exception { Group group = identityService.newGroup(<font>"user"</font><font>); group.setName(</font><font>"users"</font><font>); group.setType(</font><font>"security-role"</font><font>); identityService.saveGroup(group); User admin = identityService.newUser(</font><font>"admin"</font><font>); admin.setPassword(</font><font>"admin"</font><font>); identityService.saveUser(admin); } }; } </font>
测试应用程序
1. 分配任务给员工:
http://localhost:8080/process?assignee=Prince
2. 显示分配给Prince的任务
http://localhost:8080/tasks?assignee=Prince
3. 按任务ID完成分配给Prince的任务。
http://localhost:8080/completetask?taskId=9
4. 再次检查分配给Prince的任务
http://localhost:8080/tasks?assignee=Prince
5. 再次完成任务
http://localhost:8080/completetask?taskId=12