點擊查看原文 Apache Camel - Transforming Data
集成工具是屬于構造企業(yè)服務總線 ESB 的基礎终息,勢必會處理不同組件不同格式的消息逗鸣,那么數據轉換也就是繼承工具包括 Camel 的關鍵特性。
數據轉換(Data Transformation)可以分為兩種類型:
- 數據格式轉換 Data format transformation - 消息體的數據格式從一種轉換成另外一種帘饶,例如CSV格式轉換成XML格式
- 數據類型轉換 Data type transformation - 消息體的數據類型從一種轉換成另外一種哑诊,例如 java.lang.String 轉換成 javax.jms.TextMessage
Camel 對數據格式和數據類型的轉換有幾種方式:
- Data formats - XML, JSON ...
- Expression - Languages
- Java - Processor, Bean, Content Enricher
- Templates - XSLT, Apache Velocity ...
Data formats
Data formats 在 Camel 里以可插拔的轉換器形式存在。每個 data format 實現了接口 org.apache.camel.spi.DataFormat
并包含兩個方法:
-
marshal
- 把一個 Message 編譯成常見的數據格式及刻,例如編譯java對象成 XML, CSV, Json 等 -
unmarshal
- 反編譯镀裤,把常見數據格式轉換成 Message
Data formats 可以用在 Java DSL 和 XML DSL 中:
- 用在 Java DSL 中
from("file://rider/csvfiles")
.unmarshal().csv()
.split(body()).to("activemq:queue.csv.record");
- 用在 XML DSL 中
<route>
<from uri="file://rider/csvfiles"/>
<unmarshal><csv/></unmarshal>
<split>
<simple>body</simple>
<to uri="activemq:queue.csv.record"/>
</split>
</route>
Camel 支持的 Data formats 完整列表參見 Apache Camel > Documentation > Architecture > Data formats.
XML Json
企業(yè)集成開發(fā)中常用的兩種數據格式 XML 和 Json,經常需要相互轉換缴饭。camel-xmljson
組件是用來做 XML 和 Json 之間轉換的暑劝。
- marshalling => converting from XML to JSON
- un-marshaling => converting from JSON to XML.
添加此組件依賴包:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-xmljson</artifactId>
<version>x.x.x</version>
<!-- Use the same version as camel-core, but remember that this component is only available from Camel 2.10 -->
</dependency>
<!-- And also XOM must be included. XOM cannot be included by default due to an incompatible
license with ASF; so add this manually -->
<dependency>
<groupId>xom</groupId>
<artifactId>xom</artifactId>
<version>1.2.5</version>
</dependency>
在 Java DSL 中使用此 Data format:
// From XML to JSON - inline dataformat
from("direct:marshalInline")
.marshal().xmljson()
.to("mock:jsonInline");
// From JSON to XML - inline dataformat
from("direct:unmarshalInline")
.unmarshal().xmljson()
.to("mock:xmlInline");
更多設置參見Apache Camel > Documentation > Architecture > Data Format > XmlJson
Expression
Expressions and Predicates (expressions that evaluate to true or false) can then be used to create the various Enterprise Integration Patterns in the DSL or Xml Configuration like the Recipient List.
To support dynamic rules Camel supports pluggable Expression strategies using a variety of different Languages.
表達式 Expression 是使用不同的語言 Languages 書寫,常用的語言例如:Simple Language, XPath, Scripting Languages, Constant 等等颗搂。
例如 Simple Language 書寫的表達式: Hello ${body}
担猛,也可以用作斷言如 ${body} == 'Camel'
, ${header.zip} between '30000..39999'
。
通常表達式會作為獲取 Message Body Header Properties 值的方式丢氢,斷言會作為 Route 判斷的依據傅联。
Transform
Transform 是 Camel route DSL 中的一個方法,它接受一個 Expression 作為參數疚察,執(zhí)行表達式的結果作為轉換后的 Message Body 蒸走。Transform 可以用在 Java DSL 和 XML DSL 中,例如在 Java DSL 中使用 Transform 與 Simple language:
from("direct:start")
.transform().simple("Hello ${body}!")
.to("mock:result");
如果是使用 JavaScript 語言的表達式:
from("direct:start")
.transform().javaScript("'Hello ' + request.body + '!'")
.to("mock:result");
Java
如果 Camel 提供的 Data formats 和 Expression 不能滿足你所需要的邏輯書寫的話貌嫡,你可以還需要寫一些 Java 邏輯比驻。
可以編寫 Java 邏輯的方式有幾種:
- Processor
- Beans
- Content Enricher
Processor
The Camel Processor
is an interface defined in org.apache.camel.Processor
with a
single method:
public void process(Exchange exchange) throws Exception;
它可以任意處理傳入的 Exchange 對象该溯。
from("direct:start")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody("Hello " + exchange.getIn().getBody() + "!");
}
})
.to("mock:result");
Beans
Camel 使用了類似于 Spring Framework POJO 的輕量級 Bean 管理容器。Camel 的 Bean 管理注冊表(registry)是一個 Service Provider Interface (SPI)嫁艇,它實現了接口 org.apache.camel.spi.Registry
朗伶。常見的實現有:
- SimpleRegistry - A simple implementation to be used when unit testing or running Camel in the Google App engine, where only a limited number of JDK classes are available.
- JndiRegistry - An implementation that uses an existing Java Naming and Directory Interface (JNDI) registry to look up beans.
- ApplicationContextRegistry - An implementation that works with Spring to look up beans in the Spring ApplicationContext. This implementation is automatically used when you’re using Camel in a Spring environment.
- OsgiServiceRegistry - An implementation capable of looking up beans in the OSGi service reference registry. This implementation is automatically used when using Camel in an OSGi environment.
在 Java DSL 中使用 Bean,指定 Bean 的標識和想要調用的方法名稱:
public void configure() throws Exception {
from("direct:hello").beanRef("helloBean", "hello");
}
也可以只指定 Bean 的 Class步咪,Camel 會在 startup 時初始化 Bean论皆,并在調用時根據 Message Body data type 去匹配方法的參數類型并決定實際調用哪個方法:
public void configure() throws Exception {
from("direct:hello").bean(HelloBean.class);
}
Camel 調用 Bean 時還支持很多 Camel annotations
public String orderStatus(@Body Integer orderId, @Headers Map headers) {
Integer customerId = (Integer) headers.get("customerId");
String customerType = (String) headers.get("customerType");
...
}
和 Camel language annotations
public Document handleIncomingOrder( @Body Document xml,
@XPath("/order/@customerId") int customerId,
@Bean(ref = "guid", method="generate") int orderId );
Content Enricher
Content Enricher 模式是一種 Message Transformation 模式。
它分為 Poll enrich 和 Enrich 兩種方式猾漫。
Pollenrich
from("quartz://report?cron=0+0+6+*+*+?")
.to("http://riders.com/orders/cmd=received")
.process(new OrderToCSVProcessor())
.pollEnrich("ftp://riders.com/orders/?username=rider&password=secret",
new AggregationStrategy() {
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (newExchange == null) {
return oldExchange;
}
String http = oldExchange.getIn().getBody(String.class);
String ftp = newExchange.getIn().getBody(String.class);
String body = http + "\n" + ftp;
oldExchange.getIn().setBody(body);
return oldExchange;
}
})
.to("file://riders/orders");
Enrich
Templates
對于更高級的數據轉換我們還可以使用 Template 技術点晴,如 XSLT, Apache Velocity, FreeMarker 等。
XSLT
XSLT (Extensible Stylesheet Language Transformations) ) is a language for transforming XML documents into other XML documents or other formats such as HTML for web pages, plain text or XSL Formatting Objects, which may subsequently be converted to other formats, such as PDF, PostScript and PNG.[2] XSLT 1.0 is widely supported in modern web browsers.
XSLT 是一個 Camel 組件悯周,所以使用其 endpoint uri:
from("file://rider/inbox")
.to("xslt://camelinaction/transform.xsl")
.to("activemq:queue:transformed")
Velocity
Apache Velocity is a Java-based template engine that provides a template language to reference objects defined in Java code. It aims to ensure clean separation between the presentation tier and business tiers in a Web application (the model–view–controller design pattern).
Camel Type Converters
Camel 有一套數據類型轉換系統(tǒng)粒督,當 Camel 遇到 From Type 和 To Type 不同時,會去 Type Converters 注冊系統(tǒng)查找相應的 Converter 禽翼,如果存在相應的 Converter 則使用其轉換數據類型屠橄,否則會報出異常。
自定義的 Converter 如下:
@Converter
public final class PurchaseOrderConverter {
@Converter
public static PurchaseOrder toPurchaseOrder(byte[] data, Exchange exchange) {
TypeConverter converter = exchange.getContext().getTypeConverter();
String s = converter.convertTo(String.class, data);
if (s == null || s.length() < 30) {
throw new IllegalArgumentException("data is invalid");
}
s = s.replaceAll("##START##", "");
s = s.replaceAll("##END##", "");
String name = s.substring(0, 9).trim();
String s2 = s.substring(10, 19).trim();
BigDecimal price = new BigDecimal(s2);
price.setScale(2);
String s3 = s.substring(20).trim();
Integer amount = converter.convertTo(Integer.class, s3);
return new PurchaseOrder(name, price, amount);
}
}
本文相關代碼完整項目 Github