1. Overview
FreeMarker is a template engine, a general tool for generating text output based on templates. It is written in pure Java. FreeMarker is designed to generate HTML Web pages, especially applications based on MVC pattern. Although FreeMarker has some programming capabilities, it usually prepares the data to be displayed by Java programs, and generates the pages by FreeMarker, and displays the prepared data through the template (as shown below).
FreeMarker is not a Web application framework, but is suitable as a component of the Web application framework. FreeMarker is not related to containers because it does not know about HTTP or Servlets; FreeMarker can also be applied to non-Web application environments, FreeMarker is more suitable as a view component of Model2 frameworks (such as Struts), and you can also use JSP tag library in templates. Also, FreeMarker is free.
2. Freemarker preparation conditions
Freemarker.2.3.16.jar, the download address will not be posted here... (This jar package is actually in struts2)
3. The principle of Freemarker generating static pages
Freemarker generates a static page. First, you need to use the template page you define yourself. This template page can be the most ordinary html, or it can be a nested value expression, label or custom tag, etc. in the freemarker. Then, the template page is read in the background, parse the tags in it to complete the corresponding operation, and then pass the parameters in the key-value pair to replace the value expression in the template. After that, a new html page can be generated according to the configured path to achieve the purpose of static access.
4. Labels provided by Freemarker
Freemarker provides many useful and commonly used tags. Freemarker tags are named <# tag name> like this. ${value} represents the content of the output variable name, as follows:
1. List: This tag is mainly a list collection passed from the server side through iteratively, such as:
<#list nameList as names> ${names} </#list>name is a loop variable taken when the list loop. When freemarker parses the list tag, it is equivalent to:
for (String names : nameList) { System.out.println(names); }2. if: This tag is mainly used for if judgment, such as:
<#if (names=="Chen Jingchou")>His weapons are: fifteen~~ </#if>
This is a conditional judgment label. It should be noted that the conditional equation must be enclosed in brackets, which is equivalent to:
if(names.equals("Chen Jingchou")){ System.out.println("His weapons are: fifteen~~"); }
3. include: This tag is used to import files.
<#include "include.html"/>
This import tag is very useful, especially for page reuse.
In addition, you can use ${} to get the value in a static file. The value method is the same as the el expression, which is very convenient.
Here is an example (static.html):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> Description: ${description} <br/> Collection size: ${nameList?size} <br/> Iterative list collection: <br/> <#list nameList as names> This is the ${names_index+1} person, called: <label style="color:red">${names}</label> if judgment: <br/> <#if (names=="Chen Jingchou")> His weapons are: fifteen~~ <#elseif (names=="Yuwentuo")> <#-Note that there is no return here but at the end--> His weapons are: Xuanyuan Sword~・ <#else> Her trick is: Gu Poison~~ </#if> <br/> </#list> Iterative map collection: <br/> <#list weaponMap?keys as key> key--->${key}<br/> value----->${weaponMap[key]!("null")} <#-- fremarker does not support null, Can be used! instead of empty value. In fact, you can also give a default value-----${weaponMap[key]?default("null")} You can also determine whether it is null before output <#if weaponMap[key]??></#if>--> <br/> </#list> include import file: <br/> <#include "include.html"/> </body> </html>Actual code:
package com.chenghui.test; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; public class CreateHtml { public static void main(String[] args) { try { //Create a suitable Configuration object Configuration configuration = new Configuration(); configuration.setDirectoryForTemplateLoading(new File("D://project//webProject//WebContent//WEB-INF//template")); configuration.setObjectWrapper(new DefaultObjectWrapper()); configuration.setDefaultEncoding("UTF-8"); //This must be set, otherwise it will be garbled in the generated page // Get or create a template. Template template = configuration.getTemplate("static.html"); Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("description", "I am learning to use Freemarker to generate static files!"); List<String> nameList = new ArrayList<String>(); nameList.add("Chen Jingchou"); nameList.add("Yuer"); nameList.add("Yuwentuo"); paramMap.put("nameList", nameList); Map<String, Object> weaponMap = new HashMap<String, Object>(); weaponMap.put("first", "Xuanyuan Sword"); weaponMap.put("second", "Kongtong Seal"); weaponMap.put("third", "Nuwa Stone"); weaponMap.put("fourth", "Shennong Ding"); weaponMap.put("fifth", "Fuxi Qin"); weaponMap.put("sixth", "Kunlun Mirror"); weaponMap.put("seventh", null); paramMap.put("weaponMap", weaponMap); Writer writer = new OutputStreamWriter(new FileOutputStream("success.html"),"UTF-8"); template.process(paramMap, writer); System.out.println("Congratulations, the generation was successful~~"); } catch (IOException e) { e.printStackTrace(); } catch (TemplateException e) { e.printStackTrace(); } } }
This can basically be considered as simple and simple generation, but it is still far from being used in practice, because the tags given by freemarker cannot meet our needs at all. At this time, custom tags are needed to complete our needs. .
5. Freemarker custom tags
Freemarker custom tags are to write the tags by yourself and then parse them by yourself. They completely control the input and output of the tags by themselves, which greatly provides programmers with a lot of room to play.
Based on steps:
In the past, when writing tags, you need to add # after <, but to recognize custom tags, you need to add @ afterwards, and then you can define some parameters later. When the program executes template.process(paramMap, out);, it will parse all freemarker tags on the entire page.
Customizing the tag requires customizing a class, then implementing the TemplateDirectiveModel, rewriting the execute method, completing the acquisition of parameters, do something according to the parameters, etc. .
To bind custom tags to parse classes, you need to put an instance of the parse class in paramMap, and the stored key is the same as the custom tag. .
Note: In the custom tag, if there is nothing in the tag, the start tag and the end tag must not be the same line, otherwise an error will be reported.
freemarker.log.JDK14LoggerFactory$JDK14Logger error
I've been fooled, and this is a bug in freemarker.
Here is an example of static.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <#--Custom variables--> <#assign num='hehe'///${num} <br/> Custom tags<@content name="chenghui" age="120"> ${output} ${append} </@content> </body> </html>
Here is the parsing class of the static.html template above:
package com.chenghui.test; import static freemarker.template.ObjectWrapper.DEFAULT_WRAPPER; import java.io.IOException; import java.io.Writer; import java.util.Map; import freemarker.core.Environment; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; /** * Custom tag resolution class* @author Administrator * */ public class ContentDirective implements TemplateDirectiveModel{ private static final String PARAM_NAME = "name"; private static final String PARAM_AGE = "age"; @Override public void execute(Environment env, Map params,TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException { if(body==null){ throw new TemplateModelException("null body"); }else{ String name = getString(PARAM_NAME, params); Integer age = getInt(PARAM_AGE, params); //After receiving the parameters, you can perform specific operations according to the specific operation, and then display the data on the page. if(name!=null){ env.setVariable("output", DEFAULT_WRAPPER.wrap("The parameters obtained from the ContentDirective parsing class are: "+name+", ")); } if(age!=null){ env.setVariable("append", DEFAULT_WRAPPER.wrap("Age:"+age)); } Writer out = env.getOut(); out.write(" From here you can see the specific content on the page, just like the document.writer write operation.<br/>"); body.render(out); /* If you are careful, you will find that the page shows the out.write() output statement, and then output the content of output. It can be seen that when the body is parsing, it will first put the parameters into the env, and only when the page encounters the corresponding form, it will get the value. However, if the form does not exist, an error will be reported. I think the freemarker is not done well here, and the error will be exposed to the page when parsing. You can make up for ${output!"null"} in this way, and you always feel that it is not as good as the el expression. */ } } /** * Get the value of the parameter of type String* @param paramName * @param paramMap * @return * @throws TemplateModelException */ public static String getString(String paramName, Map<String, TemplateModel> paramMap) throws TemplateModelException{ TemplateModel model = paramMap.get(paramName); if(model == null){ return null; } if(model instanceof TemplateScalarModel){ return ((TemplateScalarModel)model).getAsString(); }else if (model instanceof TemplateNumberModel) { return ((TemplateNumberModel)model).getAsNumber().toString(); }else{ throw new TemplateModelException(paramName); } } /** * * Get parameter of type int* @param paramName * @param paramMap * @return * @throws TemplateModelException */ public static Integer getInt(String paramName, Map<String, TemplateModel> paramMap) throws TemplateModelException{ TemplateModel model = paramMap.get(paramName); if(model==null){ return null; } if(model instanceof TemplateScalarModel){ String str = ((TemplateScalarModel)model).getAsString(); try { return Integer.valueOf(str); } catch (NumberFormatException e) { throw new TemplateModelException(paramName); } }else if(model instanceof TemplateNumberModel){ return ((TemplateNumberModel)model).getAsNumber().intValue(); }else{ throw new TemplateModelException(paramName); } } }Then add:
//Custom tag parsing paramMap.put("content", new ContentDirective());This way, it can basically be used. Freemarker completes custom tags to solve the problem of writing simple business logic. However, it is impossible to do this in actual projects, because it has not been integrated with spring yet, and you need to put the parsing instance of the parsing class in the parsing time. .