跳到主要内容
← 返回博客

本文涉及的模块: Integration Flow Helper

SAP CPI 中的 Camel Simple 表达式:header、属性与 ${…} 用法示例

SAP CPI 中 Camel Simple 表达式的工作方式:${header.x}、${property.x}、${in.body}、日期、Content Modifier 的求值顺序、Router 条件,以及让表达式返回空值的常见错误。

SAP CPI 中的 Camel Simple 表达式:header、属性与 ${…} 用法示例

SAP Cloud Integration(SAP CPI)iFlow 中几乎所有动态值都用 Apache Camel 的 Simple 表达式语言编写:接收方地址中的 header、Content Modifier 中的属性、文件名中的日期、Router 上的条件。语法很短,就是 ${…},但很容易在不知不觉中写错一点。

本文介绍你每天都会用到的表达式、Content Modifier 求值的顺序、header 与 exchange property 的区别,以及让表达式悄无声息地返回空值的常见错误。

SAP CPI 中的 Simple 表达式是什么

SAP Integration Suite 在 Apache Camel 上运行每个 iFlow。某个步骤执行时,Camel 会把字段中的每个 ${…} 替换为当前消息中的值:header、exchange property、消息体,或当前日期之类的内置函数。表达式周围的文本保持不变,因此 Order-${header.orderId}.xml 会变成 Order-4711.xml。

你可以在 Content Modifier 中类型为 Expression 的值和消息体中、许多接收方适配器的地址和查询字段中、类型为 Non-XML 的 Router 和 Filter 条件中,以及邮件主题或 SFTP 文件名等字段中编写 Simple 表达式。外部化参数看起来相似,但并不相同:{{receiverHost}} 只在部署 iFlow 时替换一次,而 ${…} 会针对每条消息求值。

每天都会用到的表达式

少数几个表达式就能覆盖大多数 iFlow,而且可以与普通文本自由混用。例如,Content Modifier 的消息体可以用 header、属性和函数拼出一整份 XML 文档:

<Order>
  <Id>${property.orderId}</Id>
  <Customer>${header.customerId}</Customer>
  <ReceivedOn>${date:now:yyyy-MM-dd}</ReceivedOn>
  <Flow>${camelId}</Flow>
  <MessageLog>${property.SAP_MessageProcessingLogID}</MessageLog>
</Order>
表达式返回值
${header.orderId}消息 header orderId
${property.orderId}exchange property orderId(Camel 也接受 ${exchangeProperty.orderId})
${in.body} 或 ${body}以文本形式返回当前消息体
${date:now:yyyy-MM-dd}按指定 Java 日期格式返回今天的日期
${camelId}正在运行的集成流的名称
${property.SAP_MessageProcessingLogID}当前消息处理日志的 ID
${header.CamelHttpResponseCode}上一次 HTTP 调用返回的状态码

Content Modifier 如何对 header、属性和消息体求值

Content Modifier 按固定顺序处理各个选项卡:先是 Message Header 表,然后是 Exchange Property 表,最后是 Message Body。在每张表内,各行从上到下依次执行。

这个顺序决定了表达式能看到什么。属性行可以读取同一个 Content Modifier 中先前设置的 header,消息体则两者都能使用。header 行无法读取同一个 Content Modifier 设置的属性,因为在对 header 求值时该属性还不存在,读到的是空值。如有需要,请在更早的 Content Modifier 中设置该属性,或把这个值移到排在前面的 header 表中。

  • 源类型 Expression:值是一个 Simple 表达式,例如 ${date:now:yyyyMMdd}-${header.orderId}。
  • 源类型 Header 或 Property:按名称复制另一个 header 或属性,名称两侧不加 ${…}。
  • 源类型 XPath:从 XML 消息体中读取值(参见下方链接的 XPath 文章)。
  • 源类型 Constant、Local Variable、Global Variable 和 Number Range 用于固定值和存储的值。

header 还是 exchange property:该用哪个

header 随消息一起传递。接收方适配器可以把 header 发送到你调用的系统,header 也会随 ProcessDirect 调用传到另一个 iFlow。exchange property 只留在当前 iFlow 的 exchange 中,自身永远不会被发送给接收方。

