Apache Camel and Spring Boot

This article has covered the integration of Apache Camel with the Spring Boot framework .





1. Introduction

Apache Camel β€” , . Apache Camel , , Camel 80 API . ,  β€”  β€” , Camel . ,  Apache Camel Spring Boot.





 Spring Boot, Camel.





1.1.

(message) β€” , .





1.2.

(exchange) β€” , . , .





1.3. Camel

Camel (CamelContext) β€” Camel, (,  .).





1.4.

(routes) β€” , . , DSL, ().





1.5. -

- (Domain-Specific Language, DSL) β€” . DSL β€” Java Fluent API, Camel / XML - DSL.





1.6.

(processor) . , , .





1.7.

(component) β€” Apache Camel. Camel .   , Camel. (URI).





1.8.

(endpoint) β€” , . , (URI). , FTP, URI: ftp://[@][:]/[?] β€” FTP .





1.9.

(producer) β€” Camel, .





1.10.

(consumer) β€” Camel, , , exchange .





Camel . , Camel . Spring Boot.





2.

:





  • : ;





  • ;





  • (Camel Timer + Camel JPA);





  • REST (Camel REST);





  • Swagger (Camel Swagger).





H2, Spring Web, Spring JPA Apache Camel.





3.

. ,  IDE  Spring Initializr. pom.xml :





