FreeMark模板基本知识
FreeMarker模板基础知识
1、FreeMarker与jsp、Thymeleaf并排为三大模板引擎,用于把后端数据渲染到页面上,降低耦合度。动态数据+占位符+静态页面标签构成动态页面。
2、FreeMarker 是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电
子邮件,配置文件,源代码等)的通用工具。 是一个Java类库。
3、FreeMarker被设计用来生成 HTML Web页面,特别是基于MVC模式的应用程序,将视图从业务逻辑中抽离出来,业务中不再包括视图的展示,而是将视图交给 FreeMarker 来输出。虽然 FreeMarker 具有一些编程的能力,但通常由 Java 程序准备要显示的数据,由 FreeMarker 生成页面,通过模板显示准备的数据。
4、FreeMarker与容器无关,因为它并不知道HTTP或Servlet。FreeMarker同样可以应用于非Web应用程序环境。我们上面的案例只是通过servlet来制造数据模型而已,在非web环境下依然可以(例:页面静态化例子)。
1、快速搭建
- 创建Maven Web工程
- 导入依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--导入freemarker坐标依赖-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.29</version>
</dependency>
- 配置web.xml文件
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<!--配置模板引擎根目录 表示在webapp目录下创建以.ftl后缀的文件-->
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
</init-param>
<init-param>
<param-name>DefaultEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
- 创建ftl页面
<#--freemarker隐性注释-->
<!--显性注释 浏览器检查功能能显示的注释-->
<h1>${msg}</h1>
4、创建Servlet类
/*应该先访问Servlet*/
@WebServlet("/ftl")
public class DataServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("msg","Hello word");
req.getRequestDispatcher("index.ftl").forward(req,resp);
}
}
2、数据类型
布尔类型:true false 不能展示在页面上,要转换为字符串,否则会报错。
数值类型:int float double long等 可以直接展示在页面。
日期类型:不能展示在页面上,要转为字符串格式。
字符型:可以直接展示在页面上。
sequence(序列):等价于java的数组 Array list类型。
hash:等价与java中的Map类型。
在FreeMarker模板中,如果变量值为null或者展示不存在的变量会出现异常报错,我们需要特殊处理。
- *.ftl后缀代码
<#--布尔类型处理 不能直接展示在页面 要转为字符串-->
<#--第一种方式: ?c转换为字符串-->
<h1>${bool?c}</h1>
<#--第二种方式:?string转换为字符串-->
<h1>${bool?string}</h1>
<#--第三种方式:?then("true展示的字符串","false展示的字符串")-->
<h1>${bool?then('这个值是对的','这个值错的')}</h1>
<hr>
<#--日期类型处理 也不能直接展示,要转为字符日期型-->
<#--只显示日期-->
<h1>${date?date}</h1>
<#--只显示时间-->
<h1>${date?time}</h1>
<#--显示日期时间-->
<h1>${date?datetime}</h1>
<#--指定字符串格式化输出-->
<h1>${date?string('yyyy年MM年dd HH时mm分ss秒')}</h1>
<hr>
<#--处理字符串 字符串可以直接展示-->
<p>${str}</p>
<#--可以用常用的函数进行操作-->
<#--截取 [0,3)只截取前三个字符-->
<p>${str?substring(0,3)}</p>
<#--首字符大写-->
<p>${str?cap_first}</p>
<#--首字符不大写-->
<p>${str?uncap_first}</p>
<#--转为大写-->
<p>${str?upper_case}</p>
<#--转为小写-->
<p>${str?lower_case}</p>
<#--查询字符的下标 如果不存在就报错-->
<p>${str?index_of('yy')}</p>
<#--以什么开头 考虑到starts_with返回布尔值 应该转为字符串展示-->
<p>${str?starts_with('ys')?string}</p>
<#--以什么结尾-->
<p>${str?ends_with('ys')?string}</p>
<#--查询字符串的长度-->
<p>${str?length}</p>
<#--替换指定字符串-->
<p>${str?replace('ys','hello')}</p>
<hr>
<#--数值类型 默认会加,进行分隔 -->
<p>${number}</p>
<#--转为货币型-->
<p>${number?string.currency}</p>
<#--转为百分比-->
<p>${number?string.percent}</p>
<#--数值转为普通字符串-->
<p>${number?c}</p>
<#--保留指定小数位的浮点型 #表示一位小数-->
<p>${number?string('0.##')}</p>
<hr>
<#--处理null和不存在的变量-->
<#--处理不存在的变量 返回布尔 不存在返回false-->
<p>${a???c}</p>
<#--处理null 如果这个值是null 设置默认显示字符(这个null值)-->
<p>${val!'这个null值'}</p>
<#--第二种处理方式 把null值默认设置为" "也就是不显示 不会报异常-->
<p>${val!}</p>
- sequence数据类型处理
//Servlet代码
List<String> lists= Arrays.asList("北京","上海","重庆","武汉","贵州","深圳");
req.setAttribute("citys",lists);
String[] names=new String[]{"张三","李四","王五","陈六","赵七"};
req.setAttribute("names",names);
List<UserInfo> userInfos=new ArrayList<>();
userInfos.add(new UserInfo(1001,"zs","1123","bj"));
userInfos.add(new UserInfo(1002,"ls","1234","ss"));
userInfos.add(new UserInfo(1003,"ww","789456","sz"));
userInfos.add(new UserInfo(1004,"zl","12789","tj"));
req.setAttribute("userInfos",userInfos);
req.getRequestDispatcher("index2.ftl").forward(req,resp);
//ftl文件代码 freemarker
<#--sequence类型相当于java中的集合和数组-->
<#--打印全部数组-->
<#list citys as c>
${c}<br>
</#list>
<#--打印数组索引-->
<#list citys as index>
${index?index}
</#list>
<br>
<#--通过下标获取数组的值-->
<#list citys as index>
${index_index}
</#list>
<hr>
<#--常用的函数-->
<#--获取第一个值 ?frist 最后一个值?last 长度?size-->
${citys?size}
${citys?first}
${citys?last}<br>
<#--对值进行排序-->
<#list citys?sort as index>
${index}
</#list>
<br>
<#--对值排序反转-->
<br>
<#--对值排序反转-->
<#list citys?sort?reverse as index>
${index}
</#list>
<br>
<#list citys as i>
${i}
</#list>
${citys[1]}
<br>
<#list userInfos as u>
${u}<br>
</#list>
<br>
<#--根据指定属性进行排序-->
<#list userInfos?sort_by('userId') as u>
${u}<br>
</#list>
<#--获取指定的属性值 属性名区分大小写-->
<#list userInfos?sort_by('userId') as u>
${u.userName}<br>
</#list>
- Hash数据类型处理
<#--打印所有key值-->
<#list cityMap?keys as city>
${city}
</#list>
<br>
<#--打印所有value值-->
<#list cityMap?values as city>
${city}
</#list>
<br>
<#--根据key获取value值-->
<#list cityMap?keys as city>
${cityMap[city]}
</#list>
3、自定义变量
assign 自定义变量指令
语法:
<#assign 变量名=值>
<#assign 变量名=值 变量名=值> (定义多个变量)
- 测试代码
<#--自定义变量-->
<#assign a=10 b=10 c=20>
${a}--->${b}-->${c}
<br>
<#assign str="hello" arr=['zs','ls','ww']>
${str}-->${arr?join(",")}
<br>
<#list arr as a>
${a}
</#list>
4、条件判断分支
if, else, elseif 逻辑判断指令
格式:
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
<#else>
...
</#if>
注:
1. condition, condition2等:将被计算成布尔值的表达式。
2. elseif 和 else 指令 是可选的。
<#--条件分支判断-->
<#assign score=70>
<#if score lt 60>
成绩不及格!
<#elseif score gte 60 && score lt 70>
成绩及格!
<#elseif score gte 70 && score lt 90>
成绩良好!
<#elseif score gte 90 && score lte 100>
成绩优秀!
</#if>
<#if a??>
数据存在!
<#else>
数据不存在!
</#if>
5、集合遍历
<#--
list指令
格式1:
<#list sequence as item>
</#list>
格式2:
<#list sequence as item>
<#else>
当没有选项时,执行else指令
</#list>
<#-- 当序列没有数据项时,使用默认信息 -->
<#assign arr=[]>
<#list arr as ad>
${ad}
<#else >
这个数组是空的。
</#list>
6、Macro自定义命令 (宏命令)
当有一部分模板片段被反复使用的时候,可以利用宏变量存储模板片段,也叫自定义指令。
可以使用 macro 指令来自定义一些自定义指令。
macro 自定义指令 (宏)
1. 基本使用
格式:
<#macro 指令名>
指令内容
</#macro>
使用:
<@指令名></@指令名>
2. 有参数的自定义指令
格式:
<#macro 指令名 参数名1 参数名2>
指令内容
</#macro>
使用:
<@指令名 参数名1=参数值1 参数名2=参数值2></@指令名>
注:
1. 指令可以被多次使用。
2. 自定义指令中可以包含字符串,也可包含内置指令
定义基本的自定义指令
将模板片段放入定义的macro的标签内部,需要调用的话,就用@指令去调用即可
address为宏变量,存储模板片段,也叫自定义指令
使用的感受:就像定义方法和调用方法
作用:复用
<#--测试Macro命令-->
<#macro number a b>
两数之和为${a+b}
</#macro>
<#--使用宏命令-->
<@number 12 12></@number>
<#--无参输出-->
<#macro count>
<h1>测试无参输出效果</h1>
</#macro>
<@count></@count>
<br>
<#--打印九九乘法表-->
<#macro printNum>
<#list 1..9 as i>
<#list 1..i as j>
${j}*${i}=${i*j}
</#list>
<br/>
</#list>
</#macro>
<@printNum></@printNum>
<br/>
<#--动态参数-->
<#macro dynic num>
<#list 1..num as i>
<#list 1..i as j>
${j}*${i}=${i*j}
</#list>
<br>
</#list>
</#macro>
<@dynic 5></@dynic>
7、nested占位符
nested 指令执行自定义指令开始和结束标签中间的模板片段。嵌套的片段可以包含模板中任意合法的内容。
<#--测试Nested占位符 没有形式参数-->
<#macro company>
<h1><#nested>公司与公司开展交流合作!!</h1>
</#macro>
<@company>马士兵教育</@company>
8、import导入页面
引入外部页面,然后调用外部页面的方法。
//index5.ftl
<#--打印九九乘法-->
<#macro test>
<#list 1..9 as i >
<#list 1..i as j>
${i}*${j}=${i*j}
</#list>
<br>
</#list>
</#macro>
<#--引入外部文件-->
<#import 'index5.ftl' as index5>
<@index5.test></@index5.test>
9、include引入页面
作用:在模板中包含另一个模板(可以是html、text、jsp等外部文件>
<#--引入外部文件-->
<#include "index6.txt">
<#include "index5.ftl">
10、freeMarker页面静态化
此技术主要针对经常重复出现页面,没有必要每一次去查询,我们就需要页面静态化处理,只需要对重复的页面第一次查询用IO流的方式写入生成html静态文件,永久不再改变。实际上就是从数据库获取到数据,然后把模板ftl文件从文件流生成静态html页面。
- 在D:\bigCode\FreeMarkerDemo\src\main\resources中编写ftl模板页面(static.ftl)
<meta charset="UTF-8" content="text/html">
<#-- 新闻标题 -->
<h1>${title}</h1>
<p>
新闻来源:${source} 发布时间:${pubTime?string("yyyy-MM-dd HH:mm")}
</p>
<#-- 新闻内容 -->
<p>
${content}
</p>
- 后台生成代码
public static void main(String[] args) throws IOException, TemplateException {
//实例化Configuration 配置模板类
Configuration configuration=new Configuration();
//设置字符编码
configuration.setDefaultEncoding("UTF-8");
//获取模板页面目录
File f1=new File("D:\\bigCode\\FreeMarkerDemo\\src\\main\\resources");
//加载模板页面目录文件对象
configuration.setDirectoryForTemplateLoading(f1);
//从模板页面目录中查找模板页面,生成模板对象
Template template = configuration.getTemplate("static.ftl");
//获取数据 可以从数据库去查询
Map<String,Object> map = new HashMap<>();
map.put("title", "特别就业季:稳就业情况如何? 哪些问题待解?");
map.put("source", "人民日报");
map.put("pubTime", new Date());
map.put("content", "中共中央政治局常务委员会近日召开会议强调," +
"要有针对性地开展援企、稳岗、扩就业工作," +
"做好高校毕业生、农民工等重点群体就业工作," +
"积极帮助个体工商户纾困。疫情期间,稳就业情况如何?还有哪些问题待解?" +
"记者采访了不同群体,记录这个特别的就业季。");
//随机生成时间戳静态文件名(html文件)
String fileName=System.currentTimeMillis()+".html";
//静态文件存放路径文件对象
File file=new File("D:\\bigCode\\FreeMarkerDemo\\src\\main\\webapp",fileName);
//获取文件字符写入流
FileWriter writer=new FileWriter(file);
//把数据用字符写入流写入模板中
template.process(map,writer);
System.out.println("文件生成成功!!");
}
本文来自博客园,作者:戴莫先生Study平台,转载请注明原文链接:https://www.cnblogs.com/smallzengstudy/p/17649458.html