이 글의 모듈: Integration Flow Helper
SAP CPI Camel Simple 표현식: header, 속성, ${…} 사용법과 예제
SAP CPI에서 Camel Simple 표현식이 동작하는 방식: ${header.x}, ${property.x}, ${in.body}, 날짜, Content Modifier 평가 순서, Router 조건, 아무것도 반환하지 않게 만드는 실수를 다룹니다.

SAP Cloud Integration(SAP CPI) iFlow의 동적인 값은 거의 모두 Apache Camel의 Simple 표현식 언어로 작성합니다. 수신기 주소에 들어가는 header, Content Modifier의 속성, 파일 이름의 날짜, Router의 조건 등이 그렇습니다. 문법은 ${…}로 짧지만, 모르는 사이에 살짝 틀리기 쉽습니다.
이 글에서는 매일 쓰게 될 표현식, Content Modifier가 표현식을 평가하는 순서, header와 exchange property의 차이, 그리고 표현식이 조용히 아무것도 반환하지 않게 만드는 실수를 설명합니다.
SAP CPI의 Simple 표현식이란
SAP Integration Suite는 각 iFlow를 Apache Camel 위에서 실행합니다. 단계가 실행되면 Camel은 필드에 있는 모든 ${…}를 현재 메시지의 값으로 바꿉니다. header, exchange property, 본문, 또는 현재 날짜 같은 내장 함수의 값입니다. 표현식 주변의 텍스트는 그대로 남기 때문에 Order-${header.orderId}.xml은 Order-4711.xml이 됩니다.
Simple 표현식은 Content Modifier에서 유형이 Expression인 값과 메시지 본문, 여러 수신기 어댑터의 주소와 쿼리 필드, 유형이 Non-XML인 Router와 Filter 조건, 그리고 메일 제목이나 SFTP 파일 이름 같은 필드에 쓸 수 있습니다. 외부화된 파라미터는 비슷해 보이지만 다릅니다. {{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를 읽습니다. 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 점검이나 가드 단계를 두면 더 일찍 잡아낼 수 있습니다.