Integrating Flowable Workflow Engine with Spring Boot: A Step‑by‑Step Guide
This article explains how to use the Flowable BPMN engine in a Spring Boot project, covering workflow basics, related BPMN concepts, Maven dependencies, diagram creation, service‑task implementation, REST API for diagram viewing, unit testing, and common pitfalls such as font configuration and process definition updates.
1. Workflow Overview
Early workflow engines like jBPM (a Java‑based engine from JBoss) evolved into Activiti, Camunda and Flowable. The three mainstream engines today—Activiti, Flowable and Camunda—each have distinct characteristics: Activiti leans toward Spring Cloud and Docker, Flowable offers rich extensibility, and Camunda provides a lightweight embedded BPMN editor.
2. Related BPMN Concepts
A BPMN diagram consists of four core elements:
Events (start, end, intermediate, boundary)
Sequence flows (connections, optionally with conditions)
Tasks (user, service, script, receive, send, etc.)
Gateways (exclusive, parallel, inclusive, event)
Each task type is illustrated with screenshots in the original article; for brevity they are omitted here.
3. Spring Boot Integration of Flowable
3.1 Add Maven Dependency
org.flowable
flowable-spring-boot-starter
6.7.2Flowable automatically scans the resources/processes directory and deploys any BPMN files found there.
3.2 Draw the Process Diagram
You can use the Flowable BPMN Visualizer plugin in IDEA or the Flowable UI editor to create a diagram such as ask_for_leave.bpmn20.xml . The diagram models a simple leave‑request flow: employee → team‑lead approval → manager approval → end, with exclusive gateways handling “approve” or “reject” paths.
3.3 Service Task Implementation
@Slf4j
@Component
public class LeaveFailService implements JavaDelegate {
@Override
public void execute(DelegateExecution delegateExecution) {
log.info("审批不通过{}", delegateExecution.getCurrentActivityId());
}
}The class implements JavaDelegate and is invoked automatically when the service task runs.
3.4 Process Diagram Viewing API
@RestController
public class LeaveController {
@Autowired RuntimeService runtimeService;
@Autowired RepositoryService repositoryService;
@Autowired ProcessEngine processEngine;
@GetMapping("/pic")
public void showPic(HttpServletResponse resp, String processId) throws Exception {
ProcessInstance pi = runtimeService.createProcessInstanceQuery()
.processInstanceId(processId).singleResult();
if (pi == null) return;
List
executions = runtimeService.createExecutionQuery()
.processInstanceId(processId).list();
List
activityIds = new ArrayList<>();
for (Execution exe : executions) {
activityIds.addAll(runtimeService.getActiveActivityIds(exe.getId()));
}
BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, Collections.emptyList(),
engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(),
engconf.getClassLoader(), 1.0, false);
OutputStream out = resp.getOutputStream();
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}The endpoint returns a PNG image highlighting the current active nodes of a running process instance.
3.5 Unit Tests
@SpringBootTest
@Slf4j
@ActiveProfiles("dev")
class ProcessApplicationTests {
@Autowired RuntimeService runtimeService;
@Autowired TaskService taskService;
public static final String yuangongId = "yuangongID_3";
public static final String zuzhangId = "zuzhangId_3";
public static final String manageId = "manageId_3";
@Test
void askForLeave() {
Map
vars = new HashMap<>();
vars.put("leaveTask", yuangongId);
ProcessInstance pi = runtimeService.startProcessInstanceByKey("ask_for_leave", vars);
runtimeService.setVariable(pi.getId(), "name", "javaboy");
runtimeService.setVariable(pi.getId(), "reason", "休息一下");
runtimeService.setVariable(pi.getId(), "days", 10);
log.info("创建请假流程 processId:{}", pi.getId());
}
// Additional tests for submitting to team‑lead, approving/rejecting, etc.
}The tests demonstrate starting a process, completing user tasks, and handling approval decisions.
4. Common Issues
4.1 Diagram Text Appears as “口口口”
This occurs when the JVM cannot find a default font. Configure Flowable to use a installed font, e.g.:
@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer
{
@Override
public void configure(SpringProcessEngineConfiguration cfg) {
cfg.setActivityFontName("宋体");
cfg.setLabelFontName("宋体");
cfg.setAnnotationFontName("宋体");
}
}4.2 Changing the BPMN File Does Not Affect Running Instances
Process definitions are persisted when a process starts. Modifying the BPMN file only affects new instances; already running instances continue using the old definition.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.