Integrating Activiti 7 with Spring Boot: Dependencies, Setup, and Advanced Workflow Operations
This article provides a step‑by‑step guide for integrating Activiti 7 workflow engine into a Spring Boot application, covering Maven dependencies, environment setup, process deployment, task handling, business keys, suspension/activation, candidate users, variables, gateways, and various advanced operations with complete code examples.
1. Dependencies
Add the Activiti Spring Boot starter and the Activiti image generator to your Maven pom.xml , excluding conflicting libraries such as commons-io , commons-lang3 , and mybatis as shown below.
org.activiti
activiti-spring-boot-starter
7.0.0.SR1
commons-io
commons-io
commons-lang3
org.apache.commons
mybatis
org.mybatis
org.activiti
activiti-image-generator
7.0.0.SR1
commons-io
commons-io2. Install Activiti Environment
Configure IntelliJ IDEA to avoid Chinese character garbling:
Set File → Settings → Editor → File Encodings to UTF‑8.
Add -Dfile.encoding=UTF-8 to custom VM options.
Append -Dfile.encoding=UTF-8 to idea.exe.vmoptions and idea64.exe.vmoptions files.
Restart IDEA.
3. Basic Usage
1. Create a BPMN file
Draw a simple process diagram using the Activiti designer plugin.
2. Deploy Process Definition
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;
public class ActivitiTest {
@Test
public void testDeploy() {
//创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//进行部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/leave.bpmn")
.addClasspathResource("bpmn/leave.png")
.name("请假流程")
.deploy();
//输出部署的一些信息
System.out.println("流程部署ID:"+deployment.getId());
System.out.println("流程部署名称:"+deployment.getName());
}
}3. Start Process Instance
@Test
public void testStartProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveProcess");
System.out.println("流程定义的id = " + instance.getProcessDefinitionId());
System.out.println("流程实例的id = " + instance.getId());
}4. Query Tasks
@Test
public void testSelectTodoTaskList() {
String assignee = "李四";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List
taskList = taskService.createTaskQuery()
.processDefinitionKey("leaveProcess")
.taskAssignee(assignee)
.list();
for (Task task : taskList) {
System.out.println("流程定义id = " + task.getProcessDefinitionId());
System.out.println("流程实例id = " + task.getProcessInstanceId());
System.out.println("任务id = " + task.getId());
System.out.println("任务名称 = " + task.getName());
}
}5. Complete Task
@Test
public void testCompleteTask() {
String assignee = "李四";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List
taskList = taskService.createTaskQuery()
.processDefinitionKey("leaveProcess")
.taskAssignee(assignee)
.list();
for (Task task : taskList) {
taskService.complete(task.getId());
}
}6. Add Approval Comment
@Test
public void testAddComment() {
String assignee = "王五";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List
taskList = taskService.createTaskQuery()
.processDefinitionKey("leaveProcess")
.taskAssignee(assignee)
.list();
for (Task task : taskList) {
taskService.addComment(task.getId(), task.getProcessInstanceId(), task.getName() + "审批通过");
taskService.complete(task.getId());
}
}7. View Historical Approvals
@Test
public void testSelectHistoryTask() {
String processInstanceId = "2501";
String taskAssignee = "王五";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
TaskService taskService = processEngine.getTaskService();
List
list = historyService
.createHistoricActivityInstanceQuery()
.activityType("userTask")
.processInstanceId(processInstanceId)
.taskAssignee(taskAssignee)
.finished()
.list();
for (HistoricActivityInstance instance : list) {
System.out.println("任务名称:" + instance.getActivityName());
System.out.println("任务开始时间:" + instance.getStartTime());
System.out.println("任务结束时间:" + instance.getEndTime());
System.out.println("任务耗时:" + instance.getDurationInMillis());
List
taskComments = taskService.getTaskComments(instance.getTaskId());
if (taskComments.size() > 0) {
System.out.println("审批批注:" + taskComments.get(0).getFullMessage());
}
}
}4. Advanced Operations
1. Process Definition Query
@Test
public void testDefinitionQuery() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
List
processDefinitionList = repositoryService
.createProcessDefinitionQuery()
.processDefinitionKey("leaveProcess")
.list();
for (ProcessDefinition definition : processDefinitionList) {
System.out.println("流程定义ID:" + definition.getId());
System.out.println("流程定义名称:" + definition.getName());
System.out.println("流程定义key:" + definition.getKey());
System.out.println("流程定义版本:" + definition.getVersion());
System.out.println("流程部署ID:" + definition.getDeploymentId());
System.out.println("====================");
}
}2. Download Process Resources
@Test
public void testDownloadResource() throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
List
list = repositoryService
.createProcessDefinitionQuery()
.processDefinitionKey("leaveProcess")
.orderByProcessDefinitionVersion()
.desc()
.list();
ProcessDefinition definition = list.get(0);
String deploymentId = definition.getDeploymentId();
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, definition.getResourceName());
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, definition.getDiagramResourceName());
FileOutputStream bpmnOutPut = new FileOutputStream("D:/leave.bpmn");
FileOutputStream pngOutPut = new FileOutputStream("D:/leave.png");
IOUtils.copy(bpmnInput, bpmnOutPut);
IOUtils.copy(pngInput, pngOutPut);
}3. Delete Process Definition
@Test
public void testDeleteDeploy() {
String deploymentId = "10001";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.deleteDeployment(deploymentId);
// repositoryService.deleteDeployment(deploymentId, true); // cascade delete if needed
}4. Business Key Usage
BusinessKey links a workflow instance to a business record (e.g., a leave request ID). It is set when starting a process and can be retrieved later to fetch related business data.
@Test
public void testStartProcess() {
String businessKey = "8001";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveProcess", businessKey);
System.out.println("流程定义的id = " + instance.getProcessDefinitionId());
System.out.println("流程实例的id = " + instance.getId());
} @Test
public void testGetBusinessKey() {
String assignee = "李四";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
RuntimeService runtimeService = processEngine.getRuntimeService();
List
taskList = taskService.createTaskQuery()
.processDefinitionKey("leaveProcess")
.taskAssignee(assignee)
.list();
for (Task task : taskList) {
ProcessInstance instance = runtimeService.createProcessInstanceQuery()
.processInstanceId(task.getProcessInstanceId())
.singleResult();
System.out.println("业务key:" + instance.getBusinessKey());
System.out.println("===================");
}
}5. Suspend / Activate Process Definitions and Instances
Suspending a definition pauses all its instances; activating resumes them. Individual instances can also be suspended or activated.
@Test
public void testSuspendAllProcessInstance() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService
.createProcessDefinitionQuery()
.processDefinitionKey("leaveProcess")
.singleResult();
boolean suspended = processDefinition.isSuspended();
System.out.println("流程定义状态:" + (suspended ? "已挂起" : "已激活"));
String processDefinitionId = processDefinition.getId();
if (suspended) {
repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
System.out.println("流程ID:" + processDefinitionId + ",已激活");
} else {
repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
System.out.println("流程ID:" + processDefinitionId + ",已挂起");
}
} @Test
public void testSuspendSingleProcessInstance() {
String processInstanceId = "2501";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
boolean suspended = processInstance.isSuspended();
System.out.println("流程实例ID:" + processInstanceId + ",状态:" + (suspended ? "已挂起" : "已激活"));
if (suspended) {
runtimeService.activateProcessInstanceById(processInstanceId);
System.out.println("流程实例ID:" + processInstanceId + ",状态修改为已激活");
} else {
runtimeService.suspendProcessInstanceById(processInstanceId);
System.out.println("流程实例ID:" + processInstanceId + ",状态修改为已挂起");
}
}6. Task Assignment Strategies
Assignments can be fixed, expression‑based, or handled by listeners. Example listener implementation:
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class AssigneeTaskListener implements TaskListener {
public void notify(DelegateTask delegateTask) {
if (delegateTask.getName().equals("部门经理审批")) {
delegateTask.setAssignee("赵六");
} else if (delegateTask.getName().equals("部门经理审批")) {
delegateTask.setAssignee("孙七");
}
}
}7. Process Variables
Variables drive conditional flow. They can be set at start or during execution and accessed via UEL expressions such as ${assignee} or ${price<10000} .
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class VariablesTest {
@Test
public void testDeploy() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/leave-variables.bpmn")
.name("请假流程")
.deploy();
System.out.println("流程部署ID:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
@Test
public void testStartProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map
variables = new HashMap<>();
variables.put("day", 2);
ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveVariablesProcess", variables);
System.out.println("流程定义的id = " + instance.getProcessDefinitionId());
System.out.println("流程实例的id = " + instance.getId());
}
@Test
public void testSelectTodoTaskList() {
String assignee = "李四";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List
taskList = taskService.createTaskQuery()
.processDefinitionKey("leaveVariablesProcess")
.taskAssignee(assignee)
.list();
for (Task task : taskList) {
System.out.println("流程定义id = " + task.getProcessDefinitionId());
System.out.println("流程实例id = " + task.getProcessInstanceId());
System.out.println("任务id = " + task.getId());
System.out.println("任务名称 = " + task.getName());
}
}
@Test
public void testCompleteTask() {
String assignee = "李四";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List
taskList = taskService.createTaskQuery()
.processDefinitionKey("leaveVariablesProcess")
.taskAssignee(assignee)
.list();
for (Task task : taskList) {
taskService.complete(task.getId());
}
}
}8. Candidate Users and Task Claiming
Define multiple candidates using the candidate-users attribute, then claim a task before completing it.
@Test
public void testSelectCandidateTaskList() {
String candidateUser = "李四";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List
taskList = taskService.createTaskQuery()
.processDefinitionKey("leaveCandidateProcess")
.taskCandidateUser(candidateUser)
.list();
for (Task task : taskList) {
System.out.println("流程定义id = " + task.getProcessDefinitionId());
System.out.println("流程实例id = " + task.getProcessInstanceId());
System.out.println("任务id = " + task.getId());
System.out.println("任务名称 = " + task.getName());
}
} @Test
public void testClaimTask() {
String taskId = "2505";
String assignee = "张三";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
taskService.claim(taskId, assignee);
}9. Gateways
Examples of exclusive, parallel, and inclusive gateways are provided, demonstrating conditional routing based on process variables such as ${day > 3} .
@Test
public void testDeploy() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/leave-EGateway.bpmn")
.name("请假流程-排他网关")
.deploy();
System.out.println("流程部署ID:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
@Test
public void testStartProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map
variables = new HashMap<>();
variables.put("day", 0);
ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveEGatewayProcess", variables);
System.out.println("流程定义的id = " + instance.getProcessDefinitionId());
System.out.println("流程实例的id = " + instance.getId());
}5. Service Overview
The main Activiti services used are:
RepositoryService : Deploy and manage process definitions and resources.
RuntimeService : Start processes and query runtime state.
TaskService : Query, claim, complete, and comment on tasks.
HistoryService : Access historical data such as completed tasks and activity instances.
ManagementService : Engine administration (e.g., job management).
6. Common Operations (Code Snippets)
Deploy a process: repositoryService.createDeployment().addClasspathResource("bpmn/xxx.bpmn").deploy();
Start a process: runtimeService.startProcessInstanceByKey("processKey", variables);
Query tasks: taskService.createTaskQuery().list();
Complete a task: taskService.complete(taskId);
Claim a task: taskService.claim(taskId, userId);
Add a comment: taskService.addComment(taskId, processInstanceId, "comment");
Suspend/activate definition: repositoryService.suspendProcessDefinitionByKey(...); repositoryService.activateProcessDefinitionByKey(...);
Suspend/activate instance: runtimeService.suspendProcessInstanceById(...); runtimeService.activateProcessInstanceById(...);
Delete deployment: repositoryService.deleteDeployment(deploymentId, true);
Query definitions: repositoryService.createProcessDefinitionQuery().list();
Query instances: runtimeService.createProcessInstanceQuery().list();
Query historic tasks: historyService.createHistoricTaskInstanceQuery().list();
By following the steps and code examples above, developers can fully integrate Activiti 7 into Spring Boot projects, manage workflows, handle tasks, and leverage advanced features such as business keys, variables, gateways, and candidate user assignments.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.