讓我們使用 Camel 的 REST DSL 創建一個 REST 服務!請參閱使用 Apache Camel 和 Spring Boot 實現 REST API 的示例。
您已經
因此,在本教程中,我將展示如何使用 Camel從應用程序公開 REST 端點。
我將介紹您開始所需的依賴項和配置。最后,有一個示例供您參考,以便您了解如何使用 Apache Camel 和 Spring Boot 創建自己的 RESTful 服務。
如果您不熟悉 Apache Camel,那么我鼓勵您閱讀我的
基礎知識
如何使用 Camel 創建 REST 服務?
您現在可能已經知道 Camel 是一個用於在不同系統之間進行集成的框架。它通常不會自己做一些事情,而是創建和配置一些實際完成工作的東西(例如一個組件)。
在 Camel 中創建 REST 服務遵循幾乎相同的模式。為 Camel 編寫一些說明,它將使用一堆其他組件為您公開您的 REST 服務。您只需要准確選擇您希望服務實現的方式,Camel 將負責配置。
這意味着使用 Camel 創建 REST 服務有無數種不同的方式。因此,我不會涵蓋每一種不同的方法,而只是簡要提及您可以在 Apache Camel 中使用 REST 服務的主要方法。你可以:
-
使用 Camel 支持的組件之一公開一個 REST 服務:您使用 Camel 的 REST DSL 或 REST 組件定義您的 REST 服務操作,並選擇一個將被配置為實現您的服務的組件。然后,Camel 將使用該信息來引導組件、創建您的服務及其操作、將其部署到 Web 服務器(如 Jetty 或 Undertow)中,並為您生成 Swagger/OpenAPI 文檔。(這非常簡單,這就是我將在本教程中介紹的方式。)
-
使用 Camel 來引導使用 JAX-RS 的服務: Camel 與 Apache CXF 緊密集成,這是 Java 的Web 服務
-
使用 Camel 為現有的 REST 服務提供業務邏輯:如果您已經在應用程序的其他地方公開了 REST 服務——例如使用
例如,您可能已經編寫了一個包含使用
javax.ws.rs
注釋(@Path
、@GET
、@POST
等)注釋的方法的服務類,並且已經配置了您的實現(例如 CXF、Jersey 或 Resteasy)。如果是這樣,那么在您的服務方法中,您可以使用 Camel 的 Java API(ProducerTemplate
等)將消息發送到 Camel 路由,然后使用來自 Camel 的響應傳遞回您的使用者。
那么有沒有“最好的方法”呢?
嗯,不。:)
但在本教程中,我將向您展示我的首選方法。我們將使用 Camel 的 REST DSL 來配置服務並將其部署到嵌入式 Web 服務器中,該服務器在 Spring Boot 中運行。
使用 REST DSL 創建 REST 服務
那么如何在 Camel 中定義 REST 服務呢?最好的方法是使用 REST DSL。
REST DSL 是 Camel 現有路由構建語法的擴展,但專門用於描述 REST 服務。編寫和配置很容易。
在幕后,Camel 使用您的 REST DSL 代碼來配置實際提供REST 服務的底層組件。您現在不需要擔心這些細節,因為 Camel 會為您設置大部分默認值。
REST DSL 可以輕松定義 REST 服務,而無需了解太多底層細節或任何復雜的布線。
在非常高的層次上,當使用 Camel 創建 REST 服務時,我們需要做以下事情:
-
聲明我們的 RESTful 服務的端點和操作
-
選擇哪個組件將實現該服務(有關支持的組件列表,請參見下文)
-
添加代碼以使用參數
-
添加配置以獲取 Camel 以幫助我們處理 JSON 或 XML。
定義endpoints端點
和操作
為了定義我們服務的操作,我們可以使用 REST DSL 語法。Camel在 Camel 2.14 中引入了REST DSL。REST DSL 基本上是用於定義 REST 服務的 Camel 語法。
看起來有點像普通的Camel route…… 除了它以rest()
. 定義您使用的服務,rest(...)
然后是您的操作,其采用 HTTP 動詞的形式,例如.get()
和.post()
等。
在 Java DSL 中,它看起來像這樣:
rest("/api/customers") .get() .route() .to("direct:getCustomers") .post() .route() .to("file:output/customers");
在 Camel 的 XML DSL 中:
<rest path="/api/customers"> <get> <route> <to uri="direct:getCustomers"/> </route> </get> <post> <route> <to uri="file:output/customers"/> </route> </post> </rest>
REST 消費者還是 REST 生產者?當 Camel 公開或提供 REST 服務時,Camel 使用術語consumer,因為 Camel 正在通過 REST 消費提供給它的數據。另一方面,REST生產者是 Camel 消費或調用外部 REST 服務的地方。
配置實現
現在我們需要設置一些關於服務本身的信息。我們需要選擇哪個組件將實現服務,並設置任何屬性,如主機名和端口。
第一件事是選擇 Camel 應該引導哪個組件來實現您的 REST 服務。在這里,您可以選擇:
-
servlet
-
spark-rest
-
netty-http
-
jetty
選擇哪個組件完全取決於您,但是對於 Spring Boot 應用程序,我會選擇servlet,因為您已經擁有一個 Camel 可以用於 servlet (Tomcat) 的嵌入式 Web 服務器。
然后您可以在restConfiguration()
塊中設置此配置,如下所示:
// 定義實現組件 - 並接受默認主機和端口 restConfiguration().component("servlet"); // 定義組件和主機名和端口 restConfiguration().component("servlet") .host("localhost").port(8080);
使用參數
您的 REST API 可能需要接受來自使用者的參數。無論您是在正文、URL 還是在查詢字符串中使用參數,都可以輕松做到這一點。
POST 正文
像POST這樣的操作很容易。請求的正文將存儲在 Camel Exchange Body 中。所以你可以像這樣訪問它:
rest("/customers")
.post().log("The body is ${body}!");
網址參數
當您需要從 URL 中讀取參數(例如客戶 ID 或產品 ID)時,您需要:
-
在您的操作的 URI 中定義一個占位符,例如
/customers/{id}
-
稍后獲取您的輸入,使用同名的Header - 例如
${header.id}
這是一個示例 - 一個采用客戶 ID 的 REST 刪除操作。該參數{id}
在聲明uri
-如/customers/12345
。然后可以使用${header.id}
以下方法檢索它:
Java DSL
rest("/api/apartments") .get("/search?country={country}") .to("bean:searchBean?method=byCountry(${header.country})");
XML DSL
<rest path="/api/apartments"> <get uri="/search?country={country}"> <to uri="bean:searchBean?method=byCountry(${header.country})"/> </get> </rest>
設置 JSON 到 POJO 轉換
最后,我們需要弄清楚我們想要對我們的請求和響應消息做什么。如果您正在接收或發送 JSON,那么 Camel 如何提供幫助?
您可以手動編寫自己的 JSON 字符串,但它非常麻煩,而且編寫一大堆字符串連接也沒什么樂趣!
答案是對您的請求和響應類型使用 POJO。是的,Java 對象。當您將 POJO 用於輸入和輸出消息時,Camel 可以為您的 REST 服務使用者輕松地將這些消息與 JSON 進行相互轉換。如果 Jackson 在類路徑上,Camel 能夠做到這一點。
這是一個示例供您查看。首先,這是我編寫的一個名為ResponseType的類,它對來自我的 RESTful API 的響應進行建模。它包含一個字段,message
:
public class ResponseType { private String message; public ResponseType(String message) { this.message = message; } public String getMessage() { } return message; } public void setMessage(String message) { this.message = message; } }
為了讓 Camel 自動將其從我的 REST 服務編組為 JSON,我確保.outType()
設置了它,並且它引用了我的自定義ResponseType
類。這告訴 Camel 它應該期望將類型為ResponseType
的消息返回給消費者:
rest().path("/my-api")..... .get() .outType(ResponseType.class) .to("bean:helloBean"); // this sends the Body to the bean
由於我的 REST 操作的業務邏輯是在 Java bean 中實現的,我只需要確保我的業務邏輯方法返回一個類型為ResponseType
的對象:
public class HelloBean { public ResponseType sayHello() { return new ResponseType("Hello, world!"); } }
最后,我需要給 Camel 一個提示,將 JSON 綁定到 Java 對象。這是使用bindingMode
配置完成的,我添加到restConfiguration
塊中:
restConfiguration() .component("servlet") .bindingMode(RestBindingMode.auto);
或者,如果您願意,可以在 XML DSL 中:
<restConfiguration component="servlet" bindingMode="auto"/>
現在,當我使用curl測試服務時,HelloBean將返回一個ResponseType對象。Camel 將使用 Jackson 為我自動將其編組為 JSON - 請注意我如何獲得包含一個字段 的 JSON 對象message
,這就像我上面的示例 POJO:
$ curl http://localhost:8080/services/my-api {"message":"Hello, world!"}
示例 - 使用 REST DSL 在 Camel 中創建RESTful 服務
現在我們知道使用 Camel 創建 RESTful 服務需要什么——一個將實現服務的組件,以及一些 REST DSL 糖來配置它。這個例子將:
-
使用servlet組件托管 RESTful 服務
-
在默認的 Spring Boot Web 端口上運行,即 8080
-
在 JSON 和 Java 對象之間自動轉換,這樣我們就不必自己搞砸了
要創建服務,請按照下列步驟操作:
-
-
在您的 Maven POM 中,添加
camel-servlet-starter
為依賴項。這將允許 Camel 將我們的服務部署到嵌入式 Tomcat 容器中:<dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-servlet-starter</artifactId> </dependency>
-
添加
camel-jackson-starter
為依賴項。這將允許 Camel 編組到/從 JSON:<dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-jackson-starter</artifactId> </dependency>
-
在
RouteBuilder
新項目的 中,添加一個restConfiguration()
元素。這將初始化將提供REST 服務的組件。在這個例子中,我們為此使用了Servlet組件。
在為服務定義任何操作之前,我們首先執行此操作:
public void configure() throws Exception { restConfiguration() .component("servlet") .bindingMode(RestBindingMode.auto); }
-
定義一個 REST 端點,並為您的每個操作(GET、POST 等)添加框架。
首先,使用服務的路徑 (URI)定義 REST 端點
rest
。然后附加您的每個操作- 這些是您的 HTTP 動詞。REST 動詞/操作的語法看起來就像熟悉的 Camel 路由。但是,
from
我們使用您要使用的HTTP 動詞(例如get
、post
和 )開始每個操作,而不是delete
。像這樣做:
語言語言
rest("/api/customers") .get().route().to("...") .post().route().to("...") .delete().route().to("...");
XML DSL
<rest path="/api/customers"> <get> <route> <to uri="..."/> </route> </get> <post> <route> <to uri="..."/> </route> </post> </rest>
該在什么時候使用哪個 HTTP 動詞上?看到這篇文章的結尾,我寫了一個厚顏無恥的小備忘單。
-
現在為您的 REST 操作構建您的駱駝路線!以下是已填寫的 REST 服務示例:
Java DSL
rest("/customers") .get().route().to("bean:customerService?method=listCustomers") .post().route().to("jms:queue:CUSTOMERS");
XML DSL
<rest path="/customers"> <get> <route> <to uri="bean:customerService?method=listCustomers"/> </route> </get> <post> <route> <to uri="direct:post"/> </route> </post> </rest>
正如你所看到的,GET操作通過一個
bean
為customerService
傳遞服務的請求。但是POST操作將請求傳遞給一個 -
要添加對自動將請求和響應轉換為 JSON 的支持,請定義代表您的請求和響應消息的 POJO,例如:
public class CreateCustomerResponse { private String result; // Add some getters and setters here... }
現在,聲明您的請求和響應類型,以便 Camel 知道如何將它們編組到 JSON 或從 JSON 編組:
rest() .post() .route() .type(Customer.class) .outType(CreateCustomerResponse.class) .to("direct:post");
並確保您已在REST 配置中設置綁定模式:
restConfiguration() .component("servlet") .bindingMode(RestBindingMode.auto);
就是這樣!現在繼續使用您需要的盡可能多的端點和操作來構建您的 REST API。
只是想看看完整的、有效的例子?單擊下面的按鈕查看完整示例:
HTTP 動詞 | 何時使用 | 例子 |
---|---|---|
GET | 獲取/檢索實體 | GET /customers/:id |
POST | 創建一個新實體 | POST /customers |
PUT | 更新現有實體 | PUT /customers/:id/tags |
DELETE | 刪除現有實體 |