大多数意外来自两个细节。header 名称不区分大小写,因此 ${header.OrderID} 和 ${header.orderid} 读取的是同一个 header。exchange property 名称区分大小写,因此 ${property.OrderID} 和 ${property.orderId} 是两个不同的属性,而后者可能根本不存在。

  • 只在本 iFlow 内需要的值请用属性:ID、计数器、标志、保存下来的负载副本。
  • 需要由适配器或下一个 iFlow 接收的值请用 header,并删除不应离开 tenant 的 header。
  • 不要把大值放进 header:它们会随每次调用一起传递。

Router 和 Filter 中的 Simple 条件

在 Router 路由或类型为 Non-XML 的 Filter 中,条件是一个与某个值比较的 Simple 表达式。常用运算符有 =、!=、>、>=、<、<=、contains、in 和 regex,可用 and 或 or 连接。文本值放在单引号中:

${header.orderType} = 'EXPRESS'
${property.amount} > 1000 and ${header.country} in 'DE,AT,CH'
${header.CamelHttpResponseCode} != '200'

如果条件中的 header 或属性不存在,条件就直接为 false,消息会走另一条路由,通常是默认路由。关于未知 header 和属性的文章介绍了如何在上线生产之前发现这类问题。

Kitegra 如何帮你

Kitegra 是一款面向 SAP Integration Suite 设计器的浏览器扩展。在设计器字段中输入 ${ 或 $,它就会列出在 iFlow 当前位置适用的名称:在 Content Modifier、Groovy 和 JavaScript 脚本以及 iFlow 其他位置设置的 header 和属性,SAP 和 Camel 的标准 header 与表达式,{{…}} 参数、变量以及 Data Store 名称。只在部分路径上设置的名称会标注为“仅在部分路径上设置”。

它的 Lint 面板会标出未闭合的 ${、表达式内多余的空格,以及 iFlow 中没有任何地方设置的 header 或属性。对于 XPath 行,提供示例负载后还能获得路径提示,详见 XPath 文章。它从不保存、部署或编辑 iFlow 的内容;只有在你点击四个指定操作之一时,tenant 才会发生变化,而且这些操作可以关闭。

想看看表达式在运行时实际得到什么值?请逐步跟踪消息,查看每个步骤之前的 header 和属性。

没有 Kitegra 账户时,每个模块可用于 5 个 iFlow。Free 套餐涵盖 50 个,Starter 100 个,Pro 300 个。在团队套餐中,每位成员都享有 Pro:Startup Team 每个模块 300 个 iFlow,Growth Team 和 Scale Team 不限。Kitegra 上线期间,所有工具向所有已登录用户开放,Free 套餐也不例外。比较各套餐。

在下一个 iFlow 中试试

了解 Kitegra 在 SAP Integration Suite 设计器中能做什么,或在 Kitegra 的其他 Chrome 扩展旁查看它。

常见问题

SAP CPI 中 ${header.x} 和 ${property.x} 有什么区别?

${header.x} 读取消息 header,它随消息传递,可以到达接收方和其他 iFlow。${property.x} 读取 exchange property,它只留在当前 iFlow 内。

header 和属性名称区分大小写吗?

header 名称不区分:${header.OrderID} 和 ${header.orderid} 读取的是同一个 header。exchange property 名称区分,因此 ${property.OrderID} 和 ${property.orderId} 是不同的属性。

为什么在同一个 Content Modifier 中用属性设置的 header 是空的?

Content Modifier 先对 header 表求值,然后是属性表,最后是消息体。header 无法读取同一步骤中设置的属性;请在更早的步骤中设置该属性。

如何把今天的日期放进文件名或字段中?

使用 ${date:now:yyyy-MM-dd},可配合任意 Java 日期格式,例如用 ${date:now:yyyyMMddHHmmss} 生成时间戳。

{{parameter}} 是 Simple 表达式吗?

不是。{{…}} 表示外部化参数,只在部署 iFlow 时替换一次。${…} 则由 Camel 针对每条消息求值。

如果表达式引用了不存在的 header 会怎样?

它会返回空值且不报任何错误,问题会在之后以错误的路由或空字段的形式出现。Lint 检查或守卫步骤可以更早发现它。

无需离开设计器即可处理 iFlow

将 Kitegra 添加到 Chrome 或 Microsoft Edge。免费开始,无需账户。