In this article, we will cover how to integrate a workflow engine into a Spring Boot application. We will use Activiti as the workflow engine, which is an open source workflow engine based on the Java language. This article assumes that you already understand the basic concepts of Spring Boot and Activiti.
1. Create a Spring Boot project
First, we need to create a new Spring Boot project. You can use Spring Initializr to generate a basic Spring Boot project structure. Select the following dependencies:
- Web
- JPA
- H2
- activity
Then, import the generated project into your favorite IDE.
2. Configure Activiti
src/main/resources
Create a activiti.cfg.xml
configuration file named in the directory with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="databaseSchemaUpdate" value="true"/>
<property name="asyncExecutorActivate" value="false"/>
</bean>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"/>
</bean>
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
<bean id="managementService" factory-bean="processEngine" factory-method="getManagementService"/>
</beans>
This configuration file defines some basic configuration required by the Activiti engine. We used a Spring data source and transaction manager to manage the connection to the database.
Next, we need to application.properties
configure the database connection information in the file. Since we are using H2 in-memory database, just add the following:
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
3. Create a simple workflow
We will create a simple workflow for employee leave requests. First, src/main/resources/processes
create a leave.bpmn20.xml
file named in the directory with the following content:
<?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"
targetNamespace="http://www.activiti.org/test">
<process id="leave" name="Leave Process">
<startEvent id="start"/>
<sequenceFlow id="flow1" sourceRef="start" targetRef="apply"/>
<userTask id="apply" name="Apply for leave" activiti:assignee="${applicant}">
<documentation>
Employee applies for leave
</documentation>
</userTask>
<sequenceFlow id="flow2" sourceRef="apply" targetRef="approve"/>
<userTask id="approve" name="Approve leave" activiti:candidateGroups="managers">
<documentation>
Manager approves or rejects leave
</documentation>
</userTask>
<sequenceFlow id="flow3" sourceRef="approve" targetRef="end"/>
<endEvent id="end"/>
</process>
</definitions>
This simple workflow contains two user tasks: the employee applies for leave (apply) and the manager approves the leave (approve). We use ${applicant}
and managers
to represent the applicant and manager roles respectively.
4. Create data model
In order to handle employee leave requests, we need to create a LeaveApplication
data model. src/main/java/com/example/workflow/model
Create a file named in the directory LeaveApplication.java
with the following content:
package com.example.workflow.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class LeaveApplication {
@Id
@GeneratedValue
private Long id;
private String applicant;
private String reason;
private int days;
private String status;
// Getters and setters
// ...
}
This entity class contains basic information about leave applications, such as the applicant, reason for leave, number of days of leave, and approval status.
5. Create service class
Next, we need to create a service class to handle workflow-related operations. src/main/java/com/example/workflow/service
Create a file named in the directory WorkflowService.java
with the following content:
package com.example.workflow.service;
import com.example.workflow.model.LeaveApplication;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class WorkflowService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
public String startProcess(LeaveApplication leaveApplication) {
Map<String, Object> variables = new HashMap<>();
variables.put("applicant", leaveApplication.getApplicant());
runtimeService.startProcessInstanceByKey("leave", variables);
return "Process started";
}
public List<Task> getTasks(String assignee) {
return taskService.createTaskQuery().taskAssignee(assignee).list();
}
public void completeTask(String taskId) {
taskService.complete(taskId);
}
}
In this service class, we injected Activiti's RuntimeService
and TaskService
. startProcess
The method is used to start the workflow, getTasks
obtain the to-do tasks of the specified user, and completeTask
complete the tasks.
6. Create a controller
Finally, we need to create a controller to handle HTTP requests. src/main/java/com/example/workflow/controller
Create a file named in the directory WorkflowController.java
with the following content:
package com.example.workflow.controller;
import com.example.workflow.model.LeaveApplication;
import com.example.workflow.service.WorkflowService;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class WorkflowController {
@Autowired
private WorkflowService workflowService;
@PostMapping("/start-process")
public String startProcess(@RequestBody LeaveApplication leaveApplication) {
return workflowService.startProcess(leaveApplication);
}
@GetMapping("/tasks/{assignee}")
public List<Task> getTasks(@PathVariable String assignee) {
return workflowService.getTasks(assignee);
}
@PostMapping("/complete-task/{taskId}")
public void completeTask(@PathVariable String taskId) {
workflowService.completeTask(taskId);
}
}
This controller contains three HTTP endpoints, which are used to start the workflow, get the to-do tasks, and complete the tasks.
At this point, we have completed the integration of workflow in the Spring Boot project. You can run the project and test the API using an HTTP client such as Postman. Please note that more complex business logic and error handling may need to be handled in actual projects.
Summarize
In this article, we introduce how to integrate the Activiti workflow engine into a Spring Boot project and create a simple leave application workflow. By using Activiti, we can easily manage business processes and related tasks. I hope this article helped you understand how to integrate workflows in Spring Boot projects.