‘macro’ is used to define custom directives.
Syntax
<#macro name param1 param2 ... paramN> ... <#nested loopvar1, loopvar2, ..., loopvarN> ... <#return> ... </#macro>
‘name’: Name of Macro variable.
param1, param2, ...: The name of the local variables store the parameter values
paramN: the last parameter may optionally have 3 trailing dots (...), which indicates that the macro takes a variable number of parameters
loopvar1, loopvar2, ...etc.: Optional. The values of loop variables that the nested directive wants to create for the nested content.
Example
<#macro quotations> - Be yourself; everyone else is already taken. - Be the change that you wish to see in the world. - Live as if you were to die tomorrow. </#macro>
‘macro’ directive itself does not print anything. Information between <#macro quotations> and <#macro> will be executed only when you use the variable ‘quotations’ as a directive.
How to use user-defined directive?
Use @symbol to call the directive.
Example
<@quotations></@quotations>
Find the below working application.
Step 1: Define 'macroDef1.ftl' file under src/main/resources/templates folder.
macroDef1.ftl
<#macro quotations> - Be yourself; everyone else is already taken. - Be the change that you wish to see in the world. - Live as if you were to die tomorrow. </#macro> Printing Quotations <@quotations></@quotations> Printing Quotations Again <@quotations></@quotations>
Step 2: Define ‘FreeMarkerUtil’ class that takes model class and template file as input and merge them.
FreeMarkerUtil.java
package com.sample.app.util;
import java.io.StringWriter;
import java.util.Locale;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
public class FreeMarkerUtil {
private static final Configuration FREE_MARKER_CONFIGURATION = new Configuration(Configuration.VERSION_2_3_30);
static {
FREE_MARKER_CONFIGURATION.setClassForTemplateLoading(FreeMarkerUtil.class, "/templates/");
FREE_MARKER_CONFIGURATION.setDefaultEncoding("UTF-8");
FREE_MARKER_CONFIGURATION.setLocale(Locale.US);
FREE_MARKER_CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
FREE_MARKER_CONFIGURATION.setFallbackOnNullLoopVariable(false);
}
public static StringWriter mergeModelAndTemplate(Object modelObject, String ftlFile) throws Exception {
StringWriter stringWriter = new StringWriter();
Template template = FREE_MARKER_CONFIGURATION.getTemplate(ftlFile);
template.process(modelObject, stringWriter);
return stringWriter;
}
}
Step 3: Define MacroDef1Populator.
MacroDef1Populator.java
package com.sample.app;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import com.sample.app.util.FreeMarkerUtil;
public class MacroDef1Populator {
public static void main(String args[]) throws Exception {
Map<String, Object> modelObject = new HashMap<String, Object>();
StringWriter stringWriter = FreeMarkerUtil.mergeModelAndTemplate(modelObject, "macroDef1.ftl");
System.out.println(stringWriter.toString().trim());
}
}
Run the application, you will see below messages in the console.
Printing Quotations - Be yourself; everyone else is already taken. - Be the change that you wish to see in the world. - Live as if you were to die tomorrow. Printing Quotations Again - Be yourself; everyone else is already taken. - Be the change that you wish to see in the world. - Live as if you were to die tomorrow.
Passing Parameters to a macro
<#macro sum a b>
Sum of ${a} and ${b} is ${a+b}
</#macro>
You can call the sum macro with parameters 10 and 20 like below.
<@sum 10 20></@sum>
You can even call the macro with variable names.
For example,
<#macro employee id name age>
Hi ${name}, your id is ${id} and you are ${age} years old
</#macro>
You can call the employee directive like below.
<@employee id=76 name="Ram" age=32></@employee>
If you use variable names, then the order of variables doesn’t matter.
macroParameters.ftl
<#macro sum a b>
Sum of ${a} and ${b} is ${a+b}
</#macro>
<@sum 10 20></@sum>
<@sum 20 30></@sum>
<@sum 30 40></@sum>
<#macro employee id name age>
Hi ${name}, your id is ${id} and you are ${age} years old
</#macro>
<@employee 123 "Krishna" 31></@employee>
<@employee id=76 name="Ram" age=32></@employee>
MacroParametersPopulator.java
package com.sample.app;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import com.sample.app.util.FreeMarkerUtil;
public class MacroParametersPopulator {
public static void main(String args[]) throws Exception {
Map<String, Object> modelObject = new HashMap<String, Object>();
StringWriter stringWriter = FreeMarkerUtil.mergeModelAndTemplate(modelObject, "macroParameters.ftl");
System.out.println(stringWriter.toString());
}
}
Output
Sum of 10 and 20 is 30 Sum of 20 and 30 is 50 Sum of 30 and 40 is 70 Hi Krishna, your id is 123 and you are 31 years old Hi Ram, your id is 76 and you are 32 years old
Providing default value to variables in a macro
For example, I defined sum macro like below.
<#macro sum a=10 b=20>
Sum of ${a} and ${b} is ${a+b}
</#macro>
If you do not pass any values to the macro sum, then 10 is taken as the default value for the variable a, and 20 is taken as the default value for the variable b.
<@sum></@sum>: Call the macro sum. Since we do not pass any values a is assigned with value 10 and b is assigned with value 20.
<@sum 19></@sum>: Since I passed 19 as an argument, 'a' will be assigned with value 19, and 'b' will be assigned to the default value which is 20.
<@sum b=40></@sum>: Since I do not pass any value to the variable 'a', it will be assigned with default value 10.
macroDefaultValues.ftl
<#macro sum a=10 b=20>
Sum of ${a} and ${b} is ${a+b}
</#macro>
<@sum></@sum>
<@sum 19></@sum>
<@sum b=40></@sum>
MacroDefaultValuePopulator.java
package com.sample.app;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import com.sample.app.util.FreeMarkerUtil;
public class MacroDefaultValuePopulator {
public static void main(String args[]) throws Exception {
Map<String, Object> modelObject = new HashMap<String, Object>();
StringWriter stringWriter = FreeMarkerUtil.mergeModelAndTemplate(modelObject, "macroDefaultValues.ftl");
System.out.println(stringWriter.toString());
}
}
Output
Sum of 10 and 20 is 30 Sum of 19 and 20 is 39 Sum of 10 and 40 is 50
Nested content
We can pass content to a custom directive and it can be accessed using ‘nested’ directive.
For example, I defined a macro as below.
<#macro welcome name>
<#nested> ${name}
</#macro>
<@welcome "Krishna">Good Morning</@welcome>
Prints "Good Morning Krishna"
<@welcome "Narasimha">Good Afternoon</@welcome>
Prints "Good Afternoon Narasimha"
<@welcome "Loopa">Good Evening</@welcome>
Prints "Good Evening Loopa"
Find the below working application.
macroNestedContent.ftl
<#macro welcome name>
<#nested> ${name}
</#macro>
<@welcome "Krishna">Good Morning</@welcome>
<@welcome "Narasimha">Good Afternoon</@welcome>
<@welcome "Loopa">Good Evening</@welcome>
MacroNestedContentPopulator.java
package com.sample.app;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import com.sample.app.util.FreeMarkerUtil;
public class MacroNestedContentPopulator {
public static void main(String args[]) throws Exception {
Map<String, Object> modelObject = new HashMap<String, Object>();
StringWriter stringWriter = FreeMarkerUtil.mergeModelAndTemplate(modelObject, "macroNestedContent.ftl");
System.out.println(stringWriter.toString());
}
}
Output
Good Morning Krishna Good Afternoon Narasimha Good Evening Loopa
Note
a. Local variables of macro do not visible in nested content.
No comments:
Post a Comment