场景:工作流在配置分支的时候,需要配置流条件,而流条件有时候会比较复杂,容易写错。本章主要描述 如何从 flowable 源码中拿到 表达式处理代码。
环境:
springboot:2.2.0.RELEASE
flowable:6.4.2
如上图,表达式的写法可以很多用,flowable会基于spring EL 表达式的基础上,再进行扩展:
到节点A:(自定义函数)流条件:
${variables:substr(a1,index1,end1)}=='哈哈'}
到节点B:(数字比较)流条件:
${b==2}
到节点C:(字符串对象方法)流条件:
${c.contains("BCD")}
所以如果要进行 flowable 表达式 校验,就需要模拟拿到核心。
从源码中可以找到类:org.flowable.engine.impl.util.condition.ConditionUtil
Expression expression = CommandContextUtil.getProcessEngineConfiguration().getExpressionManager().createExpression(conditionExpression);
Condition condition = new UelExpressionCondition(expression);
return condition.evaluate(sequenceFlow.getId(), execution);
通过Debug,可以找到实现类:
org.flowable.spring.SpringExpressionManager
org.flowable.engine.impl.el.JuelExpression
org.flowable.engine.impl.el.UelExpressionCondition
org.flowable.engine.impl.el.UelExpressionCondition
public class UelExpressionCondition implements Condition {
protected Expression expression;
public UelExpressionCondition(Expression expression) {
this.expression = expression;
}
@Override
public boolean evaluate(String sequenceFlowId, DelegateExecution execution) {
Object result = expression.getValue(execution);
if (result == null) {
throw new FlowableException("condition expression returns null (sequenceFlowId: " + sequenceFlowId + ")" );
}
if (!(result instanceof Boolean)) {
throw new FlowableException("condition expression returns non-Boolean (sequenceFlowId: " + sequenceFlowId + "): " + result + " (" + result.getClass().getName() + ")");
}
return (Boolean) result;
}
}
由上面就可以基本定位到主要代码只有
Expression expression = CommandContextUtil.getProcessEngineConfiguration()
.getExpressionManager()
.createExpression(conditionExpression);
Object result = expression.getValue(execution);
PS: 前置条件:CommandContextUtil 这一类Utils在flowable中,会在Command获取缓存,直接调回导致 空指针
最终代码为:
package com.example.oldguy.modules.app.plugins;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.common.engine.impl.el.ExpressionManager;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.util.Map;
/**
* @ClassName: ExpressTestCmd
* @Author: hrh
* @Description:
* @Version:
**/
public class ExpressTestCmd implements Command<Object> {
private String conditionExpression;
private Map<String, Object> data;
public ExpressTestCmd(String conditionExpression, Map<String, Object> data) {
this.conditionExpression = conditionExpression;
this.data = data;
}
@Override
public Object execute(CommandContext commandContext) {
ExpressionManager expressionManager = CommandContextUtil.getProcessEngineConfiguration().getExpressionManager();
Expression expression = expressionManager.createExpression(conditionExpression);
DelegateExecution delegateExecution = new ExecutionEntityImpl();
delegateExecution.setTransientVariables(data);
return expression.getValue(delegateExecution);
}
}
测试调用:
@SpringBootTest
public class ExpressTests0924 {
@Autowired
private ManagementService managementService;
@Test
public void test() {
// String expression = "${a==1}";
String expression = "${variables:substr(a1,index1,end1)}${variables:substr(a2,index2)}";
// String expression = "${substr(a1,index1,end1)}";
Map<String, Object> data = new HashMap<>();
data.put("a1", "东方");
data.put("a", "1");
data.put("index1", 0);
data.put("end1", 2);
data.put("a2", "方不败");
data.put("index2", 1);
Object result = managementService.executeCommand(new ExpressTestCmd(expression, data));
System.out.println(result);
}
}
返回结果:
最后在调用异常的时候,需要对异常进行处理(下面只示例参数传输不完整)
org.flowable.common.engine.impl.javax.el.PropertyNotFoundException 传值不完整时候。