飞龙工作流FlowLong:自定义节点开发深度解析
2026-02-04 04:16:18作者:伍霜盼Ellen
引言:为什么需要自定义节点?
在企业级工作流应用中,标准审批节点往往无法满足复杂的业务需求。飞龙工作流FlowLong作为国产工作流引擎的佼佼者,提供了强大的自定义节点扩展能力,让开发者能够根据具体业务场景定制专属的流程处理逻辑。
本文将深入探讨FlowLong的自定义节点开发机制,通过实际代码示例和架构分析,帮助您掌握这一核心扩展能力。
一、FlowLong节点处理架构概览
1.1 核心处理器接口体系
FlowLong通过一套精心设计的处理器接口体系来实现节点的扩展性:
classDiagram
class ConditionNodeHandler {
+getConditionNode(FlowLongContext, Execution, NodeModel) Optional~ConditionNode~
+getRouteNode(FlowLongContext, Execution, NodeModel) Optional~ConditionNode~
+getInclusiveNodes(FlowLongContext, Execution, NodeModel) Optional~List~ConditionNode~~
}
class CreateTaskHandler {
+handle(FlowLongContext, Execution, NodeModel) boolean
}
class FlowJsonHandler {
+toJson(Object) String
+fromJson(String, Class~T~) T
}
class FlowLongContext {
-createTaskHandler: CreateTaskHandler
-conditionNodeHandler: ConditionNodeHandler
-flowJsonHandler: FlowJsonHandler
+getCreateTaskHandler() CreateTaskHandler
+getFlowConditionHandler() ConditionNodeHandler
}
FlowLongContext --> ConditionNodeHandler
FlowLongContext --> CreateTaskHandler
FlowLongContext --> FlowJsonHandler
1.2 默认实现与扩展机制
FlowLong提供了默认的简单实现,同时也允许开发者完全覆盖这些实现:
| 处理器类型 | 默认实现类 | 扩展方式 |
|---|---|---|
| 条件节点处理器 | SimpleConditionNodeHandler | 实现ConditionNodeHandler接口 |
| 任务创建处理器 | SimpleCreateTaskHandler | 实现CreateTaskHandler接口 |
| JSON处理器 | FlowJacksonHandler | 实现FlowJsonHandler接口 |
二、自定义条件节点开发实战
2.1 ConditionNodeHandler接口详解
条件节点处理器是流程分支决策的核心,负责根据业务条件选择执行路径:
/**
* 自定义条件节点处理器示例
* 实现复杂的业务条件判断逻辑
*/
public class BusinessConditionNodeHandler implements ConditionNodeHandler {
@Override
public Optional<ConditionNode> getConditionNode(FlowLongContext context,
Execution execution,
NodeModel nodeModel) {
// 获取流程变量
Map<String, Object> variables = execution.getVariables();
BigDecimal amount = (BigDecimal) variables.get("approvalAmount");
String department = (String) variables.get("applyDepartment");
// 复杂的业务条件判断逻辑
if (amount.compareTo(new BigDecimal("10000")) > 0) {
// 大额审批需要财务总监审批
return findConditionNode(nodeModel, "financeDirectorApproval");
} else if ("技术部".equals(department) && amount.compareTo(new BigDecimal("5000")) > 0) {
// 技术部中等金额需要CTO审批
return findConditionNode(nodeModel, "ctoApproval");
} else {
// 其他情况走默认审批流程
return findConditionNode(nodeModel, "defaultApproval");
}
}
@Override
public Optional<ConditionNode> getRouteNode(FlowLongContext context,
Execution execution,
NodeModel nodeModel) {
// 路由节点处理逻辑
String routeType = (String) execution.getVariable("routeType");
if ("emergency".equals(routeType)) {
return findConditionNode(nodeModel, "emergencyRoute");
}
return Optional.empty();
}
@Override
public Optional<List<ConditionNode>> getInclusiveNodes(FlowLongContext context,
Execution execution,
NodeModel nodeModel) {
// 包容分支处理:同时满足多个条件的分支
List<ConditionNode> inclusiveNodes = new ArrayList<>();
if (meetsConditionA(execution)) {
inclusiveNodes.add(findConditionNode(nodeModel, "conditionA").get());
}
if (meetsConditionB(execution)) {
inclusiveNodes.add(findConditionNode(nodeModel, "conditionB").get());
}
return inclusiveNodes.isEmpty() ? Optional.empty() : Optional.of(inclusiveNodes);
}
private Optional<ConditionNode> findConditionNode(NodeModel nodeModel, String nodeKey) {
return nodeModel.getConditionNodes().stream()
.filter(cn -> nodeKey.equals(cn.getKey()))
.findFirst();
}
}
2.2 条件节点配置示例
在流程定义中配置自定义条件节点:
{
"nodes": [
{
"key": "conditionCheck",
"type": "condition",
"name": "审批金额条件判断",
"handler": "com.yourcompany.BusinessConditionNodeHandler",
"conditionNodes": [
{
"key": "financeDirectorApproval",
"name": "财务总监审批",
"expression": "amount > 10000"
},
{
"key": "ctoApproval",
"name": "CTO审批",
"expression": "department == '技术部' && amount > 5000"
},
{
"key": "defaultApproval",
"name": "默认审批",
"expression": "true"
}
]
}
]
}
三、自定义任务创建处理器开发
3.1 CreateTaskHandler接口实现
任务创建处理器负责生成具体的审批任务,支持复杂的任务分配逻辑:
/**
* 自定义任务创建处理器
* 实现动态任务分配和特殊任务处理逻辑
*/
public class DynamicTaskCreateHandler implements CreateTaskHandler {
@Override
public boolean handle(FlowLongContext context, Execution execution, NodeModel nodeModel) {
// 1. 前置校验
if (!validateBusinessRules(execution)) {
return false;
}
// 2. 动态确定审批人
List<String> assignees = determineAssignees(execution, nodeModel);
// 3. 创建审批任务
for (String assignee : assignees) {
FlwTask task = createTaskInstance(execution, nodeModel, assignee);
// 4. 设置任务特殊属性
setTaskSpecialProperties(task, execution);
// 5. 保存任务并发送通知
context.getTaskService().saveTask(task);
sendTaskNotification(task, assignee);
}
return true;
}
private List<String> determineAssignees(Execution execution, NodeModel nodeModel) {
// 复杂的审批人确定逻辑
String projectType = (String) execution.getVariable("projectType");
BigDecimal budget = (BigDecimal) execution.getVariable("budgetAmount");
List<String> assignees = new ArrayList<>();
if ("研发项目".equals(projectType)) {
// 研发项目需要技术负责人和项目经理审批
assignees.add(getTechLead(execution));
assignees.add(getProjectManager(execution));
} else if ("市场活动".equals(projectType) && budget.compareTo(new BigDecimal("50000")) > 0) {
// 大额市场活动需要市场总监审批
assignees.add(getMarketingDirector());
}
// 默认审批人 fallback
if (assignees.isEmpty()) {
assignees.add(getDefaultApprover(nodeModel));
}
return assignees;
}
private void setTaskSpecialProperties(FlwTask task, Execution execution) {
// 设置任务优先级
String urgency = (String) execution.getVariable("urgencyLevel");
if ("high".equals(urgency)) {
task.setPriority(TaskPriority.HIGH);
task.setDueDate(calculateDueDate(2)); // 高紧急度2天内完成
}
// 设置任务标签
task.setTags(Arrays.asList("custom", "dynamic"));
}
}
3.2 任务处理器配置集成
在Spring Boot中配置自定义处理器:
@Configuration
public class FlowLongCustomConfig {
@Bean
public CreateTaskHandler dynamicTaskCreateHandler() {
return new DynamicTaskCreateHandler();
}
@Bean
public ConditionNodeHandler businessConditionNodeHandler() {
return new BusinessConditionNodeHandler();
}
@Bean
public FlowLongContext flowLongContext(FlowCache flowCache) {
FlowLongContext context = new FlowLongContext(flowCache, null);
context.setCreateTaskHandler(dynamicTaskCreateHandler());
context.setConditionNodeHandler(businessConditionNodeHandler());
return context;
}
}
四、高级自定义场景实践
4.1 会签节点的自定义实现
/**
* 自定义会签处理器
* 支持复杂的会签逻辑和动态会签人确定
*/
public class CustomCountersignHandler implements CreateTaskHandler {
@Override
public boolean handle(FlowLongContext context, Execution execution, NodeModel nodeModel) {
CountersignConfig config = parseCountersignConfig(nodeModel);
// 动态确定会签参与者
List<CountersignParticipant> participants = determineParticipants(execution, config);
// 根据会签类型创建任务
if (config.getType() == CountersignType.SEQUENTIAL) {
createSequentialTasks(context, execution, nodeModel, participants);
} else {
createParallelTasks(context, execution, nodeModel, participants);
}
return true;
}
private List<CountersignParticipant> determineParticipants(Execution execution,
CountersignConfig config) {
List<CountersignParticipant> participants = new ArrayList<>();
// 根据部门、角色、技能等维度确定会签人
if (config.isIncludeDepartmentHeads()) {
participants.addAll(getDepartmentHeads(execution));
}
if (config.isIncludeTechnicalExperts()) {
participants.addAll(getTechnicalExperts(execution));
}
// 去重和排序
return participants.stream()
.distinct()
.sorted(Comparator.comparing(CountersignParticipant::getPriority))
.collect(Collectors.toList());
}
}
4.2 条件表达式扩展
/**
* 自定义表达式处理器
* 扩展FlowLong的表达式解析能力
*/
public class CustomExpressionHandler extends SpelFlowLongExpression {
@Override
public Object execute(String expression, Map<String, Object> variables) {
// 支持自定义函数调用
if (expression.startsWith("custom:")) {
return handleCustomFunction(expression.substring(7), variables);
}
// 支持数据库查询表达式
if (expression.startsWith("dbQuery:")) {
return executeDatabaseQuery(expression.substring(8), variables);
}
// 默认使用SPEL表达式
return super.execute(expression, variables);
}
private Object handleCustomFunction(String functionExpression, Map<String, Object> variables) {
String[] parts = functionExpression.split("\\(");
String functionName = parts[0];
String params = parts[1].replace(")", "");
switch (functionName) {
case "calculateRiskScore":
return calculateRiskScore(params, variables);
case "getApprovalPath":
return getApprovalPath(params, variables);
default:
throw new IllegalArgumentException("Unknown custom function: " + functionName);
}
}
}
五、最佳实践与性能优化
5.1 自定义节点开发规范
| 实践要点 | 说明 | 示例 |
|---|---|---|
| 接口实现完整性 | 实现所有接口方法,提供合理的默认实现 | 所有Handler接口方法都要实现 |
| 异常处理 | 使用统一的异常处理机制 | 抛出FlowLongException |
| 日志记录 | 记录关键操作和决策过程 | 使用SLF4J记录调试信息 |
| 性能考虑 | 避免在处理器中进行耗时操作 | 使用缓存、异步处理 |
5.2 性能优化策略
/**
* 高性能条件节点处理器
* 使用缓存和预编译优化性能
*/
public class OptimizedConditionHandler implements ConditionNodeHandler {
private final Cache<String, CompiledCondition> conditionCache;
public OptimizedConditionHandler() {
this.conditionCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
}
@Override
public Optional<ConditionNode> getConditionNode(FlowLongContext context,
Execution execution,
NodeModel nodeModel) {
// 使用缓存加速条件判断
String cacheKey = buildCacheKey(nodeModel, execution);
CompiledCondition compiledCondition = conditionCache.get(cacheKey,
key -> compileConditions(nodeModel.getConditionNodes()));
return compiledCondition.evaluate(execution.getVariables());
}
private CompiledCondition compileConditions(List<ConditionNode> conditionNodes) {
// 预编译条件表达式,提高执行性能
return new CompiledCondition(conditionNodes);
}
}
六、测试与调试
6.1 单元测试示例
@SpringBootTest
public class CustomNodeHandlerTest {
@Autowired
private CreateTaskHandler customTaskHandler;
@Test
public void testDynamicAssigneeDetermination() {
// 准备测试数据
Execution execution = createTestExecution();
NodeModel nodeModel = createTestNodeModel();
FlowLongContext context = createMockContext();
// 执行测试
boolean result = customTaskHandler.handle(context, execution, nodeModel);
// 验证结果
assertTrue(result);
verifyTaskCreation(execution, 2); // 应该创建2个任务
}
@Test
public void testConditionNodeRouting() {
// 测试条件节点路由逻辑
Execution execution = createExecutionWithVariables(
Map.of("approvalAmount", new BigDecimal("15000"),
"applyDepartment", "技术部")
);
Optional<ConditionNode> result = conditionHandler.getConditionNode(
context, execution, nodeModel
);
assertTrue(result.isPresent());
assertEquals("financeDirectorApproval", result.get().getKey());
}
}
6.2 调试技巧
/**
* 可调试的自定义处理器
* 提供详细的调试信息和日志输出
*/
public class DebuggableTaskHandler implements CreateTaskHandler {
private static final Logger logger = LoggerFactory.getLogger(DebuggableTaskHandler.class);
@Override
public boolean handle(FlowLongContext context, Execution execution, NodeModel nodeModel) {
logger.debug("开始处理任务创建,实例ID: {}, 节点: {}",
execution.getInstanceId(), nodeModel.getName());
try {
// 详细的调试日志
logExecutionDetails(execution);
logNodeModelDetails(nodeModel);
boolean result = doHandle(context, execution, nodeModel);
logger.debug("任务创建处理完成,结果: {}", result);
return result;
} catch (Exception e) {
logger.error("任务创建处理失败", e);
throw new FlowLongException("自定义任务处理失败", e);
}
}
}
七、总结与展望
通过本文的深入探讨,我们全面了解了飞龙工作流FlowLong的自定义节点开发机制。自定义节点开发是FlowLong强大扩展能力的体现,让开发者能够:
- 灵活适应业务需求:根据具体业务场景定制审批逻辑
- 实现复杂流程控制:支持条件分支、会签、动态分配等高级功能
- 提升系统集成度:与企业现有系统深度集成
- 优化用户体验:提供更智能、更高效的审批流程
未来,随着FlowLong的持续发展,自定义节点开发将支持更多高级特性,如AI智能审批、区块链存证、多租户隔离等,为企业数字化转型提供更强大的工作流引擎支持。
掌握自定义节点开发技能,将使您能够在FlowLong基础上构建出真正符合企业需求的智能化工作流系统。
登录后查看全文
热门项目推荐
相关项目推荐
Kimi-K2.5Kimi K2.5 是一款开源的原生多模态智能体模型,它在 Kimi-K2-Base 的基础上,通过对约 15 万亿混合视觉和文本 tokens 进行持续预训练构建而成。该模型将视觉与语言理解、高级智能体能力、即时模式与思考模式,以及对话式与智能体范式无缝融合。Python00
GLM-4.7-FlashGLM-4.7-Flash 是一款 30B-A3B MoE 模型。作为 30B 级别中的佼佼者,GLM-4.7-Flash 为追求性能与效率平衡的轻量化部署提供了全新选择。Jinja00
VLOOKVLOOK™ 是优雅好用的 Typora/Markdown 主题包和增强插件。 VLOOK™ is an elegant and practical THEME PACKAGE × ENHANCEMENT PLUGIN for Typora/Markdown.Less00
PaddleOCR-VL-1.5PaddleOCR-VL-1.5 是 PaddleOCR-VL 的新一代进阶模型,在 OmniDocBench v1.5 上实现了 94.5% 的全新 state-of-the-art 准确率。 为了严格评估模型在真实物理畸变下的鲁棒性——包括扫描伪影、倾斜、扭曲、屏幕拍摄和光照变化——我们提出了 Real5-OmniDocBench 基准测试集。实验结果表明,该增强模型在新构建的基准测试集上达到了 SOTA 性能。此外,我们通过整合印章识别和文本检测识别(text spotting)任务扩展了模型的能力,同时保持 0.9B 的超紧凑 VLM 规模,具备高效率特性。Python00
KuiklyUI基于KMP技术的高性能、全平台开发框架,具备统一代码库、极致易用性和动态灵活性。 Provide a high-performance, full-platform development framework with unified codebase, ultimate ease of use, and dynamic flexibility. 注意:本仓库为Github仓库镜像,PR或Issue请移步至Github发起,感谢支持!Kotlin07
compass-metrics-modelMetrics model project for the OSS CompassPython00
项目优选
收起
deepin linux kernel
C
27
11
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
525
3.72 K
Ascend Extension for PyTorch
Python
329
391
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
877
578
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
335
162
暂无简介
Dart
764
189
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
12
1
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
1.33 K
746
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Java
67
20
React Native鸿蒙化仓库
JavaScript
302
350