使用 Apache Camel 创建 REST 服务

让我们使用 Camel 的 REST DSL 创建一个 REST 服务!请参阅使用 Apache Camel 和 Spring Boot 实现 REST API 的示例。

您已经 了解了 Apache Camel 的 一些基础知识 。您现在知道如何处理消息。伟大的!下一个是什么?

您可能想要开始使用 Web 服务。

因此,在本教程中,我将展示如何使用 Camel从应用程序 公开 REST 端点

我将介绍您开始所需的依赖项和配置。最后,有一个示例供您参考,以便您了解如何使用 Apache Camel 和 Spring Boot 创建自己的 RESTful 服务。

如果您不熟悉 Apache Camel,那么我鼓励您阅读我的 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 服务 JAX-RS 规范的 一种实现。因此,如果您正在考虑使用 JAX-RS 标准来定义您的 REST 服务,那么您可以使用 Camel 使用 CXF 为您引导您的服务。查看 CXFRS 组件 以获取更多信息。

使用 Camel 为现有的 REST 服务提供业务逻辑 :如果您已经在应用程序的其他地方公开了 REST 服务——例如使用 JAX-RS 或 Spring Rest——那么您可以使用 Camel 来实现实际的业务逻辑,如果你喜欢。

例如,您可能已经编写了一个包含使用 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">
        <route>
            <to uri="direct:getCustomers"/>
        </route>
        <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})"/>
</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 对象之间自动转换,这样我们就不必自己搞砸了

要创建服务,请按照下列步骤操作:

创建一个新的 Camel Spring Boot 项目

在您的 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 动词(例如getpost和 )开始每个操作,而不是delete

像这样做:

 rest("/api/customers")
     .get().route().to("...")
     .post().route().to("...")
     .delete().route().to("...");

XML DSL

<rest path="/api/customers">
     <route>
         <to uri="..."/>
     </route>
     <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">
   <route>
       <to uri="bean:customerService?method=listCustomers"/>
   </route>
   <route>
       <to uri="direct:post"/>
   </route>
 </post>
 </rest>

正如你所看到的,GET操作通过一个beancustomerService传递服务的请求。但是POST操作将请求传递给一个直接分量direct: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。

只是想看看完整的、有效的例子?单击下面的按钮查看完整示例:

获取示例代码 在 GitHub 上

HTTP 动词 获取/检索实体 GET /customers/:id 创建一个新实体 POST /customers 更新现有实体 PUT /customers/:id/tags
DELETE 删除现有实体 DELETE /customers/:id