Master Flowable BPM: Integrate with Spring Boot 3 for Seamless Workflow Automation
This tutorial walks through Flowable BPM basics, Spring Boot 3 integration, Maven dependencies, YAML configuration, thread‑pool setup, process definition via the Flowable UI, deployment, querying, starting, task handling, completion, and rejection, providing complete code snippets and screenshots for a functional workflow system.
Flowable Overview
Flowable is a lightweight open‑source BPM and workflow engine that supports BPMN 2.0, providing features such as process definition, execution, task management and history queries, suitable for enterprise‑level applications.
Official site: https://www.flowable.com/open-source/docs/
Project example based on Spring Boot 3, MyBatis‑Plus, Vue & Element includes RBAC, multi‑tenant, data permission, workflow, third‑party login, payment, SMS, and e‑commerce functions.
Project address: https://github.com/YunaiV/ruoyi-vue-pro
Video tutorial: https://doc.iocoder.cn/video/
Spring Boot 3 Integration
Environment: JDK 21, Spring Boot 3.4.1, Flowable 7.1.0
1. Add Maven Dependency
<!-- Flowable启动引擎 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>7.1.0</version>
</dependency>2. yml Configuration
Data source uses MySQL and Druid; adjust according to your environment.
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/flowable?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
flowable:
async-executor-activate: true
database-schema-update: true3. Thread Pool Configuration
Provide a global default thread pool and a Flowable‑specific pool named applicationTaskExecutor.
@Configuration
public class ThreadPoolTaskConfig {
@Bean("applicationTaskExecutor")
public ThreadPoolTaskExecutor applicationTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int core = Runtime.getRuntime().availableProcessors();
executor.setCorePoolSize(core);
executor.setMaxPoolSize(core * 2 + 1);
executor.setKeepAliveSeconds(120);
executor.setQueueCapacity(120);
executor.setThreadNamePrefix("thread-default-execute");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
return executor;
}
}Missing thread‑pool configuration may cause errors.
Process Definition
Use the official Flowable UI designer (docker run ...) to create and edit BPMN diagrams.
docker run -p 9096:8080 -d --name flow flowable/flowable-ui:6.8.0Access the UI at the container’s IP and port; default credentials admin/test. Create a process, add user tasks, set assignee (e.g., user1), connect nodes, and export the XML.
Deploy Process
Place the exported XML under resources and deploy it programmatically.
@Resource
private RepositoryService repositoryService;
@Resource
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Resource
private HistoryService historyService;
@Resource
private IdentityService identityService;
@GetMapping("initFlow")
@Transactional(rollbackFor = Exception.class)
public void initFlow() {
ClassPathResource bpmnFolder = new ClassPathResource("bpmn/");
var files = bpmnFolder.getFile().listFiles((dir, name) -> name.endsWith(".bpmn20.xml"));
if (files != null && files.length > 0) {
var deploymentBuilder = repositoryService.createDeployment();
for (var file : files) {
deploymentBuilder.addInputStream(file.getName(), file.toURI().toURL().openStream());
}
Deployment deployment = deploymentBuilder.deploy();
}
}Query Deployed Processes
@GetMapping("/queryAllDeployedProcesses")
public List<JSONObject> queryAllDeployedProcesses() {
List<JSONObject> jsonObjects = new ArrayList<>();
List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery()
.orderByProcessDefinitionKey().asc()
.latestVersion()
.list();
for (ProcessDefinition pd : processDefinitions) {
JSONObject obj = new JSONObject();
obj.put("id", pd.getId());
obj.put("key", pd.getKey());
obj.put("name", pd.getName());
obj.put("version", pd.getVersion());
jsonObjects.add(obj);
}
return jsonObjects;
}Start a Process
@GetMapping("/startFlow")
@Transactional(rollbackFor = Exception.class)
public String startFlow(@RequestParam("key") String key) {
Map<String, Object> vars = Map.of(
"businessType", "业务类型(业务审批、请假、出差等)",
"day", 1,
"refuseFlag", false
);
String userId = SysConstan.USER_ID;
String businessKey = "PO00001";
identityService.setAuthenticatedUserId(userId);
ProcessInstance pi = runtimeService.startProcessInstanceByKey(key, businessKey, vars);
log.info("流程实例id-{}", pi.getId());
identityService.setAuthenticatedUserId(null);
return pi.getId();
}Key refers to the process definition key obtained after deployment. The variable map can be extended to control branching (e.g., leave days).
Query All Processes
@GetMapping("/queryAllprocess")
public List<JSONObject> queryAllprocess() {
List<HistoricProcessInstance> all = historyService.createHistoricProcessInstanceQuery()
.orderByProcessInstanceStartTime().asc()
.list();
List<JSONObject> result = new ArrayList<>();
for (HistoricProcessInstance pi : all) {
JSONObject json = new JSONObject();
json.put("status", pi.getEndTime() == null ? "审批中" : "审批完成");
json.put("id", pi.getProcessDefinitionId());
json.put("processInstanceId", pi.getId());
json.put("startUser", pi.getStartUserId());
json.put("key", pi.getProcessDefinitionKey());
json.put("businessKey", pi.getBusinessKey());
json.put("name", pi.getProcessDefinitionName());
json.put("deleteReason", pi.getDeleteReason());
json.put("startTime", DateUtil.format(pi.getStartTime(), "yyyy-MM-dd HH:mm:ss"));
json.put("endTime", pi.getEndTime() != null ? DateUtil.format(pi.getEndTime(), "yyyy-MM-dd HH:mm:ss") : "");
List<HistoricVariableInstance> vars = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(pi.getId())
.list();
for (HistoricVariableInstance var : vars) {
json.put(var.getVariableName(), var.getValue());
if ("refuseFlag".equals(var.getVariableName()) && Boolean.TRUE.equals(var.getValue())) {
json.put("status", "审批驳回");
}
}
result.add(json);
}
return result;
}My Tasks
@GetMapping("/allTasks")
public List<JSONObject> getTasks() {
List<Task> tasks = taskService.createTaskQuery().list();
List<JSONObject> result = new ArrayList<>();
for (Task task : tasks) {
JSONObject json = new JSONObject();
json.put("id", task.getId());
json.put("name", task.getName());
json.put("user", task.getAssignee());
json.put("processDefinitionId", task.getProcessDefinitionId());
json.put("processInstanceId", task.getProcessInstanceId());
json.putAll(taskService.getVariables(task.getId()));
result.add(json);
}
return result;
}Complete a Task
@GetMapping("/testComplete")
@Transactional(rollbackFor = Exception.class)
public boolean testComplete(@RequestParam("id") String taskId) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
System.out.println("任务不存在");
return false;
}
String processInstanceId = task.getProcessInstanceId();
taskService.addComment(taskId, processInstanceId, "备注信息test");
taskService.complete(taskId);
boolean isFinish = processInstanceFinished(processInstanceId);
return isFinish;
}
public boolean processInstanceFinished(String processInstanceId) {
ProcessInstance pi = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
return pi == null;
}Reject a Process
@GetMapping("stopFlow")
@Transactional(rollbackFor = Exception.class)
public void stopFlow(@RequestParam("id") String processInstanceId) {
runtimeService.setVariable(processInstanceId, "refuseFlag", true);
runtimeService.deleteProcessInstance(processInstanceId, "驳回任务备注原因");
}The article concludes with screenshots of the final UI and notes about rendering issues with BPMN‑JS and Flowable’s built‑in diagram generator.
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 Tech Enthusiast
Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!
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.