<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <!--Get required dependencies from a parent-->
   <parent>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-dependencies</artifactId>
      <version>3.3.0</version>
   </parent>
   <artifactId>spring-boot-camel</artifactId>
   <name>spring-boot-camel</name>
   <description>Spring Boot Camel integration tutorial</description>
   <properties>
      <spring-boot-version>2.2.7.RELEASE</spring-boot-version>
      <run.profiles>dev</run.profiles>
   </properties>
   <dependencyManagement>
      <dependencies>
         <!--Import as a pom to let spring-boot to manage spring-boot dependencies version -->
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot-version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
         <!--Import as a pom to let camel manage camel-spring-boot dependencies version-->
         <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-spring-boot-dependencies</artifactId>
            <version>${project.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>
   <dependencies>
      <!--Spring boot dependencies to enable REST, JPA and Core features-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      <!--Camel Spring Boot Dependencies to enable REST, JSON, SWAGGER, JPA features-->
      <dependency>
         <groupId>org.apache.camel.springboot</groupId>
         <artifactId>camel-spring-boot-starter</artifactId>
      </dependency>
      <dependency>
         <groupId>org.apache.camel.springboot</groupId>
         <artifactId>camel-servlet-starter</artifactId>
      </dependency>
      <dependency>
         <groupId>org.apache.camel.springboot</groupId>
         <artifactId>camel-jackson-starter</artifactId>
      </dependency>
      <dependency>
         <groupId>org.apache.camel.springboot</groupId>
         <artifactId>camel-swagger-java-starter</artifactId>
      </dependency>
      <dependency>
         <groupId>org.apache.camel.springboot</groupId>
         <artifactId>camel-jpa-starter</artifactId>
      </dependency>
      <!--In memory database-->
      <dependency>
         <groupId>com.h2database</groupId>
         <artifactId>h2</artifactId>
         <scope>runtime</scope>
      </dependency>
      <!--Spring boot testing-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>${spring-boot-version}</version>
            <executions>
               <execution>
                  <goals>
                     <goal>repackage</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
</project>
      
      



4.

Apache Camel, , .





4.1.

«» : , , . , Camel . « » , .





@Entity
@Table(name = "products")
@NamedQuery(name = "discounted-products", query = "select product from Product product where product.discounted IS NOT NULL")
public class Product {

 @Id
 @GeneratedValue
 private int id;

 private String name;

 private Integer price;

 private Integer discounted;

 // Getters and setters
}
      
      



ProductRepository,  CrudRepository



  Spring Data. : findAll, findById, save . .





public interface ProductRepository extends CrudRepository<Product, Integer> {
}
      
      



4.2.

 ProductService  (service). ProductRepository Spring, .  findById



findAll



save



, .





@Service
public class ProductService {

    private final ProductRepository products;

    @Autowired
    public ProductService(ProductRepository products) {
        this.products = products;
    }

    public Product findById(Integer id) {
        Optional < Product > product = products.findById(id);
        if (!product.isPresent()) {
            throw new IllegalStateException("Product could not found for given id:" + id);
        }
        return product.get();
    }

    public Iterable < Product > findAll() {
        return products.findAll();
    }

    public void save(Product product) {
        products.save(product);
    }
}
      
      



,  data.sql



  src/main/resources



  , . Spring  data.sql



.  .





INSERT INTO products (id, name, price, discounted)
  VALUES
      (1, 'Book', 25, NULL),
      (2, 'Watch', 100, NULL),
      (3, 'Shoes', 40, NULL);
      
      



4.3.

«» : , . , «» OneToOne.





@Entity
@Table(name = "discounts")
public class Discount {

    @Id
    @GeneratedValue
    private int id;

    private Integer amount;

    @OneToOne
    private Product product;

    // Getters and setters
}
      
      



DiscountRepository, .





public interface DiscountRepository extends CrudRepository<Discount, Integer> {}
      
      



DiscountService ProductService.  findDiscount



,  findProduct



,  makeDiscount



. , .





@Service
public class DiscountService {

    private final DiscountRepository discounts;
    private final ProductService productService;

    private final Random random = new Random();

    @Autowired
    public DiscountService(DiscountRepository discounts,
        ProductService productService) {
        this.discounts = discounts;
        this.productService = productService;
    }

    public Discount makeDiscount() {
        // create a discount
        Discount discount = new Discount();
        int discountRate = this.random.nextInt(100);
        discount.setAmount(discountRate);

        // select random product
        int productId = this.random.nextInt(3) + 1;
        Product product = productService.findById(productId);

        // set the discount to product and save
        int discountedPrice = product.getPrice() - (discountRate * product.getPrice() / 100);
        product.setDiscounted(discountedPrice);
        productService.save(product);

        discount.setProduct(product);
        return discount;
    }

    public Discount findDiscount(Integer id) {
        Optional < Discount > discount = discounts.findById(id);
        if (!discount.isPresent()) {
            throw new IllegalStateException("Discount could not found for given id:" + id);
        }
        return discount.get();
    }
}
      
      



5.

 application-dev.yml



,  contextPath



  Camel. , .





camel:
  component:
    servlet:
      mapping:
        contextPath: /javadevjournal/*

discount:
  newDiscountPeriod: 2000
  listDiscountPeriod: 6000/pre>
      
      



6. Apache Camel

, Apache Camel. .





6.1.

Camel : RouteBuilder.  @Component



. , Apache Camel . SpringBoot Camel SpringBoot,  CamelContext



,  RouteBuilder



  .





RouteBuilder . , . :





@Component
class TimedJobs extends RouteBuilder {

@Override
public void configure() {
        from("timer:new-discount?delay=1000&period={{discount.newDiscountPeriod:2000}}")
            .routeId("make-discount")
            .bean("discountService", "makeDiscount")
            .to("jpa:org.apache.camel.example.spring.boot.rest.jpa.Discount")
            .log("Created %${body.amount} discount for ${body.product.name}");

        // additional route will be added in the next step
}
      
      



Spring Boot Camel.  ,  Java DSL.  β€”  timer, Camel . «» Camel : ( ) .





, , Apache Camel Spring Boot, . , : {{_:__}}



.





make-discount, . makeDiscount bean- discountService. , , , . , ,   Simple. , .





from("jpa:org.apache.camel.example.spring.boot.rest.jpa.Product"
    + "?namedQuery=discounted-products"
    + "&delay={{discount.listDiscountPeriod:6000}}"
    + "&consumeDelete=false")
    .routeId("list-discounted-products")
    .log(
        "Discounted product ${body.name}. Price dropped from ${body.price} to ${body.discounted}");
      
      



JPA «», namedQuery



. JPA , - , .  consumeDelete



 , «». JPA. :





Created %27 discount for Watch
Created %84 discount for Book
Created %92 discount for Shoes
Discounted product Book. Price dropped from 25 to 4
Discounted product Watch. Price dropped from 100 to 73
Discounted product Shoes. Price dropped from 40 to 4
      
      



6.2. REST

. REST Swagger.  RouteBuilder



. Camel restConfiguration



.





@Component
class RestApi extends RouteBuilder {

@Override
public void configure() {
        restConfiguration()
            .contextPath("/javadevjournal")
            .apiContextPath("/api-doc")
            .apiProperty("api.title", "JAVA DEV JOURNAL REST API")
            .apiProperty("api.version", "1.0")
            .apiProperty("cors", "true")
            .apiContextRouteId("doc-api")
            .port(env.getProperty("server.port", "8080"))
            .bindingMode(RestBindingMode.json);

        rest("/products").description("Details of products")
            .get("/").description("List of all products")
            .route().routeId("products-api")
            .bean(ProductService.class, "findAll")
            .endRest()
            .get("discounts/{id}").description("Discount of a product")
            .route().routeId("discount-api")
            .bean(DiscountService.class, "findDiscount(${header.id})");
    }
}
      
      



 contextPath



 β€” javadevjournal β€” - API β€” api-doc



, Swagger. . Jackson JSON pom.xml, JSON.   .  /products



   ProductService.findAll.  /products



/discounts/{id}



, DiscountService.findDiscount



id, . {header}



  ,   Simple,   {body}



.





 http://localhost:8080/javadevjournal/api-doc



, Swagger.  http://localhost:8080/javadevjournal/products



,  :





[
    {
        "id": 1,
        "name": "Book",
        "price": 25,
        "discounted": 4
    },
    {
        "id": 2,
        "name": "Watch",
        "price": 100,
        "discounted": 73
    },
    {
        "id": 3,
        "name": "Shoes",
        "price": 40,
        "discounted": 4
    }
]
      
      



,  http://localhost:8080/javadevjournal/products/discounts/1



,  :





{
    "id": 1,
    "amount": 92,
    "product": {
        "id": 3,
        "name": "Shoes",
        "price": 40,
        "discounted": 4
    }
}
      
      



,   Apache Camel Spring Boot. , Apache Camel Spring Boot .  Github.






" Spring Framework".





14 demo day - , , -, , , .





DEMO DAY









All Articles