| <!doctype html> |
| <!-- Generated by FreeMarker/Docgen from DocBook --> |
| <html lang="en" class="page-type-section"> |
| <head prefix="og: http://ogp.me/ns#"> |
| <meta charset="utf-8"> |
| <title>Template loading - Apache FreeMarker Manual</title> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <meta name="format-detection" content="telephone=no"> |
| <meta property="og:site_name" content="Apache FreeMarker Manual"> |
| <meta property="og:title" content="Template loading"> |
| <meta property="og:locale" content="en_US"> |
| <meta property="og:url" content="https://freemarker.apache.org/docs/pgui_config_templateloading.html"> |
| <link rel="canonical" href="https://freemarker.apache.org/docs/pgui_config_templateloading.html"> |
| <link rel="icon" href="favicon.png" type="image/png"> |
| <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:500,700,400,300|Droid+Sans+Mono"> |
| <link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css?1707770044859"> |
| <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/cookie-bar/cookiebar-latest.min.js"></script> |
| </head> |
| <body itemscope itemtype="https://schema.org/Code"> |
| <meta itemprop="url" content="https://freemarker.apache.org/docs/"> |
| <meta itemprop="name" content="Apache FreeMarker Manual"> |
| |
| <!--[if lte IE 9]> |
| <div class="oldBrowserWarning" style="display: block"> |
| Unsupported web browser - Use a modern browser to view this website! |
| </div> |
| <![endif]--> <div class="oldBrowserWarning"> |
| Unsupported web browser - Use a modern browser to view this website! |
| </div> |
| <div class="header-top-bg"><div class="site-width header-top"><div id="hamburger-menu" role="button"></div> <div class="logo"> |
| <a href="https://freemarker.apache.org" role="banner"><img itemprop="image" src="logo.png" alt="FreeMarker"></a> </div> |
| <ul class="tabs"><li><a href="https://freemarker.apache.org/">Home</a></li><li class="current"><a href="index.html">Manual</a></li><li><a class="external" href="api/index.html">Java API</a></li></ul><ul class="secondary-tabs"><li><a class="tab icon-heart" href="https://freemarker.apache.org/contribute.html" title="Contribute"><span>Contribute</span></a></li><li><a class="tab icon-bug" href="https://issues.apache.org/jira/projects/FREEMARKER" title="Report a Bug"><span>Report a Bug</span></a></li><li><a class="tab icon-download" href="https://freemarker.apache.org/freemarkerdownload.html" title="Download"><span>Download</span></a></li></ul></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="index.html" class="navigation-header">Manual</a><div class="navigation-header"></div><form method="get" class="search-form" action="search-results.html"><fieldset><legend class="sr-only">Search form</legend><label for="search-field" class="sr-only">Search query</label><input id="search-field" name="q" type="search" class="search-input" placeholder="Search" spellcheck="false" autocorrect="off" autocomplete="off"><button type="submit" class="search-btn"><span class="sr-only">Search</span></button></fieldset></form></div><div class="site-width breadcrumb-row"> <div class="breadcrumbs"> |
| <ul class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"><li class="step-0" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="index.html"><span itemprop="name">Apache FreeMarker Manual</span></a></li><li class="step-1" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui.html"><span itemprop="name">Programmer's Guide</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_config.html"><span itemprop="name">The Configuration</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_config_templateloading.html"><span itemprop="name">Template loading</span></a></li></ul> </div> |
| <div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul><li><a href="alphaidx.html">Alpha. index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions</a></li><li><a href="ref_builtins_alphaidx.html">?builtins</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_specvar.html">.spec_vars</a></li><li><a href="app_faq.html">FAQ</a></li></ul></div></div></div> <div class="main-content site-width"> |
| <div class="content-wrapper"> |
| <div id="table-of-contents-wrapper" class="col-left"> |
| <script>var breadcrumb = ["Apache FreeMarker Manual","Programmer\'s Guide","The Configuration","Template loading"];</script> |
| <script src="toc.js?1707770044859"></script> |
| <script src="docgen-resources/main.min.js?1707770044859"></script> |
| </div> |
| <div class="col-right"><div class="page-content"><div class="page-title"><div class="pagers top"><a class="paging-arrow previous" href="pgui_config_settings.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_config_errorhandling.html"><span>Next</span></a></div><div class="title-wrapper"> |
| <h1 class="content-header header-section1" id="pgui_config_templateloading" itemprop="headline">Template loading</h1> |
| </div></div><div class="page-menu"> |
| <div class="page-menu-title">Page Contents</div> |
| <ul><li><a class="page-menu-link" href="#autoid_38" data-menu-target="autoid_38">Template loaders</a><ul><li><a class="page-menu-link" href="#autoid_39" data-menu-target="autoid_39">Built-in template loaders</a></li><li><a class="page-menu-link" href="#autoid_40" data-menu-target="autoid_40">Loading templates from multiple locations</a></li><li><a class="page-menu-link" href="#autoid_41" data-menu-target="autoid_41">Loading templates from other sources</a></li><li><a class="page-menu-link" href="#autoid_42" data-menu-target="autoid_42">The template name (template path)</a></li></ul></li><li><a class="page-menu-link" href="#pgui_config_templateloading_caching" data-menu-target="pgui_config_templateloading_caching">Template caching</a></li></ul> </div> |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_38">Template loaders</h2> |
| |
| |
| |
| |
| <p>Template loaders are objects that load raw textual data based |
| on abstract template paths like <code class="inline-code">"index.ftl"</code> or |
| <code class="inline-code">"products/catalog.ftl"</code>. It's up to the concrete |
| template loader if from where and how the template |
| "files" are loaded. They could be real files inside a |
| specified directory, or values in a data base table, or |
| <code class="inline-code">String</code>-s in a Java Map, etc. When you call |
| <code class="inline-code">cfg.getTemplate</code> (where <code class="inline-code">cfg</code> is |
| a <code class="inline-code">Configuration</code> instance), FreeMarker asks the |
| template loader (<code class="inline-code">cfg.getTemplateLoader</code>) to return |
| the text for the given template path, and then FreeMarker parses |
| that text as template. It doesn't care or even know if the template |
| is a real file or not, and where it is physically; those details are |
| only known by the template loader.</p> |
| |
| |
| |
| |
| |
| |
| <h3 class="content-header header-section3" id="autoid_39">Built-in template loaders</h3> |
| |
| |
| <p>You can set up the three most common template loading |
| mechanism in the <code class="inline-code">Configuration</code> using the |
| following <em>convenience</em> methods:</p> |
| |
| <ul> |
| <li> |
| <p><code class="inline-code">void setDirectoryForTemplateLoading(File |
| dir)</code>: Sets a directory on the file system from which |
| to load templates. Template names (template paths) will be |
| interpreted relatively to this physical directory. It won't |
| let you load files outside this directory.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">void setClassForTemplateLoading(Class cl, |
| String basePackagePath)</code> and <code class="inline-code">void |
| setClassLoaderForTemplateLoading(ClassLoader classLoader, |
| String basePackagePath)</code>: These are for when you want |
| to load templates via the same mechanism with which Java loads |
| classes (from the class-path, as they used to say vaguely). |
| This is very likely be the preferred means of loading |
| templates for production code, as it allows you to keep |
| everything inside the deployment <code class="inline-code">jar</code> files. |
| The first parameter decides which Java |
| <code class="inline-code">ClassLoader</code> will be used. The second |
| parameter specifies the package that contains the templates, |
| in <code class="inline-code">/</code>-separated format. Note that if you |
| don't start it with <code class="inline-code">/</code>, it will be |
| interpreted relatively to the package of the |
| <code class="inline-code">Class</code> parameter.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">void setServletContextForTemplateLoading(Object |
| servletContext, String path)</code>: Takes the context of |
| your Servlet-based web application, and a base path, which is |
| interpreted relative to the web application root directory |
| (that's the parent of the <code class="inline-code">WEB-INF</code> |
| directory). Note that we refer to "directory" here although |
| this loading method works even for unpacked |
| <code class="inline-code">.war</code> files, since it uses |
| <code class="inline-code">ServletContext.getResource()</code> to access the |
| templates. If you omit the second parameter (or use |
| <code class="inline-code">""</code>), you can simply store the static files |
| (<code class="inline-code">.html</code>, <code class="inline-code">.jpg</code>, etc.) |
| mixed with the <code class="inline-code">.ftl</code> files. Of course, you |
| must set up a Servlet for the <code class="inline-code">*.ftl</code>, |
| <code class="inline-code">*.ftlh</code>, <code class="inline-code">*.ftlx</code> |
| uri-patterns in <code class="inline-code">WEB-INF/web.xml</code> for this, |
| otherwise the client will get the raw templates as is! To |
| avoid a such accident, many prefers storing the templates |
| somewhere inside the <code class="inline-code">WEB-INF</code> directory, |
| which is never visitable directly. This mechanism will very |
| likely be the preferred means of loading templates for servlet |
| applications, since the templates can be updated without |
| restarting the web application, while this often doesn't work |
| with the class-loader mechanism.</p> |
| </li> |
| </ul> |
| |
| <p>If you want to use a custom |
| <code class="inline-code">TemplateLoader</code> implementation, or need to set |
| up some extra settings of a built-in template loader, you need to |
| instantiate the <code class="inline-code">TemplateLoader</code> object yourself, |
| and then call |
| <code class="inline-code">Configuration.setTemplateLoader(TemplateLoader)</code>:</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">WebappTemplateLoader templateLoader = new WebappTemplateLoader(servletContext, "WEB-INF/templates"); |
| templateLoader.setURLConnectionUsesCaches(false); |
| templateLoader.setAttemptFileAccess(false); |
| cfg.setTemplateLoader(templateLoader);</pre> </div> |
| |
| |
| |
| |
| |
| |
| |
| |
| <h3 class="content-header header-section3" id="autoid_40">Loading templates from multiple locations</h3> |
| |
| |
| <p>If you need to load templates from multiple locations, you |
| have to instantiate the template loader objects for every |
| location, wrap them into a <code class="inline-code">MultiTemplateLoader</code>, |
| and finally pass that loader to the |
| <code class="inline-code">setTemplateLoader(TemplateLoader loader)</code> method |
| of <code class="inline-code">Configuration</code>. Here's an example for loading |
| templates from two distinct directories and with the |
| class-loader:</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">import freemarker.cache.*; // template loaders live in this package |
| |
| <em>...</em> |
| |
| FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates")); |
| FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates")); |
| ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), "/com/example/templates"); |
| |
| MultiTemplateLoader mtl = new MultiTemplateLoader(new TemplateLoader[] { ftl1, ftl2, ctl }); |
| |
| cfg.setTemplateLoader(mtl);</pre> </div> |
| |
| |
| <p>Now FreeMarker will try to load templates from |
| <code class="inline-code">/tmp/templates</code> directory, and if it does not |
| find the requested template there, it will try to load that from |
| <code class="inline-code">/usr/data/templates</code>, and if it still does not |
| find the requested template, then it tries to load it from the |
| <code class="inline-code">com.example.templates</code> Java package.</p> |
| |
| |
| |
| |
| |
| |
| |
| <h3 class="content-header header-section3" id="autoid_41">Loading templates from other sources</h3> |
| |
| |
| <p>If none of the built-in class loaders fit your needs, you |
| can write your own class that implements the |
| <code class="inline-code">freemarker.cache.TemplateLoader</code> interface and |
| pass it to the <code class="inline-code">setTemplateLoader(TemplateLoader |
| loader)</code> method of <code class="inline-code">Configuration</code>. |
| Please read the API JavaDoc for more information.</p> |
| |
| <p>If your template source accesses the templates through an |
| URL, you needn't implement a <code class="inline-code">TemplateLoader</code> |
| from scratch; you can choose to subclass |
| <code class="inline-code">freemarker.cache.URLTemplateLoader</code> instead and |
| just implement the <code class="inline-code">URL getURL(String |
| templateName)</code> method.</p> |
| |
| |
| |
| |
| |
| |
| |
| <h3 class="content-header header-section3" id="autoid_42">The template name (template path)</h3> |
| |
| |
| |
| |
| |
| |
| |
| |
| <p>It is up to the template loader how it interprets template |
| names (also known as template paths). But to work together with |
| other components there are restrictions regarding the format of |
| the path. In general, it is strongly recommended that template |
| loaders use URL-style paths. The path must not use |
| <code class="inline-code">/</code> (path step separator) character, nor the |
| <code class="inline-code">.</code> (same-directory) and <code class="inline-code">..</code> |
| (parent directory) path steps with other meaning than they have in |
| URL paths (or in UN*X paths). The <code class="inline-code">*</code> (asterisk) |
| step is also reserved, and used for "template |
| acquisition" feature of FreeMarker.</p> |
| |
| <p><code class="inline-code">://</code> (or with |
| <code class="inline-code">template_name_format</code> setting set to |
| <code class="inline-code">DEFAULT_2_4_0</code>, the <code class="inline-code">:</code> (colon) |
| character) is reserved for specifying a scheme part, similarly as |
| it works with URI-s. For example |
| <code class="inline-code">someModule://foo/bar.ftl</code> uses the |
| <code class="inline-code">someModule</code>, or assuming the |
| <code class="inline-code">DEFAULT_2_4_0</code> format, |
| <code class="inline-code">classpath:foo/bar.ftl</code> uses the |
| <code class="inline-code">classpath</code> scheme. Interpreting the scheme part |
| is completely up to the <code class="inline-code">TemplateLoader</code>. (The |
| FreeMarker core is only aware of the idea of schemes because |
| otherwise it couldn't resolve relative template names |
| properly.)</p> |
| |
| <p>FreeMarker always normalizes the paths before passing them |
| to the <code class="inline-code">TemplateLoader</code>, so the paths don't |
| contain <code class="inline-code">/../</code> or such, and are relative to the |
| imaginary template root directory (that is, they don't start with |
| <code class="inline-code">/</code>). They don't contain the <code class="inline-code">*</code> |
| step either, as template acquisition happens in an earlier stage. |
| Furthermore, with <code class="inline-code">template_name_format</code> setting |
| set to <code class="inline-code">DEFAULT_2_4_0</code>, multiple consecutive |
| <code class="inline-code">/</code>-s will be normalized to a single |
| <code class="inline-code">/</code> (unless they are part of the |
| <code class="inline-code">://</code> scheme separator).</p> |
| |
| <p>Note that FreeMarker template path should always uses slash |
| (not backslash) regardless of the host OS.</p> |
| |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="pgui_config_templateloading_caching">Template caching</h2> |
| |
| |
| |
| |
| |
| |
| <p>FreeMarker caches templates (assuming you use the |
| <code class="inline-code">Configuration</code> methods to create |
| <code class="inline-code">Template</code> objects). This means that when you call |
| <code class="inline-code">getTemplate</code>, FreeMarker not only returns the |
| resulting <code class="inline-code">Template</code> object, but stores it in a |
| cache, so when next time you call <code class="inline-code">getTemplate</code> |
| with the same (or equivalent) path, it just returns the cached |
| <code class="inline-code">Template</code> instance, and will not load and parse |
| the template file again.</p> |
| |
| <p>If you change the template file, then FreeMarker will re-load |
| and re-parse the template automatically when you get the template |
| next time. However, since always checking for changes can be burden |
| for a system that processes lot of templates, there is a |
| <code class="inline-code">Configuration</code> level setting called "update |
| delay" (defaults is 5 seconds). Until this much time has |
| elapsed since the last checking for a newer version, FreeMarker will |
| not check again if the template was changed. If you want to see the |
| changes without delay, set this setting to 0. Note that some |
| template loaders won't see that a template was changed because of |
| the underlying storage mechanism doesn't support that; for example, |
| class-loader based template loaders may have this problem.</p> |
| |
| <p>A template will be removed from the cache if you call |
| <code class="inline-code">getTemplate</code> and FreeMarker realizes that the |
| template file has been removed meanwhile. Also, if the JVM thinks |
| that it begins to run out of memory, by default it can arbitrarily |
| drop templates from the cache. Furthermore, you can empty the cache |
| manually with the <code class="inline-code">clearTemplateCache</code> method of |
| <code class="inline-code">Configuration</code>. You can also drop selected |
| template from the cache with |
| <code class="inline-code">removeTemplateFromCache</code>; this can be also |
| utilized to force re-loading a template regardless of the |
| "update delay" setting.</p> |
| |
| <p>The actual strategy of when a cached template should be thrown |
| away is pluggable with the <code class="inline-code">cache_storage</code> setting, |
| by which you can plug any <code class="inline-code">CacheStorage</code> |
| implementation. For most users |
| <code class="inline-code">freemarker.cache.MruCacheStorage</code> will be |
| sufficient. This cache storage implements a two-level Most Recently |
| Used cache. In the first level, items are strongly referenced up to |
| the specified maximum (strongly referenced items can't be dropped by |
| the JVM, as opposed to softly referenced items). When the maximum is |
| exceeded, the least recently used item is moved into the second |
| level cache, where they are softly referenced, up to another |
| specified maximum. The size of the strong and soft parts can be |
| specified with the constructor. For example, set the size of the |
| strong part to 20, and the size of soft part to 250:</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250))</pre> </div> |
| |
| |
| <p>Or, since <code class="inline-code">MruCacheStorage</code> is the default |
| cache storage implementation:</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">cfg.setSetting(Configuration.CACHE_STORAGE_KEY, "strong:20, soft:250");</pre> </div> |
| |
| |
| <p>When you create a new <code class="inline-code">Configuration</code> object, |
| initially it uses an <code class="inline-code">MruCacheStorage</code> where |
| <code class="inline-code">strongSizeLimit</code> is 0, and |
| <code class="inline-code">softSizeLimit</code> is |
| <code class="inline-code">Integer.MAX_VALUE</code> (that is, in practice, |
| infinite). Depending on how smart the JVM is, using non-0 |
| <code class="inline-code">strongSizeLimit</code> is maybe a safer option, as with |
| only softly referenced items the JVM could even throw the most |
| frequently used templates when there's a resource shortage, which |
| then have to be re-loaded and re-parsed, burdening the system even |
| more.</p> |
| <div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="pgui_config_settings.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_config_errorhandling.html"><span>Next</span></a></div></div></div></div> </div> |
| </div> |
| <div class="site-footer"><div class="site-width"><div class="footer-top"><div class="col-left sitemap"><div class="column"><h3 class="column-header">Overview</h3><ul><li><a href="https://freemarker.apache.org/">What is FreeMarker?</a></li><li><a href="https://freemarker.apache.org/freemarkerdownload.html">Download</a></li><li><a href="app_versions.html">Version history</a></li><li><a href="app_faq.html">FAQ</a></li><li><a itemprop="license" href="app_license.html">License</a></li><li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy policy</a></li></ul></div><div class="column"><h3 class="column-header">Often used / Reference</h3><ul><li><a href="https://try.freemarker.apache.org/">Try template online</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions cheatsheet</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_builtins_alphaidx.html">?built_ins</a></li><li><a href="ref_specvar.html">.special_vars</a></li><li><a href="api/freemarker/core/Configurable.html#setSetting-java.lang.String-java.lang.String-">Configuration settings</a></li></ul></div><div class="column"><h3 class="column-header">Community</h3><ul><li><a href="https://github.com/apache/freemarker">Github project page</a></li><li><a href="https://issues.apache.org/jira/projects/FREEMARKER">Report a bug</a></li><li><a href="https://freemarker.apache.org/report-security-vulnerabilities.html">Report security vulnerability</a></li><li><a href="https://stackoverflow.com/questions/ask?tags=freemarker">Get help on StackOverflow</a></li><li><a href="https://twitter.com/freemarker">Announcements on Twitter</a></li><li><a href="https://freemarker.apache.org/mailing-lists.html">Discuss on mailing lists</a></li></ul></div></div><div class="col-right"><ul class="social-icons"><li><a class="github" href="https://github.com/apache/freemarker">Github</a></li><li><a class="twitter" href="https://twitter.com/freemarker">Twitter</a></li><li><a class="stack-overflow" href="https://stackoverflow.com/questions/ask?tags=freemarker">Stack Overflow</a></li></ul><a class="xxe" href="http://www.xmlmind.com/xmleditor/" rel="nofollow" title="Edited with XMLMind XML Editor"><span>Edited with XMLMind XML Editor</span></a></div></div><div class="footer-bottom"> <p class="last-generated"> |
| Last generated: |
| <time itemprop="dateModified" datetime="2024-02-12T20:34:04Z" title="Monday, February 12, 2024 at 8:34:04 PM Greenwich Mean Time">2024-02-12 20:34:04 GMT</time>, for Freemarker 2.3.32 </p> |
| <p class="copyright"> |
| © <span itemprop="copyrightYear">1999</span>–2024 |
| <a itemtype="http://schema.org/Organization" itemprop="copyrightHolder" href="https://apache.org/">The Apache Software Foundation</a>. Apache FreeMarker, FreeMarker, Apache Incubator, Apache, the Apache FreeMarker logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners. </p> |
| </div></div></div></body> |
| </html> |