Master Flowable: Deploy, Model, and Run BPMN Workflows with Spring Boot
This guide walks through installing Flowable 6.6.0, deploying its UI, modeling a leave‑approval process, exporting the BPMN file, configuring a Spring Boot backend, understanding Flowable's database tables, and using the engine's APIs to start, query, and complete workflow tasks.
Overview
Use Flowable's built‑in flowable‑ui to create process diagrams.
Develop Spring Boot interfaces to implement the process business logic.
1. Deploy flowable‑ui
Run the official Flowable 6.6.0 demo.
Reference documentation:
https://flowable.com/open-source/docs/bpmn/ch14-Applications/
1. Download Flowable 6.6.0 from GitHub:
https://github.com/flowable/flowable-engine/releases/download/flowable-6.6.0/flowable-6.6.0.zip2. Deploy flowable-6.6.0\wars\flowable-ui.war to Tomcat.
3. Open http://localhost:8080/flowable-ui and log in with admin/test .
4. In APP.MODELER create the process, export the BPMN file, or edit
apache-tomcat-9.0.37/webapps/flowable-ui/WEB-INF/classes/flowable-default.propertiesto connect to a local database.
Note: copy the MySQL driver mysql-connector-java-5.1.45.jar to apache-tomcat-9.0.37/webapps/flowable-rest/WEB-INF/lib .
After this, the backend program can directly use the created process.
2. Draw Process Diagram
In flowable‑ui > APP.MODELER draw the diagram as shown above. Key concepts:
Event – models lifecycle moments, shown as start/end circles.
Sequence flow – connector between elements, shown as arrows.
Gateway – controls flow direction, shown as a diamond with an X.
User task – models work that requires human execution, shown as a rectangle.
A simple workflow proceeds from the start node to a student task, then a teacher task, a gateway that checks the teacher's decision, optionally to a principal task, and finally to the end node.
Drawing details
1. Preserve the process model.
2. Sequence flows can have conditions (example gateway).
3. Assign tasks to candidate groups or specific users.
Finally export the workflow file.
File 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-insmtece" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.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="http://www.flowable.org/processdef">
<process id="leave_approval" name="请假审批" isExecutable="true">
<startEvent id="start" name="开始" flowable:initiator="startuser" flowable:formFieldValidation="true"/>
<userTask id="stu_task" name="学生" flowable:candidateGroups="stu_group" flowable:formFieldValidation="true"/>
<sequenceFlow id="flow1" sourceRef="start" targetRef="stu_task"/>
<userTask id="te_task" name="老师" flowable:candidateGroups="te_group" flowable:formFieldValidation="true"/>
<exclusiveGateway id="getway1" name="网关1"/>
<userTask id="mte_task" name="校长" flowable:candidateGroups="mte_group" flowable:formFieldValidation="true"/>
<exclusiveGateway id="getway2" name="网关2"/>
<endEvent id="end" name="结束"/>
... (remaining BPMN elements omitted for brevity) ...
</process>
</definitions>4. Import the BPMN file by uploading it to Flowable UI if needed.
3. Backend Project Setup
The backend uses JDK 8 and Spring Boot.
Spring Boot version:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>Project dependencies (pom.xml):
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.6.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>application.yml configuration:
spring:
datasource:
url: jdbc:mysql://localhost:3306/flowable?useSSL=false&characterEncoding=UTF-8&serverTimezone=GMT%2B8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 1234564. Database
All Flowable tables start with ACT_. Prefixes indicate purpose: ACT_RE_: repository – static information such as process definitions and resources. ACT_RU_: runtime – data for running instances (tasks, variables, jobs). Deleted when the instance ends. ACT_HI_: history – historical data for completed instances. ACT_GE_: generic – used in multiple places.
Key table groups:
General data tables: act_ge_bytearray, act_ge_property.
History tables (8): act_hi_actinst, act_hi_attachment, act_hi_comment, act_hi_detail, act_hi_identitylink, act_hi_procinst, act_hi_taskinst, act_hi_varinst.
User tables (4): act_id_group, act_id_info, act_id_membership, act_id_user.
Definition tables (3): act_re_deployment, act_re_procdef, act_re_model.
Runtime tables (6): act_ru_task, act_ru_event_subscr, act_ru_execution, act_ru_identitylink, act_ru_job, act_ru_variable.
5. Engine API and Services
The engine API is the primary way to interact with Flowable. The main entry point is ProcessEngine .
RepositoryService manages deployments and process definitions (static information).
RuntimeService starts new process instances.
IdentityService manages users and groups.
FormService is optional.
HistoryService provides access to historical data.
ManagementService offers low‑level DB access and job management.
DynamicBpmnService can modify a deployed definition without redeployment (e.g., change assignee or class name).
Example code using the leave‑approval process:
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;
@Slf4j
public class TestFlowable {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private HistoryService historyService;
@Autowired
private org.flowable.engine.TaskService taskService;
@Autowired
private org.flowable.engine.IdentityService identityService;
public void createDeploymentZip() {
try {
File zipTemp = new File("f:/leave_approval.bpmn20.zip");
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipTemp));
Deployment deployment = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
log.info("Deployment successful:{}", deployment.getId());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// Query process definitions
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("leave_approval").list();
// Start a process instance
String processDefinitionKey = "leave_approval";
String businessKey = "schoolleave";
Map<String, Object> variablesDefinition = new HashMap<>();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variablesDefinition);
log.info("Process started:{}", processInstance.getId());
// Student tasks
String candidateGroup = "stu_group";
List<Task> taskList = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
for (Task task : taskList) {
taskService.claim(task.getId(), "my");
taskService.complete(task.getId());
}
// Teacher tasks with decision variable
String candidateGroupTe = "te_group";
List<Task> taskListTe = taskService.createTaskQuery().taskCandidateGroup(candidateGroupTe).orderByTaskCreateTime().desc().list();
for (Task task : taskListTe) {
taskService.claim(task.getId(), "myte");
Map<String, Object> vars = new HashMap<>();
vars.put("command", "agree");
taskService.complete(task.getId(), vars);
}
// Historical queries
List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery()
.processDefinitionKey("leave_approval").list();
List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery()
.processDefinitionKey("leave_approval").list();
// Identity queries
List<User> users = identityService.createUserQuery().list();
List<Group> groups = identityService.createGroupQuery().list();
}
}6. References
Flowable documentation Chinese translation: https://github.com/qiudaoke/flowable-userguide
Cat Seven’s Flowable‑6.6.0 official demo.
Additional article: https://www.cnblogs.com/yangjiming/p/10938515.html
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.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
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.
