005_FreeMarker入门程序

一. 创建Configuration实例

1. 使用FreeMarker, 首先, 你应该创建一个freemarker.template.Configuration实例, 然后调整它的设置。Configuration实例是存储FreeMarker应用级设置的核心部分。同时, 它也处理创建和缓存预解析模板(比如: Template对象)的工作。

2. 不需要重复创建Configuration实例; 它的代价很高, 尤其是会丢失缓存。Configuration实例就是应用级别的单例。

3. 当使用多线程应用程序(比如Web网站), Configuration实例中的设置就不能被修改。它们可以被视作为"有效的不可改变的"对象, 也可以使用线程安全技术来保证实例对其它线程也可用。

二. 创建数据模型

1. 在简单的示例中你可以使用java.lang和java.util包中的类, 还有用户自定义的Java Bean来构建数据对象:

1.1. 使用java.lang.String来构建字符串。

1.2. 使用java.lang.Number来派生数字类型。

1.3. 使用java.lang.Boolean来构建布尔值。

1.4. 使用java.util.List或Java数组来构建序列。

1.5. 使用java.util.Map来构建哈希表。

1.6. 使用自定义的bean类来构建哈希表, bean中的项和bean的属性对应。比如: product的price属性(getProperty())可以通过product.price获取。

2. 下面是构建这个数据模型的Java代码片段:

Map<String, Object> root = new HashMap<String, Object>();
List<String> colors = new ArrayList<String>();
colors.add("陶瓷黑");
colors.add("陶瓷白");
root.put("colors", colors);
root.put("id", 100001);
root.put("name", "HUAWEI Mate 40 RS 保时捷设计");
root.put("price", 12999.00F);
root.put("date", new Date(System.currentTimeMillis()));
root.put("fastCharge", true);

3. 在真实应用系统中, 通常会使用应用程序指定的类来代替Map, 它会有JavaBean规范规定的getXxx/isXxx方法。比如有一个和下面类似的类:

public class Product {
	private Integer id; // 商品id
	...

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
	...
}
List<String> colors = new ArrayList<String>();
colors.add("陶瓷黑");
colors.add("陶瓷白");
Product root = new Product(100002, "HUAWEI Mate 40 RS 保时捷设计", 12999.00F, colors, new Date(System.currentTimeMillis()), true);

三. 获取模板

1. 模板代表了freemarker.template.Template实例。典型的做法是从Configuration实例中获取一个Template实例。无论什么时候你需要一个模板实例, 都可以使用它的getTemplate方法来获取。假如我们获取一个test.html模板, 那么就可以这样来做:

Template temp = cfg.getTemplate("test.html");

2. 当调用这个方法的时候, 将会创建一个test.html的Template实例, 通过读取/where/you/store/templates/test.html文件, 之后解析(编译)它。Template实例以解析后的形式存储模板, 而不是以源文件的文本形式。

3. Configuration缓存Template实例, 当再次获得test.html的时候, 它可能再读取和解析模板文件了, 而只是返回第一次的Template实例。

四. 合并模板和数据模型

1. 我们已经知道, 数据模型+模板=输出, 我们有了一个数据模型(root)和一个模板(temp), 为了得到输出就需要合并它们。这是由模板的process方法完成的。它用数据模型root和Writer对象作为参数, 然后向Writer对象写入产生的内容。为简单起见, 这里我们只做标准的输出:

Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);

2. Java I/O相关注意事项: 基于out对象, 必须保证out.close()最后被调用。其它时候, 比如典型的Web应用程序, 那就不能关闭out对象。FreeMarker会在模板执行成功后(也可以在Configuration中禁用)调用out.flush(), 所以不必为此担心。

3. 请注意, 一旦获得了Template实例, 就能将它和不同的数据模型进行不限次数(Template实例是无状态的)的合并。此外, 当Template实例创建之后test.html文件才能访问, 而不是在调用处理方法时。

5. 例子

5.1. 新建一个名为FMRuMen动态Web工程, 同时添加相关jar包。

5.2. 编写FMFactory.java

package com.fm.util;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import freemarker.template.Configuration;
import freemarker.template.TemplateExceptionHandler;

public class FMFactory {
	private final static FMFactory instance = new FMFactory();
	private FMFactory() {}
	public static FMFactory getInstance() {
		return instance;
	}
	
