groovy - Activiti:使用 activiti:expression 定义可重用的 ScriptTaskListener 脚本
问题描述
我想在某处定义脚本源代码并从 Activiti 5.12 或更高版本中的多个 ScriptTaskListener 重用它。
假设我taskScript
在之前的 groovy 脚本任务中定义了一个 processVariable,其中包含 groovy 源代码:
execution.setVariable("taskScript",
'def log = org.slf4j.LoggerFactory.getLogger("my.Logger");log.info("works")')
现在我想org.activiti.engine.impl.bpmn.listener.ScriptTaskListener
通过将它作为一个来使用该代码activiti:expression
:
<activiti:taskListener event="complete" class="org.activiti.engine.impl.bpmn.listener.ScriptTaskListener" >
<activiti:field name="script">
<activiti:expression><![CDATA[${taskScript}]]></activiti:expression>
</activiti:field>
<activiti:field name="language" stringValue="groovy" />
</activiti:taskListener>
我得到以下异常:
javax.script.ScriptException: groovy.lang.MissingMethodException:
No signature of method: org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.$()
is applicable for argument types: (Script657$_run_closure1)
${taskScript}
在 Activiti 将表达式传递给 ScriptTaskListener 属性之前,似乎没有对表达式进行评估script
,而是 groovy 引擎尝试将其${taskScript}
作为 groovy 脚本进行评估。
但是,这可以正常工作:
<activiti:taskListener event="complete" class="org.activiti.engine.impl.bpmn.listener.ScriptTaskListener" >
<activiti:field name="script">
<activiti:string>
def log = org.slf4j.LoggerFactory.getLogger("my.Logger");
log.info("works")
</activiti:string>
</activiti:field>
<activiti:field name="language" stringValue="groovy" />
</activiti:taskListener>
我很困惑为什么我不能这样做。activiti:expression
在应用于activiti:field
?
是否有不同的方法可以在 ScriptTaskListeners 中重用脚本代码?
解决方案
关键是 ScriptTaskListener 如何评估表达式。它不计算 UEL 表达式并将其传递给 Groovy,而是只让 Groovy 引擎计算表达式。我们需要将 groovy 脚本作为表达式而不是${taskScript}
UEL 表达式传递。
事实证明这是有效的:
<activiti:expression><![CDATA[
try {
evaluate(task.getVariable("taskScript"));
} catch (ex) {
def log = org.slf4j.LoggerFactory.getLogger("my.Logger");
log.warn("failed to invoke taskScript", ex)
}
]]>
</activiti:expression>
评估调用必须与 try..catch 嵌套,因为侦听器中的异常会阻止事件被处理,因此您的进程将永久停止。
推荐阅读
- flutter - 使用带有大量数据的 Dio 发送请求时,Flutter 应用程序正在关闭
- mysql - SQLAlchemy 无法连接到 Kubernetes 本地主机上的 Mysql 服务器
- c - PNG 文件被截断,不能由每个应用程序显示
- python-3.x - 如何将 DataFrame(包括数组)中的两列与 CSV(Dataframe/Dictionary)中的两列匹配
- python - 在类外调用变量
- can-bus - 在 CANopen 中发送超过 8 字节数据的事件(异步数据)
- javascript - DJANGO:如何在views.py中获取表单值而不提交它
- pyspark - 根据其他列的值将小时数添加到数据框中的时间戳列
- java - java - 如何使用java swing中其他包中不同类的数据更新UI
- python - 熊猫系列中的熊猫数据框