I’m learning Apache Camel in Spring Boot project and I try to create a Retful Webservice and the service is starting but the problem is that I get 404 when I call the endpoint.
@Component @RequiredArgsConstructor public class RestJavaDsl extends RouteBuilder { private final WeatherDataProvider weatherDataProvider; @Override public void configure() throws Exception { from("rest:get:javadsl/weather/{city}?produces=application/json") .outputType(WeatherDto.class) .process(this::getWeatherData); } private void getWeatherData(Exchange exchange) { String city = exchange.getMessage().getHeader("city", String.class); WeatherDto currentWeather = weatherDataProvider.getCurrentWeather(city); Message message = new DefaultMessage(exchange.getContext()); message.setBody(currentWeather); exchange.setMessage(message); } }
I created this class to hardcode some data:
@Component public class WeatherDataProvider { private static Map<String, WeatherDto> weatherData = new HashMap<>(); public WeatherDataProvider() { WeatherDto dto = WeatherDto.builder().city("London").temp("10").unit("C").receivedTime(new Date().toString()).id(1).build(); weatherData.put("LONDON", dto); } public WeatherDto getCurrentWeather(String city) { return weatherData.get(city.toUpperCase()); } public void setCurrentWeather(WeatherDto dto) { dto.setReceivedTime(new Date().toString()); weatherData.put(dto.getCity().toUpperCase(), dto); } } @Data @NoArgsConstructor @AllArgsConstructor @Builder public class WeatherDto implements Serializable { static int counter = 1; private int id = counter++; private String city; private String temp; private String unit; private String receivedTime; }
application.yml
camel: component: servlet: mapping: context-path: /services/*
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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.dgs</groupId> <artifactId>camel-rest-springboot</artifactId> <version>0.0.1-SNAPSHOT</version> <name>camel-rest-springboot</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> <camel.version>3.14.0</camel.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-spring-boot-starter</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-test</artifactId> <scope>test</scope> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jackson</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jaxb</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-servlet</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-servlet-starter</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-rest-starter</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
The serviceis starting and this is the console log:
2022-01-24 20:01:40.353 INFO 15796 --- [ main] c.d.c.CamelRestSpringbootApplication : Starting CamelRestSpringbootApplication using Java 11.0.5 on pc-PC with PID 15796 (D:Spring Bootcamel-rest-springboottargetclasses started by pc in D:Spring Bootcamel-rest-springboot) 2022-01-24 20:01:40.357 INFO 15796 --- [ main] c.d.c.CamelRestSpringbootApplication : No active profile set, falling back to default profiles: default 2022-01-24 20:01:43.583 INFO 15796 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-01-24 20:01:43.604 INFO 15796 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-01-24 20:01:43.604 INFO 15796 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.56] 2022-01-24 20:01:43.820 INFO 15796 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-01-24 20:01:43.821 INFO 15796 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3235 ms 2022-01-24 20:01:45.228 INFO 15796 --- [ main] o.a.c.c.s.CamelHttpTransportServlet : Initialized CamelHttpTransportServlet[name=CamelServlet, contextPath=] 2022-01-24 20:01:45.233 INFO 15796 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-01-24 20:01:45.592 INFO 15796 --- [ main] o.a.c.impl.engine.AbstractCamelContext : Message DataType is enabled on CamelContext: camel-1 2022-01-24 20:01:45.607 INFO 15796 --- [ main] o.a.c.impl.engine.AbstractCamelContext : Routes startup (total:1 started:1) 2022-01-24 20:01:45.607 INFO 15796 --- [ main] o.a.c.impl.engine.AbstractCamelContext : Started route1 (rest://get:javadsl/weather/%7Bcity%7D) 2022-01-24 20:01:45.607 INFO 15796 --- [ main] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 3.14.0 (camel-1) started in 370ms (build:83ms init:269ms start:18ms) 2022-01-24 20:01:45.617 INFO 15796 --- [ main] c.d.c.CamelRestSpringbootApplication : Started CamelRestSpringbootApplication in 6.569 seconds (JVM running for 8.087)
But when I try to call the endpoint http://localhost:8080/services/javadsl/weather/london
It looks like this endpoint doesn’t exist, the rest isn’t created. I used debugger and the method getWeatherData() isn’t called. And I think this log is not ok: Started route1 (rest://get:javadsl/weather/%7Bcity%7D), it should be something like that: route1 started and consuming from servlet:/javadsl/weather/%7Bcity%7D And the tutorial is from here: https://www.youtube.com/watch?v=spDjbC8mZf0&t=433s Thank you in advance!
Advertisement
Answer
You can start by creating example project using official camel-archetype-spring-boot maven archetype. You can generate project based on the archetype using your IDE or from command-line using following maven command.
mvn archetype:generate -DarchetypeArtifactId="camel-archetype-spring-boot" -DarchetypeGroupId="org.apache.camel.archetypes" -DarchetypeVersion="3.14.0"
Now in the maven project file pom.xml
add following block to the dependencies
<dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-jetty-starter</artifactId> </dependency>
Note that version doesn’t need to be specified as it is provided by camel-spring-boot-dependencies
BOM (bill of materials) in dependencyManagement section.
After that you can create new file ConfigureCamelContext.java where we can configure our CamelContext and provide it with RestConfiguration. We can do this by implementing CamelContextConfiguration and @Component
annotation.
The annotation tells spring-framework that it should create instance of the class and inject it to objects that request it based on its class-type or interface. Camel is configured to automatically ask spring-framework for these RestConfiguration instances which it will proceed to use configure CamelContext.
package com.example; import org.apache.camel.CamelContext; import org.apache.camel.spi.RestConfiguration; import org.apache.camel.spring.boot.CamelContextConfiguration; import org.springframework.stereotype.Component; @Component public class ConfigureCamelContext implements CamelContextConfiguration { @Override public void beforeApplicationStart(CamelContext camelContext) { RestConfiguration restConfiguration = new RestConfiguration(); restConfiguration.setApiComponent("jetty"); restConfiguration.setApiHost("localhost"); restConfiguration.setPort(8081); camelContext.setRestConfiguration(restConfiguration); } @Override public void afterApplicationStart(CamelContext camelContext) { } }
This should work with RestDSL and rest-component.
Edit MySpringBootRouter.java to something like this:
package com.example; import org.apache.camel.Exchange; import org.apache.camel.builder.RouteBuilder; import org.springframework.stereotype.Component; @Component public class MySpringBootRouter extends RouteBuilder { static final String CONTET_TYPE_TEXT = "text/plain"; @Override public void configure() { rest() .get("/hello/") .route() .setHeader(Exchange.CONTENT_TYPE, constant(CONTET_TYPE_TEXT)) .setBody().constant("Hello world") .end() .endRest() .get("/hello/{name}") .route() .setHeader(Exchange.CONTENT_TYPE, constant(CONTET_TYPE_TEXT)) .setBody().simple("Hello ${headers.name}") .end() .endRest(); from("rest:get:test?produces=plain/text") .setBody().constant("Hello from JavaDSL"); } }
Comment out the class under src/test/java/<grouId>/
as the example test provided by the archetype is not applicable for for MySpringBootRouter and will interrupt build.
To run the project you can use command
mvn spring-boot:run
Now you should be able to open up localhost:8081/hello
, localhost:8081/hello/<Name>
or localhost:8081/test
get response in plain text.