	private Map<String, Configuration> map = new ConcurrentHashMap<String, Configuration>();
	
	// 创建单个Configuration实例
	public synchronized Configuration getCfg(Object servletContext, String path) {
		if(null != map.get(path)) {
			return map.get(path);
		}
		Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
		cfg.setServletContextForTemplateLoading(servletContext, path);
		cfg.setDefaultEncoding("utf-8");
		cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
		map.put(path, cfg);
		
		return cfg;
	}
	
}

5.3. 编写Product.java

package com.fm.model;

import java.io.Serializable;
import java.sql.Date;
import java.util.List;

public class Product implements Serializable {
	private static final long serialVersionUID = 1L;

	private Integer id; // 商品id
	private String name; // 商品名称
	private Float price; // 商品价格
	private List<String> colors; // 商品颜色
	private Date date; // 出厂日期
	private Boolean fastCharge; // 是否支持快充
	
	public Product() {
	}

	public Product(Integer id, String name, Float price, List<String> colors, Date date, Boolean fastCharge) {
		this.id = id;
		this.name = name;
		this.price = price;
		this.colors = colors;
		this.date = date;
		this.fastCharge = fastCharge;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Float getPrice() {
		return price;
	}

	public void setPrice(Float price) {
		this.price = price;
	}

	public List<String> getColors() {
		return colors;
	}

	public void setColors(List<String> colors) {
		this.colors = colors;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public Boolean getFastCharge() {
		return fastCharge;
	}

	public void setFastCharge(Boolean fastCharge) {
		this.fastCharge = fastCharge;
	}

}

5.4. 编写ProductInfo.java

package com.fm.action;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fm.model.Product;
import com.fm.util.FMFactory;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class ProductInfo extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		Configuration cfg = FMFactory.getInstance().getCfg(req.getServletContext(), "WEB-INF/templates/product");
		
//		Map<String, Object> root = new HashMap<>();
//		List<String> colors = new ArrayList<String>();
//		colors.add("陶瓷黑");
//		colors.add("陶瓷白");
//		root.put("colors", colors);
//		root.put("id", 100001);
//		root.put("name", "HUAWEI Mate 40 RS 保时捷设计");
//		root.put("price", 12999.00F);
//		root.put("date", new Date(System.currentTimeMillis()));
//		root.put("fastCharge", true);
		
		// 创建数据模型
		List<String> colors = new ArrayList<String>();
		colors.add("陶瓷黑");
		colors.add("陶瓷白");
		Product root = new Product(100002, "HUAWEI Mate 40 RS 保时捷设计", 12999.00F, colors, new Date(System.currentTimeMillis()), true);
		
		// 获取模板
		Template temp = cfg.getTemplate("product.html");
		Writer out = new OutputStreamWriter(resp.getOutputStream());
		try {
			// 合并模板和数据模型
			temp.process(root, out);
		} catch (TemplateException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}
}

5.5. 编写index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>主页</title>
	</head>
	<body>
		<a href="pi.action">商品信息</a>
	</body>
</html>

5.6. 修改web.xml

5.7. 在WEB-INF/templates/product目录下, 编写product.html模板文件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>商品信息</title>
	</head>
	<body>
		<!-- c(当用于布尔值时)该内建函数将布尔值转换为字符串, 针对"计算机语言"而不是用户。结果是"true"或"false"。c就代表计算机的意思。-->
		<!-- c(当被用作是数字值时)该内建函数将"计算机语言"的数字转换成字符串, 这都是对计算机来说的, 而不是对用户。c就代表计算机的意思。 -->
	  	商品编号: ${id?c} <br />
	  	商品名字: ${name} <br />
	  	商品价格: ¥ ${price?c} <br />
	  	商品颜色: ${colors[0]}, ${colors[1]} <br />
	  	出厂日期: ${date} <br />
	  	<!-- 布尔类型需要转换为字符串类型输出 -->
	  	<!-- booleanExp?then(whenTrue, whenFalse), 就像是类C语言中的三元运算符 -->
	  	支持快充: ${fastCharge?then("支持快充", "不支持快充")}
	</body>
</html>

5.8. 运行项目

5.9. 访问商品信息

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值