Server

Using FreeMarker Template Language (FTL)

Updated: December 4, 2024

JAX-RS Resources

Sample2.java

import javax.ws.rs.*; import javax.ws.rs.core.*; import org.nuxeo.ecm.webengine.model.impl.*; import org.nuxeo.ecm.webengine.model.*; /** * Templates sample. * * This demonstrates how to use template files to build client responses. * JAX-RS provides a flexible mechanism to send responses based on the mime type that the client expects. * To send a response to the client you simply return the Object you want as the response. * JAX-RS engines will usually know how to render common Java objects like String, InputStream, File etc. * If you need to output specific objects you need to register a custom MessageBodyWriter class. * In JAX-RS you are not able to modify the HttpServletResponse object directly from a resource method. (add headers, cookies etc) * Anything you may want to output must be returned from the resource method back to JAX-RS engine, and the engine will output it for you. * This is a very good thing, even if for some people this approach may seem strange. * You may ask yourself, ok cool, The response rendering is pretty well separated from the resource logic. * But how can I modify response headers? * In that case you must return a javax.ws.rs.Response that may be used to customize your response headers. * <p> * WebEngine is adding a new type of response objects: templates. * Templates are freemarker based templates that can be used to render your objects depending on the request context. * WebEngine is adding some cool extensions to freemarker templates that let you build your web site in a modular fashion. * These extensions are called blocks. Blocks are dynamic template parts that can be extended or replaced using derived blocks. * Using blocks, you can write a base template that may define the site layout (using blocks containing empty or generic content) and then * write final <i>skins</i> for your layout by extending the base template and redefining blocks you are interested in. * See the <i>skin</i> directory for template examples. * <p> * Templates are stored in files under the <i>skin</i> directory. Templates are always resolved relative to the <i>skin</i> directory, * even if you are using absolute paths. * The following variables are accessible from a template when rendered at rendering time: * <ul> * <li> <code>Context</code> - the WebContext instance * <li> <code>Engine</code> - the WebEngine instance * <li> <code>This</code> - the target Web Object. * <li> <code>Root</code> - the root WebObject. * <li> <code>Document</code> - the target Document if any otherwise null. * <li> <code>Session</code> - the Repository Session. (aka Core Session) * <li> <code>basePath</code> - the request base path (context path + servlet path) * </ul> * To render a template as a response you need to instantiate it and then return it from the resource method. * The template will be processed by the corresponding MessageBodyWriter and rendered on the client stream. * * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ @WebObject(type="sample2") @Path("/sample2") @Produces({"text/html"}) public class Sample2 extends ModuleRoot { @GET public Object doGet() { return "Sample2: Hello World!"; } /** * Return the template index.ftl from 'skin' directory */ @GET @Path("index1") public Object getIndex1() { return getTemplate("index1.ftl"); } /** * Inject the variable 'name' in the template context and then return the template. */ @GET @Path("index1/{name}") public Object getIndex1(@PathParam("name") String name) { return getTemplate("index1.ftl").arg("name", name); } /** * Render the index2 template */ @GET @Path("index2") public Object getIndex2() { return getTemplate("index2.ftl"); } /** * Example of using redirect. * The redirect method inherited from DefaultModule is returning a Response object that is doing a redirect */ @GET @Path("redirect/{whereToRedirect}") public Response doRedirect(@PathParam("whereToRedirect") String path) { return redirect(ctx.getModulePath() + "/"+ path); } /** * Example of using a Response object. * This method is sending a 403 HTTP error. */ @GET @Path("error/{errorCode}") public Response sendError(@PathParam("errorCode") String errorCode) { try { int statusCode = Integer.parseInt(errorCode); Response.Status status = Response.Status.fromStatusCode(statusCode); if (status != null) { return Response.status(status).build(); } } catch (Exception e) { } return Response.status(500).entity("Invalid error code: " + errorCode).build(); } }

Object Views

skin/base.ftl

<!-- Base template that defines the site layout --> <html> <head> <title><@block name="title"/></title> </head> <body> <table width="100%" border="1"> <tr> <td> <@block name="header">Header</@block> </td> </tr> <tr> <td> <@block name="content">Content</@block> </td> </tr> <tr> <td> <@block name="footer">Footer</@block> </td> </tr> </table> </body> </html>

skin/index1.ftl

<@extends src="base.ftl"> <@block name="title">Index 2</@block> <@block name="header"> <#if name> Hello ${name}! <#else> Hello World! </#if> </@block> <@block name="content"> This is the <i>index1</i> skin. </@block> <@block name="footer"> The footer here ... </@block> </@extends>

skin/index2.ftl

<@extends src="base.ftl"> <@block name="title">Index 2</@block> <@block name="content"> This is the <i>index2</i> skin. </@block> </@extends>