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.
<!--添加activiti和SpringBoot整合的依赖
MyBatis版本会有冲突,所以需要排除,所需数据库的依赖根据需求添加-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.0.0.SR1</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
<exclusion>
<artifactId>commons-lang3</artifactId>
<groupId>org.apache.commons</groupId>
</exclusion>
<exclusion>
<artifactId>mybatis</artifactId>
<groupId>org.mybatis</groupId>
</exclusion>
</exclusions>
</dependency>
<!--activiti可以绘制流程的的依赖-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-image-generator</artifactId>
<version>7.0.0.SR1</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
</exclusions>
</dependency>2. 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<Task> 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<Task> 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<Task> 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<HistoricActivityInstance> 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<Comment> 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<ProcessDefinition> 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<ProcessDefinition> 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<Task> 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<String, Object> 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<Task> 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<Task> 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<Task> 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<String, Object> 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
