blob: 811d87f56673e8055e2db66ad1070e6af1f991c4 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="Date-Revision-yyyymmdd" content="20140918"/>
<meta http-equiv="Content-Language" content="en"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Freemarker Tags</title>
<link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,400italic,600italic,700italic" rel="stylesheet" type="text/css">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link href="/css/main.css" rel="stylesheet">
<link href="/css/custom.css" rel="stylesheet">
<link href="/css/syntax.css" rel="stylesheet">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="/js/community.js"></script>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//analytics.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '41']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
</head>
<body>
<a href="https://github.com/apache/struts" class="github-ribbon">
<img decoding="async" loading="lazy" style="position: absolute; right: 0; border: 0;" width="149" height="149" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_red_aa0000.png?resize=149%2C149" class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1">
</a>
<header>
<nav>
<div role="navigation" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" data-toggle="collapse" data-target="#struts-menu" class="navbar-toggle">
Menu
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/index.html" class="navbar-brand logo"><img src="/img/struts-logo.svg"></a>
</div>
<div id="struts-menu" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Home<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/index.html">Welcome</a></li>
<li><a href="/download.cgi">Download</a></li>
<li><a href="/releases.html">Releases</a></li>
<li><a href="/announce-2024.html">Announcements</a></li>
<li><a href="http://www.apache.org/licenses/">License</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html">Thanks!</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Support<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/mail.html">User Mailing List</a></li>
<li><a href="https://issues.apache.org/jira/browse/WW">Issue Tracker</a></li>
<li><a href="/security.html">Reporting Security Issues</a></li>
<li><a href="/commercial-support.html">Commercial Support</a></li>
<li class="divider"></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Migration+Guide">Version Notes</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Security+Bulletins">Security Bulletins</a></li>
<li class="divider"></li>
<li><a href="/maven/project-info.html">Maven Project Info</a></li>
<li><a href="/maven/struts2-core/dependencies.html">Struts Core Dependencies</a></li>
<li><a href="/maven/struts2-plugins/modules.html">Plugin Dependencies</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Documentation<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/birdseye.html">Birds Eye</a></li>
<li><a href="/primer.html">Key Technologies</a></li>
<li><a href="/kickstart.html">Kickstart FAQ</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Home">Wiki</a></li>
<li class="divider"></li>
<li><a href="/getting-started/">Getting Started</a></li>
<li><a href="/security/">Security Guide</a></li>
<li><a href="/core-developers/">Core Developers Guide</a></li>
<li><a href="/tag-developers/">Tag Developers Guide</a></li>
<li><a href="/maven-archetypes/">Maven Archetypes</a></li>
<li><a href="/plugins/">Plugins</a></li>
<li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li>
<li><a href="/tag-developers/tag-reference.html">Tag reference</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/FAQs">FAQs</a></li>
<li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Contributing<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/youatstruts.html">You at Struts</a></li>
<li><a href="/helping.html">How to Help FAQ</a></li>
<li><a href="/dev-mail.html">Development Lists</a></li>
<li class="divider"></li>
<li><a href="/submitting-patches.html">Submitting patches</a></li>
<li><a href="/builds.html">Source Code and Builds</a></li>
<li><a href="/coding-standards.html">Coding standards</a></li>
<li><a href="/contributors/">Contributors Guide</a></li>
<li class="divider"></li>
<li><a href="/release-guidelines.html">Release Guidelines</a></li>
<li><a href="/bylaws.html">PMC Charter</a></li>
<li><a href="/volunteers.html">Volunteers</a></li>
<li><a href="https://gitbox.apache.org/repos/asf?p=struts.git">Source Repository</a></li>
<li><a href="/updating-website.html">Updating the website</a></li>
</ul>
</li>
<li class="apache"><a href="http://www.apache.org/"><img src="/img/apache.png"></a></li>
</ul>
</div>
</div>
</div>
</nav>
</header>
<article class="container">
<section class="col-md-12">
<a class="edit-on-gh" href="https://github.com/apache/struts-site/edit/master/source/tag-developers/freemarker-tags.md" title="Edit this page on GitHub">Edit on GitHub</a>
<a href="index" title="back to Tag Developers Guide"><< back to Tag Developers Guide</a>
<h1 class="no_toc" id="freemarker-tags">FreeMarker Tags</h1>
<ul id="markdown-toc">
<li><a href="#attributes-and-parameters" id="markdown-toc-attributes-and-parameters">Attributes and Parameters</a> <ul>
<li><a href="#using-inline-attributes-with-templates" id="markdown-toc-using-inline-attributes-with-templates">Using inline attributes with templates</a></li>
</ul>
</li>
<li><a href="#attribute-types" id="markdown-toc-attribute-types">Attribute Types</a></li>
<li><a href="#jsp-tag-support" id="markdown-toc-jsp-tag-support">JSP Tag Support</a></li>
</ul>
<p>FreeMarker tags are extensions of the generic <a href="struts-tags">Struts Tags</a> provided by the framework. You can jump
right in just by knowing the generic structure in which the tags can be accessed:</p>
<div class="language-ftl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;@</span><span class="no">s</span><span class="na">.tag</span><span class="err">&gt; ...&lt;/@</span><span class="no">s</span><span class="na">.tag</span><span class="err">&gt;</span><span class="w">
</span></code></pre></div></div>
<p>, where <code class="language-plaintext highlighter-rouge">tag</code> is any of the <a href="tag-reference">tags</a> supported by the framework.</p>
<p>For example, in JSP you might create a form using Struts tags.</p>
<p><strong>JSP Form</strong></p>
<div class="language-jsp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;s:form </span><span class="na">action=</span><span class="s">"updatePerson"</span><span class="nt">&gt;</span>
<span class="nt">&lt;s:textfield </span><span class="na">label=</span><span class="s">"First name"</span><span class="na"> name=</span><span class="s">"firstName"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;s:submit </span><span class="na">value=</span><span class="s">"Update"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/s:form&gt;</span>
</code></pre></div></div>
<p>In FreeMarker the same form can also be built using Struts tags.</p>
<p><strong>FTL Form</strong></p>
<div class="language-ftl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;@</span><span class="no">s</span><span class="na">.form</span><span class="w"> </span>action="updatePerson"&gt;<span class="w">
</span>&lt;@s.textfield label="First name" name="firstName"/&gt;<span class="w">
</span>&lt;@s.submit value="Update"/&gt;<span class="w">
</span><span class="err">&lt;/@</span><span class="no">s</span><span class="na">.form</span><span class="err">&gt;</span><span class="w">
</span></code></pre></div></div>
<p><strong>But, wait there’s more!</strong></p>
<p>Aside from doing everything that the JSP tags do, the FTL tags boast additional features that you can use to make your
pages even easier to code. You can even invoke third-party JSP taglibs as if there were native FTL tags.</p>
<h2 id="attributes-and-parameters">Attributes and Parameters</h2>
<p>Unlike older versions of JSP (in which the <a href="jsp-tags">JSP Tags</a> are based), FreeMarker allows for <em>dynamic attributes</em>,
much like JSP 2.0. You can supply attributes to the tags that the tag doesn’t explicitedly support. Those attributes
that cannot be applied directly to the tag object will be set to the tag’s general-purpose <code class="language-plaintext highlighter-rouge">parameters</code> Map.</p>
<p>Suppose we wanted to build an URL in a JSP. The URL needs to take an arbitary parameter to the query string,
that (being arbitary) isn’t specified on the URL tag. In a JSP, we’d have to use the <code class="language-plaintext highlighter-rouge">url</code> and <code class="language-plaintext highlighter-rouge">param</code> tags together.</p>
<p><strong>Creating a URL with a query string (JSP)</strong></p>
<div class="language-jsp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;s:url </span><span class="na">value=</span><span class="s">"somePage"</span><span class="nt">&gt;</span>
<span class="nt">&lt;s:param </span><span class="na">name=</span><span class="s">"personId"</span><span class="na"> value=</span><span class="s">"%{personId}"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/s:url&gt;</span>
</code></pre></div></div>
<p>In FreeMarker, we can pass the arbitrary parameter directly and create the URL in one simple statement.</p>
<p><strong>Creating a URL with a query string (FTL)</strong></p>
<div class="language-ftl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;@</span><span class="no">s</span><span class="na">.url</span><span class="w"> </span>value="somePage" personId="%<span class="p">{</span><span class="no">personId</span><span class="p">}</span>"/&gt;<span class="w">
</span></code></pre></div></div>
<h3 id="using-inline-attributes-with-templates">Using inline attributes with templates</h3>
<p>Suppose you created a “three column” theme to replace the typical two column theme (xhtml). You might want an additional
parameter to display in the third column called “description”. Using FreeMarker, you can just pop the description
attribute into the textfield tag, no fuss, no muss.</p>
<p><strong>Passing an attribute to the template</strong></p>
<div class="language-ftl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;@</span><span class="no">s</span><span class="na">.form</span><span class="w"> </span>action="updatePerson"&gt;<span class="w">
</span>&lt;@s.textfield label="First name" name="firstName" description="..."/&gt;<span class="w">
</span>&lt;@s.submit value="Update"/&gt;<span class="w">
</span><span class="err">&lt;/@</span><span class="no">s</span><span class="na">.form</span><span class="err">&gt;</span><span class="w">
</span></code></pre></div></div>
<p>In the new template, the description is referenced via the parameters Map: <code class="language-plaintext highlighter-rouge">${parameters.description}</code>.</p>
<blockquote>
<p>For simple cases, inline attributes are much easier to use than the param} tag. But, the <code class="language-plaintext highlighter-rouge">param</code> tag is more flexible
than inline attributes for advanced use cases. For example, <code class="language-plaintext highlighter-rouge">param</code> can take the entire body of the tag and apply
that as the <code class="language-plaintext highlighter-rouge">value</code> attribute.</p>
</blockquote>
<h2 id="attribute-types">Attribute Types</h2>
<p>Remember that all tag attributes must first be set as Strings - they are then later evaluated (using <a href="ognl">OGNL</a>)
to a different type, such as List, int, or boolean. This generally works just fine, but it can be limiting when using
FreeMarker which provides more advanced ways to apply attributes. Suppose the following example:</p>
<div class="language-ftl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;@</span><span class="no">s</span><span class="na">.select</span><span class="w"> </span>label="Foo label - %<span class="p">{</span><span class="no">foo</span><span class="p">}</span>" name="%<span class="p">{</span><span class="no">name</span><span class="p">}</span>" list="%<span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">}</span>"/&gt;<span class="w">
</span></code></pre></div></div>
<p>What will happen here is that each attribute will be evaluated to a String as best it can. This may involve calling the
<code class="language-plaintext highlighter-rouge">toString</code> method on the internal FreeMarker objects. In this case, all objects will end up being exactly what you would
expect. Then, when the tag runs, the <code class="language-plaintext highlighter-rouge">list</code> attribute will be converted from a String to a List using <a href="ognl">OGNL</a>’s
advanced collection support.</p>
<p>But suppose you wish to use FreeMarker’s list or hash support instead? You can do this:</p>
<div class="language-ftl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;@</span><span class="no">s</span><span class="na">.select</span><span class="w"> </span>label="Foo label - %<span class="p">{</span><span class="no">foo</span><span class="p">}</span>" name="%<span class="p">{</span><span class="no">name</span><span class="p">}</span>" list=[1, 2, 3]/&gt;<span class="w">
</span></code></pre></div></div>
<p>Notice that the list attribute no longer has quotes around it. Now it will come in to the tag as an object that can’t
easily be converted to a String. Normally, the tag would just call <code class="language-plaintext highlighter-rouge">toString</code>, which would return <code class="language-plaintext highlighter-rouge">[1, 2, 3]</code> and be
unable to be converted back to a List by OGNL. Rather than go through all this back and forth, the frameworks’s FreeMarker
tag support will recognize collections and not pass them through the normal tag attribute. Instead, the framework will
set them directly in the <code class="language-plaintext highlighter-rouge">parameters</code> Map, ready to be consumed by the template.</p>
<p>In the end, everything tends to do what you would expect, but it can help to understand the difference of when OGNL is
being used and when it isn’t, and how attribute types get converted.</p>
<h2 id="jsp-tag-support">JSP Tag Support</h2>
<p>While the framework provides native FreeMarker Tags, you might wish to use other third-party tags that are only available
for JSP. Fortunately, FreeMarker has the ability to run JSP tags. To do so, you must include the JspSupportServlet in
the application’s <code class="language-plaintext highlighter-rouge">web.xml</code>, as this allows the FreeMarker integration to get access to the required objects needed
to emulate a JSP taglib container.</p>
<p><strong>Adding JspSupportSerlvet to web.xml</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;servlet&gt;</span>
<span class="nt">&lt;servlet-name&gt;</span>JspSupportServlet<span class="nt">&lt;/servlet-name&gt;</span>
<span class="nt">&lt;servlet-class&gt;</span>org.apache.struts2.views.JspSupportServlet<span class="nt">&lt;/servlet-class&gt;</span>
<span class="nt">&lt;load-on-startup&gt;</span>1<span class="nt">&lt;/load-on-startup&gt;</span>
<span class="nt">&lt;/servlet&gt;</span>
</code></pre></div></div>
<p>Once you’ve done that, you can simply add something like this in your templates:</p>
<div class="language-ftl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;#</span><span class="no">assign</span><span class="w"> </span>cewolf=JspTaglibs["/WEB-INF/cewolf.tld"] /&gt;<span class="w">
</span><span class="err">...</span><span class="w">
</span><span class="err">&lt;@</span><span class="no">cewold</span><span class="na">.xxx</span><span class="err"> ...</span><span class="w"> </span>/&gt;<span class="w">
</span></code></pre></div></div>
</section>
</article>
<footer class="container">
<div class="col-md-12">
Copyright &copy; 2000-2022 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
Apache Struts, Struts, Apache, the Apache feather logo, and the Apache Struts project logos are
trademarks of The Apache Software Foundation. All Rights Reserved.
</div>
<div class="col-md-12">Logo and website design donated by <a href="https://softwaremill.com/">SoftwareMill</a>.</div>
</footer>
<script>!function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, "script", "twitter-wjs");</script>
<script src="https://apis.google.com/js/platform.js" async="async" defer="defer"></script>
<div id="fb-root"></div>
<script>(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
</body>
</html>