在前三篇文章中,我们依次认识了 Flowable 的基础概念、用 Modeler 设计流程,以及通过 API 控制流程运行。但在实际项目中,我们更需要将 Flowable 与 Spring Boot 深度融合,构建完整的工作流平台。本文将从环境配置、设计器集成、权限控制等方面,分享 Flowable 与 Spring Boot 集成的实战经验。
一、Flowable 与 Spring Boot 的无缝对接
1.1 基础环境配置
Spring Boot 对 Flowable 提供了自动配置支持,只需引入相关依赖即可快速集成:
<dependencies>
<!-- Flowable核心依赖 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.8.0</version>
</dependency>
<!-- Web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据库依赖 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 安全框架(用于权限控制) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
在application.yml中配置数据库和 Flowable 参数:
spring:
datasource:
url: jdbc:mysql://localhost:3306/flowable_boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
flowable:
# 数据库表结构更新策略
database-schema-update: true
# 异步执行器配置
async-executor-activate: true
# 历史记录级别
history-level: full
# 流程部署路径
process-definition-location-prefix: classpath:/processes/
1.2 自定义 Flowable 配置
通过ProcessEngineConfigurationConfigurer可自定义流程引擎配置:
@Configuration
public class FlowableConfig implements ProcessEngineConfigurationConfigurer {
@Override
public void configure(SpringProcessEngineConfiguration configuration) {
// 配置邮件服务器(用于任务通知)
configuration.setMailServerHost("smtp.example.com");
configuration.setMailServerPort(587);
configuration.setMailServerUsername("notifications@example.com");
configuration.setMailServerPassword("password");
// 配置自定义表单类型
List<AbstractFormType> customFormTypes = new ArrayList<>();
customFormTypes.add(new PhoneFormType()); // 自定义手机号表单类型
customFormTypes.add(new IdCardFormType()); // 自定义身份证表单类型
configuration.setCustomFormTypes(customFormTypes);
// 配置流程自动部署器
configuration.setDeploymentName("spring-boot-deployment");
}
}
二、Flowable Modeler 与业务系统集成
将 Flowable Modeler 嵌入业务系统,实现流程设计与业务的无缝衔接。
2.1 部署独立的 Modeler 服务
- 下载 Flowable Modeler 的 WAR 包并部署到 Tomcat
- 配置跨域支持(flowable-modeler-app/WEB-INF/classes/flowable-modeler.properties):
flowable.modeler.app.cors.allowed-origins=http://localhost:8080
flowable.modeler.app.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
flowable.modeler.app.cors.allowed-headers=Content-Type,Authorization
3.配置与业务系统相同的数据库,实现数据共享
2.2 实现 Modeler 与业务系统的单点登录
通过自定义过滤器实现 SSO 集成:
@Component
public class ModelerSsoFilter extends OncePerRequestFilter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// 从请求头获取令牌
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
try {
// 验证令牌并创建认证对象
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(token, token);
Authentication authentication = authenticationManager.authenticate(authToken);
// 设置安全上下文
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (AuthenticationException e) {
SecurityContextHolder.clearContext();
}
}
filterChain.doFilter(request, response);
}
}
2.3 流程部署与版本管理
实现流程设计完成后自动部署到业务系统:
@Service
public class ProcessDeploymentService {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RestTemplate restTemplate;
/**
* 从Modeler获取流程模型并部署
*/
public Deployment deployFromModeler(String modelId) {
// 调用Modeler的API获取流程模型JSON
String modelUrl = "http://localhost:8080/flowable-modeler/app/rest/models/" + modelId + "/source";
String bpmnXml = restTemplate.getForObject(modelUrl, String.class);
// 部署流程定义
return repositoryService.createDeployment()
.name("model-" + modelId)
.addString("process-" + modelId + ".bpmn20.xml", bpmnXml)
.deploy();
}
/**
* 流程版本管理
*/
public List<ProcessDefinition> getProcessVersions(String processKey) {
return repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(processKey)
.orderByProcessDefinitionVersion()
.asc()
.list();
}
/**
* 激活指定版本的流程
*/
public void activateProcessVersion(String processDefinitionId) {
repositoryService.activateProcessDefinitionById(processDefinitionId);
// 停用其他版本
String processKey = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(processDefinitionId)
.singleResult()
.getKey();
List<ProcessDefinition> otherVersions = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(processKey)
.processDefinitionIdNotEquals(processDefinitionId)
.list();
otherVersions.forEach(def ->
repositoryService.suspendProcessDefinitionById(def.getId())
);
}
}
三、基于 Flowable 的工作流平台搭建
构建包含待办任务、流程监控、报表分析的完整工作流平台。
3.1 待办任务中心
实现个人待办、已办任务的统一管理:
@RestController
@RequestMapping("/workflow/task")
public class TaskController {
@Autowired
private TaskService taskService;
@Autowired
private IdentityService identityService;
/**
* 获取当前用户的待办任务
*/
@GetMapping("/pending")
public Page<TaskVO> getPendingTasks(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
// 查询待办任务(包含候选人任务)
List<Task> tasks = taskService.createTaskQuery()
.taskCandidateOrAssigned(currentUser)
.orderByTaskCreateTime()
.desc()
.listPage(page * size, size);
// 转换为VO对象
List<TaskVO> taskVOs = tasks.stream()
.map(this::convertToVO)
.collect(Collectors.toList());
// 计算总条数
long total = taskService.createTaskQuery()
.taskCandidateOrAssigned(currentUser)
.count();
return new Page<>(taskVOs, page, size, total);
}
/**
* 认领任务
*/
@PostMapping("/claim/{taskId}")
public ResponseEntity<Void> claimTask(@PathVariable String taskId) {
String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
// 验证任务是否可认领
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(currentUser)
.singleResult();
if (task == null) {
return ResponseEntity.badRequest().build();
}
// 认领任务
taskService.claim(taskId, currentUser);
return ResponseEntity.ok().build();
}
/**
* 完成任务
*/
@PostMapping("/complete/{taskId}")
public ResponseEntity<Void> completeTask(
@PathVariable String taskId,
@RequestBody TaskCompleteRequest request) {
String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
// 验证任务归属
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(currentUser)
.singleResult();
if (task == null) {
return ResponseEntity.badRequest().build();
}
// 完成任务
taskService.complete(taskId, request.getVariables());
return ResponseEntity.ok().build();
}
// 其他方法:获取已办任务、委托任务、转办任务等
}
3.2 流程监控与分析
实现流程运行状态的实时监控和数据分析:
@RestController
@RequestMapping("/workflow/monitor")
public class MonitorController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private HistoryService historyService;
@Autowired
private ManagementService managementService;
/**
* 流程运行状态统计
*/
@GetMapping("/statistics")
public WorkflowStatisticsVO getStatistics() {
WorkflowStatisticsVO stats = new WorkflowStatisticsVO();
// 运行中流程数量
stats.setRunningProcessCount(runtimeService.createProcessInstanceQuery().active().count());
// 已完成流程数量
stats.setCompletedProcessCount(historyService.createHistoricProcessInstanceQuery().finished().count());
// 平均流程完成时间
HistoricProcessInstanceStatistics avgStats = historyService
.createHistoricProcessInstanceStatisticsQuery(null)
.singleResult();
if (avgStats != null) {
stats.setAvgCompletionTime(avgStats.getAverageDurationInMillis());
}
// 各流程定义的运行数量
List<ProcessDefinitionCountVO> definitionCounts = runtimeService.createProcessInstanceQuery()
.groupByProcessDefinitionKey()
.countByProcessDefinitionKey()
.entrySet().stream()
.map(entry -> {
ProcessDefinitionCountVO vo = new ProcessDefinitionCountVO();
vo.setProcessKey(entry.getKey());
vo.setCount(entry.getValue());
return vo;
})
.collect(Collectors.toList());
stats.setProcessDefinitionCounts(definitionCounts);
return stats;
}
/**
* 流程实例跟踪
*/
@GetMapping("/trace/{processInstanceId}")
public ProcessTraceVO traceProcess(@PathVariable String processInstanceId) {
// 获取流程实例
ProcessInstance instance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
// 获取历史活动实例
List<HistoricActivityInstance> activities = historyService
.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime()
.asc()
.list();
// 构建流程跟踪VO
ProcessTraceVO traceVO = new ProcessTraceVO();
traceVO.setProcessInstanceId(processInstanceId);
traceVO.setProcessDefinitionId(instance.getProcessDefinitionId());
traceVO.setStartTime(instance.getStartTime());
traceVO.setStatus(instance.isEnded() ? "completed" : "running");
// 转换活动实例
List<ActivityTraceVO> activityTraces = activities.stream()
.map(activity -> {
ActivityTraceVO activityVO = new ActivityTraceVO();
activityVO.setActivityId(activity.getActivityId());
activityVO.setActivityName(activity.getActivityName());
activityVO.setAssignee(activity.getAssignee());
activityVO.setStartTime(activity.getStartTime());
activityVO.setEndTime(activity.getEndTime());
activityVO.setDuration(activity.getDurationInMillis());
return activityVO;
})
.collect(Collectors.toList());
traceVO.setActivities(activityTraces);
return traceVO;
}
}
3.3 流程报表与分析
通过报表分析流程瓶颈,优化业务流程:
@Service
public class WorkflowReportService {
@Autowired
private HistoryService historyService;
/**
* 流程环节耗时分析
*/
public List<ActivityDurationVO> analyzeActivityDurations(String processKey) {
// 查询指定流程的所有历史活动
List<HistoricActivityInstance> activities = historyService
.createHistoricActivityInstanceQuery()
.processDefinitionKey(processKey)
.activityTypeIn("userTask", "serviceTask")
.list();
// 按活动ID分组计算平均耗时
Map<String, List<Long>> durationMap = new HashMap<>();
for (HistoricActivityInstance activity : activities) {
String activityId = activity.getActivityId();
long duration = activity.getDurationInMillis() == null ? 0 : activity.getDurationInMillis();
durationMap.computeIfAbsent(activityId, k -> new ArrayList<>()).add(duration);
}
// 计算平均值并转换为VO
return durationMap.entrySet().stream()
.map(entry -> {
ActivityDurationVO vo = new ActivityDurationVO();
vo.setActivityId(entry.getKey());
// 获取活动名称
String activityName = activities.stream()
.filter(a -> a.getActivityId().equals(entry.getKey()))
.findFirst()
.map(HistoricActivityInstance::getActivityName)
.orElse(entry.getKey());
vo.setActivityName(activityName);
// 计算平均耗时
List<Long> durations = entry.getValue();
long avgDuration = durations.stream()
.mapToLong(Long::longValue)
.average()
.orElse(0);
vo.setAvgDuration(avgDuration);
vo.setCount(durations.size());
return vo;
})
.sorted(Comparator.comparingLong(ActivityDurationVO::getAvgDuration).reversed())
.collect(Collectors.toList());
}
}
四、安全与权限控制
集成 Spring Security 实现流程操作的权限管控。
4.1 基于角色的权限控制
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
// 公开接口
.requestMatchers("/workflow/public/**", "/actuator/health").permitAll()
// 管理员接口
.requestMatchers("/workflow/admin/**", "/flowable-ui/**").hasRole("ADMIN")
// 流程设计接口
.requestMatchers("/workflow/model/**").hasAnyRole("ADMIN", "PROCESS_DESIGNER")
// 其他接口需认证
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
)
.csrf(csrf -> csrf.disable());
return http.build();
}
/**
* JWT认证转换器(将JWT声明转换为Spring Security权限)
*/
private JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return converter;
}
}
4.2 流程权限的细粒度控制
通过AccessControlProvider控制流程实例的访问权限:
@Component
public class CustomAccessControlProvider implements AccessControlProvider {
@Autowired
private ProcessRepositoryService processRepositoryService;
@Override
public boolean isAuthorized(UserDetails user, String processInstanceId) {
String username = user.getUsername();
// 管理员拥有所有权限
if (user.getAuthorities().stream()
.anyMatch(auth -> auth.getAuthority().equals("ROLE_ADMIN"))) {
return true;
}
// 流程发起人拥有权限
ProcessInstance instance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
if (instance != null && username.equals(instance.getStartUserId())) {
return true;
}
// 参与过流程的用户拥有权限
long participatedCount = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.taskAssignee(username)
.count();
if (participatedCount > 0) {
return true;
}
return false;
}
}
五、实际项目中的架构设计与踩坑经验
5.1 分布式环境下的 Flowable 部署
在微服务架构中,Flowable 的部署策略:
- 共享数据库模式:所有服务共享 Flowable 数据库,适合中小规模部署
- 独立流程服务:将 Flowable 作为独立微服务,提供 REST API 供其他服务调用
- 事件驱动架构:通过消息队列(如 Kafka)实现流程事件的跨服务通知
5.2 性能优化实践
- 历史数据归档:定期将旧的历史数据迁移到归档库
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行
public void archiveHistoricData() {
// 归档30天前的历史数据
Date cutoffDate = new Date(System.currentTimeMillis() - 30L * 24 * 60 * 60 * 1000);
historyService.createHistoricProcessInstanceQuery()
.finished()
.processInstanceEndTimeBefore(cutoffDate)
.list()
.forEach(instance -> {
// 迁移到归档表
archiveService.archiveInstance(instance.getId());
// 删除原表数据
historyService.deleteHistoricProcessInstance(instance.getId());
});
}
2.流程变量优化:
- 避免存储大对象(超过 1KB)
- 使用runtimeService.setVariableLocal设置局部变量
- 敏感信息加密存储
3.缓存策略:缓存流程定义和常用流程数据
@Bean
public CacheManager flowableCacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(30, TimeUnit.MINUTES)
.maximumSize(1000));
return cacheManager;
}
5.3 常见问题及解决方案
问题 |
解决方案 |
流程实例查询性能差 |
1. 减少返回字段 2. 分页查询 3. 添加索引 4. 使用缓存 |
分布式环境下流程事件重复处理 |
1. 使用幂等设计 2. 事件去重 3. 分布式锁控制 |
大并发下任务创建慢 |
1. 异步创建任务 2. 批量处理 3. 数据库优化 |
流程版本升级困难 |
1. 设计兼容的流程变更 2. 流程实例迁移工具 3. 灰度发布策略 |
六、小结与下一篇预告
本文我们实现了 Flowable 与 Spring Boot 的深度集成,包括:
- 环境搭建与自定义配置
- Modeler 与业务系统的无缝对接
- 工作流平台核心功能(待办任务、流程监控)
- 安全权限控制与分布式部署策略
这些内容足以支撑企业级工作流平台的构建。下一篇文章,我们将探讨 Flowable 的高级特性与扩展,包括:
- 动态流程生成(无需预先设计 BPMN 文件)
- Flowable 与决策引擎 DMN 的集成
- 复杂场景的流程设计模式(如子流程嵌套、事件子流程)
- 自定义 Flowable 的核心组件(如自定义解析器、行为处理器)
如果在集成过程中遇到特殊场景或技术难题,欢迎在评论区留言讨论!