Spring Boot + Activiti示例 - Websparrow


在本教程中,我们将演示Spring Boot + Activiti示例。Activiti是一个开源工作流引擎,可以执行BPMN 2.0中描述的业务流程。Activiti引擎的核心目标是采用由人工任务和服务调用组成的流程定义,并按特定顺序执行。
在这里,我们将设计一个BMPN工作流程图和Spring Boot应用程序,它有助于管理流程,如下所示:

然后我们将使用Spring JPA创建员工列表并将其详细信息存储到数据库中,并通过调用Activiti API将任务分配给员工。员工将完成第一项任务和第二项任务。

技术列表:

  1. Spring Tool Suite 3
  2. JDK 8
  3. Spring Boot 1.5.3.RELEASE
  4. Activiti 5.22.0
  5. H2(内存中)数据库
  6. Spring JPA

使用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="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="Examples">
  <process id=
"simple-process" name="Simple Process" isExecutable="true">
    <startEvent id=
"start" name="Start"></startEvent>
    <userTask id=
"userTask1" name="User Task 1" activiti:assignee="${employee.name}">
      <documentation>Complete user task 1 first.</documentation>
    </userTask>
    <userTask id=
"userTask2" name="User Task 2" activiti:assignee="${employee.name}">
      <documentation>Work for the second task.</documentation>
    </userTask>
    <endEvent id=
"theEnd"></endEvent>
    <sequenceFlow id=
"flow1" sourceRef="userTask2" targetRef="theEnd"></sequenceFlow>
    <sequenceFlow id=
"flow3" sourceRef="userTask1" targetRef="userTask2"></sequenceFlow>
    <sequenceFlow id=
"flow4" sourceRef="start" targetRef="userTask1"></sequenceFlow>
  </process>
</definitions>

activiti:assignee属性 ${employee.name}是被分配到任务的雇员。

模型和存储库类
创建Employee数据模型类。


@Entity
public class Employee {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String designation;
// generate getters and setters...

    public Employee() {
    }

    public Employee(String name, String designation) {

        this.name = name;
        this.designation = designation;
    }
}

创建EmployeeRepository实现接口JpaRepository<T, ID>的findByName(Stringname)Employee方法,实现从数据库查询的雇员。


public interface EmployeeRepository extends JpaRepository<Employee, Long> {

    public Employee findByName(String name);

}

服务类
EmployeeService班负责员工加入到数据库中。应用程序启动时将调用此服务类。

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    // create the list of Employees into the database who perform the task
    public void createEmployee() {

        if (employeeRepository.findAll().size() == 0) {

            employeeRepository.save(new Employee(
"Prince", "Software Enginner"));
            employeeRepository.save(new Employee(
"Gaurav", "Technical Lead"));
            employeeRepository.save(new Employee(
"Abhinav", "Test Lead"));
        }
    }
}

而ProcessService类是负责启动的过程中,给员工分配任务,检索分配给员工的任务,并通过ID完成特定的任务。


@Service
public class ProcessService {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RepositoryService repositoryService;

    // start the process and set employee as variable
    public String startTheProcess(String assignee) {

        Employee employee = employeeRepository.findByName(assignee);

        Map<String, Object> variables = new HashMap<>();
        variables.put(
"employee", employee);

        runtimeService.startProcessInstanceByKey(
"simple-process", variables);

        return processInformation();
    }

    
// fetching process and task information
    public String processInformation() {

        List<Task> taskList = taskService.createTaskQuery().orderByTaskCreateTime().asc().list();

        StringBuilder processAndTaskInfo = new StringBuilder();
        
        processAndTaskInfo.append(
"Number of process definition available: "
                + repositoryService.createProcessDefinitionQuery().count() +
" | Task Details= ");

        taskList.forEach(task -> {

            processAndTaskInfo.append(
"ID: " + task.getId() + ", Name: " + task.getName() + ", Assignee: "
                    + task.getAssignee() +
", Description: " + task.getDescription());
        });

        return processAndTaskInfo.toString();
    }

    
// fetch task assigned to employee
    public List<Task> getTasks(String assignee) {
        return taskService.createTaskQuery().taskAssignee(assignee).list();
    }

    
// complete the task
    public void completeTask(String taskId) {
        taskService.complete(taskId);
    }
}

控制器类
ProcessController类处理HTTP请求,调用相应的ProcessService类的方法,和响应的具体结果。

@RestController
public class ProcessController {

    @Autowired
    private ProcessService processService;

    /*
     * Method will start the Activiti process engine and set employee to perform
     * the task
     */

    @RequestMapping(value =
"/process")
    public String startProcessInstance(@RequestParam String assignee) {
        return processService.startTheProcess(assignee);
    }

    
// Retrieve the tasks assigned to an employee
    @RequestMapping(value =
"/tasks")
    public String getTasks(@RequestParam String assignee) {
        List<Task> tasks = processService.getTasks(assignee);
        return tasks.toString();
    }

    
// Complete the task by their ID
    @RequestMapping(value =
"/completetask")
    public String completeTask(@RequestParam String taskId) {
        processService.completeTask(taskId);
        return
"Task with id " + taskId + " has been completed!";
    }
}

运行应用程序
最后,创建一个App类,该类调用在启动应用程序时创建员工EmployeeSerice的createEmployee()方法。

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Bean
    public CommandLineRunner init(final EmployeeService employeeService) {

        return new CommandLineRunner() {
            public void run(String... strings) throws Exception {
                employeeService.createEmployee();
            }
        };
    }
}

要使用用户标识和密码保护您的应用程序,请在App类中添加以下代码。

@Bean
InitializingBean usersAndGroupsInitializer(final IdentityService identityService) {

    return new InitializingBean() {
        public void afterPropertiesSet() throws Exception {

            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);
        }
    };
}


测试应用程序

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