FREEMARKER学习笔记

一.背景概念

Freemarker之前一直零零散散的接触过一些,都没有很好的去总结过,这里做个学习笔记。Freemarker是一个模板引擎,可以看成和JSP扮演差不多的角色。在Struts2中有大量的应用,基于模板生成文本输出。本身使用纯Java编写,优点很多,缺点是分布式环境中的性能不怎么样。经常被用来设计生成HTML Web页面,但是并不限于此,在普通的Java项目里面也可以应用,比如实现一个Java代码生成器。和JSP不一样的是,Freemarker不依赖于容器,也就是说,他并不知道有HTTP,servlet之类的,只要有基本的Java运行环境即可。

二.用法

2.1 HelloWorld

先来个HelloWorld程序简单感受下用法,当然在此之前有些概念先说一下。Freemarker的data根节点是一个map,下面可以有很多的(Key,Value).继续往下层还可以套很多的容器等子节点,总体是一个树状结构。另外,虽然Freemarker也具备一定的编程能力,但常用的模式还是,Java程序提供数据,freemarker负责模板。
首先创建一个普通Java程序,导入Freemarker的jar包,项目目录下新建templates目录,其下新建hello.ftl模板文件,写入以下内容:

hello,${user}!

然后新建Java类,开始HelloWorld效果测试,

    package com.zqx.test;
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import java.io.File;
    import java.io.OutputStreamWriter;
    import java.io.Writer;
    import java.util.HashMap;
    import java.util.Map;

    public class TestFreemarker {
    public static void main(String[] args) throws Exception{
    //创建Freemarker配置实例
    Configuration configuration = new Configuration();
    configuration.setDirectoryForTemplateLoading(new File("templates"));

    //创建数据模型
    Map root = new HashMap();
    root.put("user","zqx");

    //加载模板文件
    Template template = configuration.getTemplate("hello.ftl");

    //显示生成的数据
    Writer out = new OutputStreamWriter(System.out);
    template.process(root,out);
    out.flush();
    out.close();

    }

    }

结果如下:

2.2 常用指令

1.if指令
模板文件hello.ftl里面加入以下内容

	------------if指令测试-----------------
	<#if user=="zqx" >
		身份验证通过
	<#else>
		身份验证失败
	</#if>
	************
	<#if random lt 60>
	  分数:${random},不及格
	<#elseif random lte 80>
	  分数:${random},良好
	<#else >
	  分数:${random},优秀
	</#if>

Java类TestFreemarker.java加入这句:
root.put("random",new Random().nextInt(100));
输出结果:

这里可以顺路提一下:
字符串类型可以使用单引号或双引号。里面可以使用转移字符"",如果存在大量的特殊字符,可以在引号前面直接加上一个r,则所有字符将直接输出。
数值类型可以直接输入,不需要引号,不支持科学记数法。

2.list指令
模板文件hello.ftl里面加入以下内容

	------------list指令测试-----------------
	<#list lst as girl>
	<b>姓名:${girl.name},年龄:${girl.age}</b></br>
	</#list>
	新建Girl类,并在Java类TestFreemarker.java加入这段:
	List list = new ArrayList();
	list.add(new Girl("小丽",18,"A"));
	list.add(new Girl("小美",13,"B"));
	list.add(new Girl("小红",22,"C"));
	root.put("lst",list);

测试结果:

3.include指令
该指令可以引入其他文件,并不仅限于模板文件。也可以是其他类型的文本文件。
templates下新建include.ftl文件:

    hello,${user},我是被包含的文件~

在hello.ftl中引用:

    ------------include指令测试-----------------
    <#include "include.ftl" />

结果:

4.marco自定义指令
类似于函数,过程,方法等概念。
在hello.ftl继续加入以下内容:

	------------marco指令测试-----------------

	<#macro m1 > <#-- 定义不带参数的宏指令 -->
	<b>aaaaaaaaaaaa </b>
	<b>bbbbbbbbbbbb </b>
	</#macro>
	第一次调用:
	<@m1></@m1>
	第二次调用:
	<@m1/>

	<#macro m2 a b c > <#-- 定义带参数的宏指令,自动类型转换 -->
	${a}---${b}---${c}
	</#macro>

	调用带参数的宏指令:
	<@m2 "a" "bb" "ccc"/>

结果:

5.nested指令
在hello.ftl中加入:

	------------nested指令测试-----------------
	<#macro border width>
	<table border="4" width="${width}px">
	<tr>
	<td>
	<#nested />
	</td>
	</tr>
	</table>
	</#macro>

	测试nested指令:
	<@border 100>
	单元格内容
	</@border>

结果:

6.命名空间
类似于Java里的package,主要为了防止命名冲突
templates下新建import.ftl文件:

    <#macro copyright date>
        <p>Copyright (C) ${date} 汉得信息</p>
    </#macro>
    <#assign mail = "2443934916@qq.com" />

