| = Thymeleaf Component | |
| :doctitle: Thymeleaf | |
| :shortname: thymeleaf | |
| :artifactid: camel-thymeleaf | |
| :description: Transform messages using a Thymeleaf template. | |
| :since: 4.1 | |
| :supportlevel: Stable | |
| :tabs-sync-option: | |
| :component-header: Only producer is supported | |
| *Since Camel {since}* | |
| *{component-header}* | |
| The Thymeleaf component allows you to process a message using a | |
| https://www.thymeleaf.org/[Thymeleaf] template. This can be very powerful | |
| when using Templating to generate responses for requests. | |
| Maven users will need to add the following dependency to their `pom.xml` | |
| for this component: | |
| [source,xml] | |
| ---- | |
| <dependency> | |
| <groupId>org.apache.camel</groupId> | |
| <artifactId>camel-thymeleaf</artifactId> | |
| <version>x.x.x</version> | |
| <!-- use the same version as your Camel core version --> | |
| </dependency> | |
| ---- | |
| == URI format | |
| ---- | |
| thymeleaf:templateName[?options] | |
| ---- | |
| Where *templateName* is the classpath-local URI of the template to | |
| invoke; or the complete URL of the remote template (e.g.: | |
| `\file://folder/myfile.html`). | |
| // component options: START | |
| include::partial$component-configure-options.adoc[] | |
| include::partial$component-endpoint-options.adoc[] | |
| include::partial$component-endpoint-headers.adoc[] | |
| // component options: END | |
| Headers set during the Thymeleaf evaluation are returned to the message | |
| and added as headers, thus making it possible to return values from | |
| Thymeleaf to the Message. | |
| For example, to set the header value of `fruit` in the Thymeleaf template | |
| `fruit-template.html`: | |
| ---- | |
| $in.setHeader("fruit", "Apple") | |
| ---- | |
| The `fruit` header is now accessible from the `message.out.headers`. | |
| == Usage | |
| === Thymeleaf Context | |
| Camel will provide exchange information in the Thymeleaf context (just a | |
| `Map`). | |
| The `Exchange` is transferred as: | |
| [width="100%",cols="10%,90%",options="header",] | |
| |======================================================================= | |
| |key |value | |
| |`exchange` |The `Exchange` itself. | |
| |`exchange.properties` |The `Exchange` properties. | |
| |`headers` |The headers of the In message. | |
| |`camelContext` |The Camel Context instance. | |
| |`request` |The In message. | |
| |`in` |The In message. | |
| |`body` |The In message body. | |
| |`out` |The Out message (only for InOut message exchange pattern). | |
| |`response` |The Out message (only for InOut message exchange pattern). | |
| |======================================================================= | |
| You can set up a custom Thymeleaf Context yourself by | |
| setting property `allowTemplateFromHeader=true` and setting the message header `CamelThymeleafContext` like this | |
| ._Java-only: programmatic Thymeleaf context setup via Exchange API_ | |
| [source,java] | |
| ---- | |
| EngineContext engineContext = new EngineContext(variableMap); | |
| exchange.getIn().setHeader("CamelThymeleafContext", engineContext); | |
| ---- | |
| === Hot reloading | |
| The Thymeleaf template resource is, by default, hot reloadable for both | |
| file and classpath resources (expanded jar). If you set | |
| `cacheable=true`, the template is only loaded once, and thus | |
| hot reloading is not possible. This scenario can be used in production | |
| when the resource never changes. | |
| === Dynamic templates | |
| Camel provides two headers by which you can define a different resource | |
| location for a template or the template content itself. If any of these | |
| headers is set, then Camel uses this over the endpoint configured | |
| resource. This allows you to provide a dynamic template at runtime. | |
| [width="100%",cols="10%,10%,80%",options="header",] | |
| |======================================================================= | |
| |Header |Type |Description | |
| |`CamelThymeleafResourceUri` |`String` |A URI for the template resource to use instead of the | |
| endpoint configured. | |
| |`CamelThymeleafTemplate` |`String` |The template to use instead of the endpoint configured. | |
| |======================================================================= | |
| == Examples | |
| For a simple use case, you could use something like: | |
| [tabs] | |
| ==== | |
| Java:: | |
| + | |
| [source,java] | |
| ---- | |
| from("activemq:My.Queue") | |
| .to("thymeleaf:com/acme/MyResponse.html"); | |
| ---- | |
| XML:: | |
| + | |
| [source,xml] | |
| ---- | |
| <route> | |
| <from uri="activemq:My.Queue"/> | |
| <to uri="thymeleaf:com/acme/MyResponse.html"/> | |
| </route> | |
| ---- | |
| YAML:: | |
| + | |
| [source,yaml] | |
| ---- | |
| - route: | |
| from: | |
| uri: activemq:My.Queue | |
| steps: | |
| - to: | |
| uri: thymeleaf:com/acme/MyResponse.html | |
| ---- | |
| ==== | |
| To use a Thymeleaf template to formulate a response to a message for | |
| InOut message exchanges (where there is a `JMSReplyTo` header). | |
| If you want to use InOnly and consume the message and send it to another | |
| destination, you could use the following route: | |
| [tabs] | |
| ==== | |
| Java:: | |
| + | |
| [source,java] | |
| ---- | |
| from("activemq:My.Queue") | |
| .to("thymeleaf:com/acme/MyResponse.html") | |
| .to("activemq:Another.Queue"); | |
| ---- | |
| XML:: | |
| + | |
| [source,xml] | |
| ---- | |
| <route> | |
| <from uri="activemq:My.Queue"/> | |
| <to uri="thymeleaf:com/acme/MyResponse.html"/> | |
| <to uri="activemq:Another.Queue"/> | |
| </route> | |
| ---- | |
| YAML:: | |
| + | |
| [source,yaml] | |
| ---- | |
| - route: | |
| from: | |
| uri: activemq:My.Queue | |
| steps: | |
| - to: | |
| uri: thymeleaf:com/acme/MyResponse.html | |
| - to: | |
| uri: activemq:Another.Queue | |
| ---- | |
| ==== | |
| And to use the content cache, e.g., for use in production, where the | |
| `.html` template never changes: | |
| [tabs] | |
| ==== | |
| Java:: | |
| + | |
| [source,java] | |
| ---- | |
| from("activemq:My.Queue") | |
| .to("thymeleaf:com/acme/MyResponse.html?cacheable=true") | |
| .to("activemq:Another.Queue"); | |
| ---- | |
| XML:: | |
| + | |
| [source,xml] | |
| ---- | |
| <route> | |
| <from uri="activemq:My.Queue"/> | |
| <to uri="thymeleaf:com/acme/MyResponse.html?cacheable=true"/> | |
| <to uri="activemq:Another.Queue"/> | |
| </route> | |
| ---- | |
| YAML:: | |
| + | |
| [source,yaml] | |
| ---- | |
| - route: | |
| from: | |
| uri: activemq:My.Queue | |
| steps: | |
| - to: | |
| uri: thymeleaf:com/acme/MyResponse.html | |
| parameters: | |
| cacheable: true | |
| - to: | |
| uri: activemq:Another.Queue | |
| ---- | |
| ==== | |
| And a file-based resource: | |
| [tabs] | |
| ==== | |
| Java:: | |
| + | |
| [source,java] | |
| ---- | |
| from("activemq:My.Queue") | |
| .to("thymeleaf:file://myfolder/MyResponse.html?cacheable=true") | |
| .to("activemq:Another.Queue"); | |
| ---- | |
| XML:: | |
| + | |
| [source,xml] | |
| ---- | |
| <route> | |
| <from uri="activemq:My.Queue"/> | |
| <to uri="thymeleaf:file://myfolder/MyResponse.html?cacheable=true"/> | |
| <to uri="activemq:Another.Queue"/> | |
| </route> | |
| ---- | |
| YAML:: | |
| + | |
| [source,yaml] | |
| ---- | |
| - route: | |
| from: | |
| uri: activemq:My.Queue | |
| steps: | |
| - to: | |
| uri: thymeleaf:file://myfolder/MyResponse.html | |
| parameters: | |
| cacheable: true | |
| - to: | |
| uri: activemq:Another.Queue | |
| ---- | |
| ==== | |
| It's possible to specify what template the component | |
| should use dynamically via a header, so for example: | |
| [tabs] | |
| ==== | |
| Java:: | |
| + | |
| [source,java] | |
| ---- | |
| from("direct:in") | |
| .setHeader("CamelThymeleafResourceUri").constant("path/to/my/template.html") | |
| .to("thymeleaf:dummy?allowTemplateFromHeader=true"); | |
| ---- | |
| XML:: | |
| + | |
| [source,xml] | |
| ---- | |
| <route> | |
| <from uri="direct:in"/> | |
| <setHeader name="CamelThymeleafResourceUri"> | |
| <constant>path/to/my/template.html</constant> | |
| </setHeader> | |
| <to uri="thymeleaf:dummy?allowTemplateFromHeader=true"/> | |
| </route> | |
| ---- | |
| YAML:: | |
| + | |
| [source,yaml] | |
| ---- | |
| - route: | |
| from: | |
| uri: direct:in | |
| steps: | |
| - setHeader: | |
| name: CamelThymeleafResourceUri | |
| expression: | |
| constant: | |
| expression: path/to/my/template.html | |
| - to: | |
| uri: thymeleaf:dummy | |
| parameters: | |
| allowTemplateFromHeader: true | |
| ---- | |
| ==== | |
| It's possible to specify a template directly as a header. | |
| The component should use it dynamically via a header, so, for example: | |
| [tabs] | |
| ==== | |
| Java:: | |
| + | |
| [source,java] | |
| ---- | |
| from("direct:in") | |
| .setHeader("CamelThymeleafTemplate").constant("Hi this is a thymeleaf template that can do templating ${body}") | |
| .to("thymeleaf:dummy?allowTemplateFromHeader=true"); | |
| ---- | |
| XML:: | |
| + | |
| [source,xml] | |
| ---- | |
| <route> | |
| <from uri="direct:in"/> | |
| <setHeader name="CamelThymeleafTemplate"> | |
| <constant>Hi this is a thymeleaf template that can do templating ${body}</constant> | |
| </setHeader> | |
| <to uri="thymeleaf:dummy?allowTemplateFromHeader=true"/> | |
| </route> | |
| ---- | |
| YAML:: | |
| + | |
| [source,yaml] | |
| ---- | |
| - route: | |
| from: | |
| uri: direct:in | |
| steps: | |
| - setHeader: | |
| name: CamelThymeleafTemplate | |
| expression: | |
| constant: | |
| expression: "Hi this is a thymeleaf template that can do templating ${body}" | |
| - to: | |
| uri: thymeleaf:dummy | |
| parameters: | |
| allowTemplateFromHeader: true | |
| ---- | |
| ==== | |
| === The Email Example | |
| In this sample, we want to use Thymeleaf templating for an order | |
| confirmation email. The email template is laid out in Thymeleaf as: | |
| .letter.html | |
| [source,text] | |
| ---- | |
| Dear [(${headers.lastName})], [(${headers.firstName})] | |
| Thanks for the order of [(${headers.item})]. | |
| Regards Camel Riders Bookstore | |
| [(${body})] | |
| ---- | |
| And the java code (from a unit test): | |
| ._Java-only: unit test with Exchange creation and RouteBuilder_ | |
| [source,java] | |
| ---- | |
| private Exchange createLetter() { | |
| Exchange exchange = context.getEndpoint("direct:a").createExchange(); | |
| Message msg = exchange.getIn(); | |
| msg.setHeader("firstName", "Claus"); | |
| msg.setHeader("lastName", "Ibsen"); | |
| msg.setHeader("item", "Camel in Action"); | |
| msg.setBody("PS: Next beer is on me, James"); | |
| return exchange; | |
| } | |
| @Test | |
| public void testThymeleafLetter() throws Exception { | |
| MockEndpoint mock = getMockEndpoint("mock:result"); | |
| mock.expectedMessageCount(1); | |
| mock.message(0).body(String.class).contains("Thanks for the order of Camel in Action"); | |
| template.send("direct:a", createLetter()); | |
| mock.assertIsSatisfied(); | |
| } | |
| from("direct:a") | |
| .to("thymeleaf:org/apache/camel/component/thymeleaf/letter.txt") | |
| .to("mock:result"); | |
| ---- |