1.FreeMarker入门
1.1 FreeMarker简介
1.2 FreeMarker官方文档
官方中文文档:http://freemarker.foofun.cn/toc.html
官方文档:https://freemarker.apache.org/
1.3 Maven仓库地址
地址: http://mvnrepository.com/artifact/org.freemarker/freemarker
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
2.使用程序开发
2.1入门小Demo,使用FreeMarker生成简单网页
2.1.1 创建Maven工程,引入FreeMarker依赖
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
2.1.2 基本结构
2.1.2 简单的Demo
Demo01
public class Demo01 {
public static void main(String[] args) throws Exception {
//1.创建配置类 Configuration.VERSION_2_3_28 版本
Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
//2.设置模板所在目录
cfg.setDirectoryForTemplateLoading(new File("E:\\基础项目\\Java_Project\\java_project_idea\\other-farmework\\freemarker-demo\\src\\main\\resources\\"));
//3.设置编码方式
cfg.setDefaultEncoding("UTF-8");
//4.设置错误显示方式
//IGNORE_HANDLER 这只是跳过失败的指令,让模板继续执行。
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
//5.设置数据模型
Map<String, Object> dataModel = new HashMap<String, Object>();
dataModel.put("content", "Hello World");
//6.设置模板
Template temp = cfg.getTemplate("freemarkerForHtmlTemplate.ftl");
//7.创建输出流,设置生成文件
Writer out = new FileWriter("D:\\page\\index.html");
//8.生成页面
temp.process(dataModel, out);
//9.关闭输出流
out.close();
}
}
freemarkerForHtmlTemplate.ftl 模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
${content}
</body>
</html>
结果:
2.2 基本数据模型
2.2.1基本标量
4种类型的标量
- 布尔值
- 数字
- 字符串
- 日期类型(子类型: 日期(没有时间部分 date),时间(time)或者日期-时间(datetime))
每一种标量类型都是 TemplateTypeModel 接口的实现,这里的 Type 就是类型的名称。这些接口只定义了一个方法: type getAsType();。 它返回变量的Java类型(boolean, Number, String 和 Date 各自代表的值)。
2.2.1.1 常见的标量类型
类名 | 属性 |
---|---|
SimpleDate | Date |
SimpleHash | Map |
SimpleNumber | 数字 |
SimpleScalar | 字符串 |
SimpleList | List |
SimpleSequence | 序列 |
SimpleCollection | 集合 |
2.2.1.2 分析SimpleNumber的实现
/**
* A simple implementation of the <tt>TemplateNumberModel</tt>
* interface. Note that this class is immutable.
*
* <p>This class is thread-safe.
*/
public final class SimpleNumber implements TemplateNumberModel, Serializable {
/**
* @serial the value of this <tt>SimpleNumber</tt>
*/
private final Number value;
public SimpleNumber(Number value) {
this.value = value;
}
public SimpleNumber(byte val) {
this.value = Byte.valueOf(val);
}
public SimpleNumber(short val) {
this.value = Short.valueOf(val);
}
public SimpleNumber(int val) {
this.value = Integer.valueOf(val);
}
public SimpleNumber(long val) {
this.value = Long.valueOf(val);
}
public SimpleNumber(float val) {
this.value = Float.valueOf(val);
}
public SimpleNumber(double val) {
this.value = Double.valueOf(val);
}
public Number getAsNumber() {
return value;
}
@Override
public String toString() {
return value.toString();
}
}
可以看出
- 1.SimpleNumber是通过实现TemplateTypeModel 的Number类型来实现操作数字
- 2 .SimpleNumber通过Number代表的值,由此得出我们根据需要的类型可以使用boolean, Number, String 和 Date 代表各自需要的值
2.2.2 容器类型
2.3 自定义方法
2.3.1 文档位置
文档位置:http://freemarker.foofun.cn/pgui_datamodel_method.html
2.3.2创建自定义方法具体步骤
- 1.创建自定义方法类实现TemplateMethodModelEx或者TemplateMethodModel,TemplateMethodModelEx 接口扩展了 TemplateMethodModel
- 2.重写exec(List args)方法
- 3.将方法作为数据添加到数据模型中,由模板调用
2.3.3 例子:
AddMethod 自定义方法类
/**
* 创建一个两个数字相加的方法
* TemplateMethodModelEx 接口扩展了 TemplateMethodModel
*
* @author LGX_TvT
* @date 2018-08-26 20:40
*
*/
public class AddMethod implements TemplateMethodModelEx {
public Object exec(List args) throws TemplateModelException {
if(args.size() != 2){
throw new TemplateModelException("Wrong arguments");
}
return new SimpleNumber(Integer.parseInt(args.get(0).toString()) + Integer.parseInt(args.get(1).toString()));
};
}
Demo01
public class Demo01 {
public static void main(String[] args) throws Exception {
...
...
//代码与前面一样
...
...
//5.设置数据模型
Map<String, Object> dataModel = new HashMap<String, Object>();
dataModel.put("content", "Hello World");
// ==> 添加自定义方法
dataModel.put("AddMethod",new AddMethod());
//6.设置模板
...
...
}
}
freemarkerForHtmlTemplate.ftl 模板调用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
${content}<br>
<#--调用自定义方法-->
${AddMethod(1,2)}
</body>
</html>
结果:
2.4 自定义指令
2.4.1 文档位置
自定义指令文档地址:http://freemarker.foofun.cn/pgui_datamodel_directive.html
2.4.2 具体步骤
- 1.创建自定义指令类实现TemplateDirectiveModel接口,重写execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)方法
- 2.根据params获取参数,按照需求处理数据
- 3.使用IO流将处理后数据输出
2.4.3 实现例子
创建自定义指令将英文字符串首字母转换为大写
UpperInitials
/**
* 自定义首字母大写指令
* @author LGX_TvT
* @date 2018-08-26 21:21
*/
public class UpperInitials implements TemplateDirectiveModel {
private static final String PARAM_NAME_COUNT = "value";
/**
*
* @param env 用于设置环境
* @param params 用于获取参数
* @param loopVars
* @param body 用于操作标签body,如<xxx>标签body</xxx>
*/
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
String upperStr = "";
if (loopVars.length != 0) {
throw new TemplateModelException("This directive doesn't allow loop variables.");
}
if (params.isEmpty()){
throw new TemplateModelException("params(Value) is Empty");
}
//获取参数
Iterator paramIter = params.entrySet().iterator();
//遍历Map集合
while (paramIter.hasNext()) {
Map.Entry ent = (Map.Entry) paramIter.next();
//获取Key与Value
String paramName = (String) ent.getKey();
TemplateModel paramValue = (TemplateModel) ent.getValue();
if (PARAM_NAME_COUNT.equals(paramName)){
//判断value是不是字符串
if (paramValue instanceof TemplateScalarModel){
String value = ((TemplateScalarModel) paramValue).getAsString();
if (!"".equals(value)){
//首字母转换为大写
upperStr = value.substring(0, 1).toUpperCase() + value.substring(1);
}
}else{
throw new TemplateModelException("Type error.This is not TemplateScalarModel(String)");
}
}
//通过env获取输出流输出
Writer out = env.getOut();
out.write(upperStr);
out.flush();
//输出在标签体里面:例如<xxx>body输出内容</xxx>
//if (body != null) {
// out.write(" this is body!!!");
// body.render(env.getOut());
//} else {
// throw new RuntimeException("missing body");
//}
}
}
}
Demo01
public class Demo01 {
public static void main(String[] args) throws Exception {
...
...
//代码与前面一样
...
...
//5.设置数据模型
Map<String, Object> dataModel = new HashMap<String, Object>();
dataModel.put("content", "Hello World");
// ==> 添加自定义方法
dataModel.put("AddMethod",new AddMethod());
// ==> 添加自定义指令
dataModel.put("UpperInitials",new UpperInitials());
//6.设置模板
...
...
}
}
freemarkerForHtmlTemplate.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
${content}<br>
<#--调用自定义方法-->
${AddMethod(1,2)}
<#--使用自定义指令-->
<@UpperInitials value="hello" />
</body>
</html>
结果:
3.模板语言
模板文件中四种元素
1、文本:直接输出的部分
2、注释:<#– xxxx –>格式不会输出
3、插值:即${..}部分,将使用数据模型中的部分替代输出
4、FTL指令:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出。
3.1 FTL指令
3.1.1 assign指令
作用: 此指令用于在页面上定义一个变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<#assign name="zhangsan">
${name}
</body>
</html>
结果:
3.1.2 include指令
作用:此指令用于模板文件的嵌套
head.ftl
<h1>Hello World</h1>
模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<#--测试include指令-->
<#include "head.ftl">
<#--测试assign指令-->
<#assign name="zhangsan">
${name}
</body>
</html>
结果:
3.1.3 if指令
作用:判断
在freemarker的判断中,可以使用= 也可以使用==
<#assign num = 0>
<#if num gt 0>
num > 0
<#elseif num lt 0>
num < 0
<#else>
num == 0
</#if>
结果:
3.1.4 list指令
作用:用于循环
添加数据
//设置数据模型
Map<String, Object> dataModel = new HashMap<String, Object>();
List<String> list = new ArrayList<String>();
list.add("篮球");
list.add("足球");
list.add("排球");
dataModel.put("playList",list);
<#list playList as boal>
序号 ${boal_index}: 名称 ${boal}: 是否还有下一个 ${boal_has_next?c}
</#list>
结果:
…
…
其他的可以查看官方中文文档
http://freemarker.foofun.cn/ref_directives.html
3.2 内建函数
内建函数语法格式: 变量+?+函数名称
3.2.1 size
作用:获取集合大小
<#--测试size函数-->
一共${playList?size}条数据
结果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
一共3条数据
</body>
</html>
3.2.2 eval
作用:转换JSON字符串为对象
在数据模型中添加数据
dataModel.put("person","{'name':'zhangsan','age':14}");
<#assign p=person?eval />
${p.name}
${p.age}
3.2.3
作用:日期格式化
添加数据
dataModel.put("today", new Date());
当前日期:${today?date} <br>
当前时间:${today?time} <br>
当前日期+时间:${today?datetime} <br>
日期格式化:${today?string("yyyy年MM月")}
结果:
3.2.4 c
作用:数字转换为字符串
添加数据
dataModel.put("number",123456789);
3.2.4.1 若没有使用c函数
${number}
结果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
123,456,789
</body>
</html>
3.2.4.2 使用c函数
${number?c}
结果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
123456789
</body>
</html>
3.3 基本运算符
3.3.1 算术运算符
+, - , * , / , %
3.3.2 逻辑运算符
逻辑与:&&
逻辑或:||
逻辑非:!
3.3.3 空值运算符
3.3.3.1 ??
作用:使用??判断某一变量是否存在
用法为:
变量??
如果该变量存在,返回true,否则返回false
3.3.3.2 !
缺失变量默认值:“!”
作用:若该变量不存在可以使用!来设置默认值
${value!'hello'}
若value不存在则输出hello
3.4 保留名称
true:布尔值”true”
false:布尔值”false”
gt:比较运算符”大于”
gte:比较运算符”大于或等于”
lt:比较运算符”小于”
lte:比较运算符”小于或等于”
as:由少数指令使用
in:由少数指令使用
using:由少数指令使用