在hello.ftl里加入

	------------import指令测试-----------------
	<#import "import.ftl" as bb />
	<@bb.copyright date="1998-2018" />
	${bb.mail}

	<#assign mail="jxlpzqx@163.com" />
	${mail}
	<#assign mail="qingxin.zhu@hand-china.com" in bb />
	${bb.mail}

命名空间命名规则:
一个重要规则是ftl模板文件的路径不应该包含大写字母,为了分割单词应该使用下划线。
另外,结合前面的自定义marco宏指令说一下,freemarker自带的指令一般都以#开头,如<#if></#if>. 自定义指令一般一@开头,其他框架中定义的指令也看做自定义指令,但一般会多一个命名空间,Struts2的默认命名空间我们指定为s:

    <#assign s=JspTaglibs["/WEB-INF/struts-tags.tld"] /> <#--这一句是为了让Freemarker识别struts2的标签 -->

使用就可以这样使用了:

    <@s.form></@s.form>

结果:

7.date类型处理
在hello.ftl里加入

    ------------date类型测试-----------------
    ${date?string("yyyy-MM-dd HH:mm:ss")}

在在Java类TestFreemarker.java加入

    root.put("date",new Date());

结果:

8.空值处理
在hello.ftl里加入

	------------空值处理测试-----------------
	<#-- ${nullval} 没有定义这个变量会报异常 -->
	${nullval!} <#-- 如果没有定义,默认为空字符串 -->
	${nullval!"aaa"} <#-- 如果没有定义,使用给定默认值aaa -->
	<#-- ??返回布尔值,可以判断变量是否存在 -->
	<#if user??><h1>Welcome ${user}!</h1></#if>

结果:

另外,注意一下,这里我们为了测试方便,out流都指向了控制台输出。同理,我们把流指向文件,response到浏览器,甚至于通过scoket指向远程的某个地方都是没问题的。

2.3 在web项目中使用Freemarker

可以直接参考freemarker的examples参考项目webapp1,这里直接粘一些主要代码,方便自己以后查找
Web.xml

	<?xml version="1.0" encoding="ISO-8859-1"?>

	<!DOCTYPE web-app
		PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
		"http://java.sun.com/dtd/web-app_2_3.dtd">

	<web-app>
	  <display-name>FreeMarker Example Web Application 1</display-name>
	  <servlet>
		<servlet-name>hello</servlet-name>
		<servlet-class>example.HelloServlet</servlet-class>
	  </servlet>
	  <servlet-mapping>
		<servlet-name>hello</servlet-name>
		<url-pattern>/hello</url-pattern>
	  </servlet-mapping>
	  <welcome-file-list>
		  <welcome-file>help.html</welcome-file>
	  </welcome-file-list>
	</web-app>

Servlet中调用:

	package example;

	import java.util.*;
	import java.io.*;
	import javax.servlet.*;
	import javax.servlet.http.*;
	import freemarker.template.*;

	/**
	 * This Servlet does not do anything useful, just prints "Hello World!". The
	 * intent is to help you to get started if you want to build your own Controller
	 * servlet that uses FreeMarker for the View. For more advanced example, see the
	 * 2nd Web application example.
	 */
	public class HelloServlet extends HttpServlet {
		private Configuration cfg; 
		
		public void init() {
			// Initialize the FreeMarker configuration;
			// - Create a configuration instance
			cfg = new Configuration();
			// - Templates are stoted in the WEB-INF/templates directory of the Web app.
			cfg.setServletContextForTemplateLoading(
					getServletContext(), "WEB-INF/templates");
			// In a real-world application various other settings should be explicitly
			// set here, but for the sake of brevity we leave it out now. See the
			// "webapp2" example for them.
		}
		
		protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
			
			// Build the data-model
			Map root = new HashMap();
			root.put("message", "Hello World!");
			
			// Get the templat object
			Template t = cfg.getTemplate("test.ftl");
			
			// Prepare the HTTP response:
			// - Use the charset of template for the output
			// - Use text/html MIME-type
			resp.setContentType("text/html; charset=" + t.getEncoding());
			Writer out = resp.getWriter();
			
			// Merge the data-model and the template
			try {
				t.process(root, out);
			} catch (TemplateException e) {
				throw new ServletException(
						"Error while processing FreeMarker template", e);
			}
		}
	}

三. 其他

到这里,Freemarker就算是入门了。至于其他的更具体,更详细的用法,包括集合,map的各种用法啊,也不可能全记,用到了再去查就是了。
主要参考一个忘了在哪里找到的视频

posted @ 2018-10-28 20:13  zhuqingxin  阅读(267)  评论(0编辑  收藏  举报