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环境下依然可以(例:页面静态化例子)。

image-20230822100147983

1、快速搭建

  • 创建Maven Web工程
  1. 导入依赖
 <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>
  1. 配置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>
  1. 创建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}&nbsp;
        </#list>
        <br/>
    </#list>
</#macro>
<@printNum></@printNum>
    <br/>
<#--动态参数-->
<#macro dynic num>
    <#list 1..num as i>
        <#list 1..i as j>
            ${j}*${i}=${i*j}&nbsp;
            </#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}  &nbsp;
            </#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} &nbsp; 发布时间:${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("文件生成成功!!");

    }
posted @ 2023-08-22 19:06  戴莫先生Study平台  阅读(402)  评论(0编辑  收藏  举报