Java EE之FreeMarker前度模板引擎的使用

五、FreeMarker

5.1 FreeMarker介绍

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GNM7dglY-1650637129688)(JavaEE.assets/FreeMarker.png)]

这种方式通常被称为 MVC (模型 视图 控制器) 模式,对于动态网页来说,是一种特别流行的模式。 它帮助从开发人员(Java 程序员)中分离出网页设计师(HTML设计师)。设计师无需面对模板中的复杂逻辑, 在没有程序员来修改或重新编译代码时,也可以修改页面的样式。

而FreeMarker最初的设计,是被用来在MVC模式的Web开发框架中生成HTML页面的,它没有被绑定到 Servlet或HTML或任意Web相关的东西上。它也可以用于非Web应用环境中。

5.2 FreeMarker的特性

5.2.1 通用目标

能够生成各种文本:HTML、XML、RTF、Java 源代码等等

易于嵌入到你的产品中:轻量级;不需要 Servlet 环境

插件式模板载入器:可以从任何源载入模板,如本地文件、数据库等等

你可以按你所需生成文本:保存到本地文件;作为 Email 发送;从 Web 应用程序发送它返回给 Web浏览器

5.2.2强大的模板语言

所有常用的指令:include、if/elseif/else、循环结构

在模板中创建和改变变量

几乎在任何地方都可以使用复杂表达式来指定值

命名的宏,可以具有位置参数和嵌套内容

名字空间有助于建立和维护可重用的宏库,或将大工程分成模块,而不必担心名字冲突

输出转换块:在嵌套模板片段生成输出时,转换HTML转义、压缩、语法高亮等等;你可以定义自己

的转换

5.2.3通用数据模型

FreeMarker不是直接反射到Java对象,Java对象通过插件式对象封装,以变量方式在模板中显示

你可以使用抽象(接口)方式表示对象(JavaBean、XML文档、SQL查询结果集等等),告诉模板开 发者使用方法,使其不受技术细节的打扰

5.2.4 为Web准备

在模板语言中内建处理典型Web相关任务(如HTML转义)的结构

能够集成到Model2 Web应用框架中作为JSP的替代

支持JSP标记库

为MVC模式设计:分离可视化设计和应用程序逻辑;分离页面设计员和程序员

5.2.5智能的国际化和本地化

字符集智能化(内部使用UNICODE)

数字格式本地化敏感

日期和时间格式本地化敏感

非US字符集可以用作标识(如变量名)

多种不同语言的相同模板

5.2.6强大的XML处理能力

<#recurse> 和 <#visit> 指令(2.3版本)用于递归遍历XML树。在模板中清楚和直接的访问XML对象

模型。开源论坛 JForum 就是使用了 FreeMarker 做为页面模板。


5.3 FreeMarker环境搭建步骤

  1. 新建一个Maven Web项目

  2. 配置坐标依赖和部署插件

    • 在项目的webapp/WEB-INF目录下的web.xml文件中,添加freemarker 相关 servlet 配置
    <!-- freemarker的坐标依赖 -->
            <dependency>
                <groupId>org.freemarker</groupId>
                <artifactId>freemarker</artifactId>
                <version>2.3.23</version>
               
            </dependency>
            <!-- servlet-api的坐标依赖 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.0.1</version>
            </dependency>
    
  3. 修改配置文件web.xml

  • 在项目的webapp/WEB-INF目录下的web.xml文件中,添加freemarker 相关 servlet 配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <!-- FreeMarkerServlet配置 -->
    <servlet>
        <servlet-name>freemarker</servlet-name>
        <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
        <init-param> <!-- 模板路径 -->
            <param-name>TemplatePath</param-name> <!-- 默认在webapp目录下查找对应的模板文件 -->
            <param-value>/</param-value>
        </init-param>
        <init-param> <!-- 模板默认的编码:UTF-8 -->
            <param-name>default_encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
<!--        2.3.4. 编写Servlet2.3.5. 新建模板文件 ftl-->
<!--        在webapp目录下新建template文件夹,创建f01.ftl文件-->
<!--        2.3.6. 启动项目-->
    </servlet> <!-- 处理所有以.ftl结尾的文件;ftl是freemarker默认的文件后缀 -->
    <servlet-mapping>
        <servlet-name>freemarker</servlet-name>
        <url-pattern>*.ftl</url-pattern>
    </servlet-mapping>
</web-app>
  1. 编写Servlet 类

    @WebServlet("/f1")
    public class FreeMarker extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //创建域对象属性
            req.setAttribute("mgr","hello");
            //跳转到页面中
            req.getRequestDispatcher("TemplatePath/freemarker01.ftl").forward(req,resp);
        }
    }
    
  2. 新建模板文件 ftl

    • 在webapp目录下新建template文件夹,创建freemarker01.ftl文件
    <#--ftl文件内容--> 
    ${mgr}
    
  3. 启动项目

  4. 访问项目

5.4 FreeMarker 的数据类型

  • 布尔型:
    • 等价于 Java 的 Boolean 类型,不同的是不能直接输出,可转换为字符串输出
  • 日期型:
    • 等价于 java 的 Date 类型,不同的是不能直接输出,需要转换成字符串再输出
  • 数值型:
    • 等价于 java 中的 int,float,double 等数值类型
  • 三种显示形式:数值型(默认)、货币型、百分比型
  • 字符型:
    • 等价于 java 中的字符串,有很多内置函数
  • sequence 类型:
    • 等价于 java 中的数组,list,set 等集合类型
  • hash 类型:
    • 等价于 java 中的 Map 类型
5.4.1 布尔类型

boolean类型的数据是不能直接输出,需要转换成字符串使用

5.4.2 日期类型

在freemarker中日期类型不能直接输出;如果输出要先转成日期型或字符串

  • 转换规则:

    1. 年月日          	?date
    2. 时分秒              ?time
    3. 年月日时分秒     ?datetime
    4. 指定格式        ?string("自定义格式")
                              y:年  M:月  d:日
                              H:时  m:分  s:秒
    
  • 示例:

    // 在servlet中设置日期类型 
    request.setAttribute("createDate",new Date());
    
    <#--.ftl文件中获取数据 -->
    	<#-- 输出日期格式 --> 
        ${createDate?date} <br> 
        <#-- 输出时间格式 --> 
        ${createDate?time} <br> 
        <#-- 输出日期时间格式 --> 
        ${createDate?datetime} <br> 
        <#-- 输出格式化日期格式 --> 
        ${createDate?string("yyyy年MM月dd日 HH:mm:ss")} <br>
    
5.4.3 数值类型

数值类型在freemarker中数值类型可以直接输出;

  • 转换规则:

    1. 转字符串
                    普通字符串       ?c
                    货币型字符串     ?string.currency
                    百分比型字符串   ?string.percent
    2. 保留浮点型数值指定小数位(#表示一个小数位)
                    ?string["0.##"]
    
  • 示例:

    // 在servlet中设置数值类型 
            req.setAttribute("age",18); // 数值型
            req.setAttribute("salary",10000); // 数值型
            req.setAttribute("avg",0.545); // 浮点型
    
    <#--.ftl文件中获取数据 -->
    	<#-- 直接输出数值型 --> 
        ${age} <br> ${salary} <br> 
        <#-- 将数值转换成字符串输出 --> 
        ${salary?c} <br> 
        <#-- 将数值转换成货币类型的字符串输出 --> 
        ${salary?string.currency} <br> 
        <#-- 将数值转换成百分比类型的字符串输出 --> 
        ${avg?string.percent} <br> 
        <#-- 将浮点型数值保留指定小数位输出 (##表示保留两位小数) --> 
        ${avg?string["0.##"]} <br>
    
5.4.4 字符串类型
  • 转换规则:

    直接输出,常用方法如下

    在freemarker中字符串类型可以直接输出; 
    	1. 截取字符串(左闭右开) ?substring(start,end) 
        2. 首字母小写输出 ?uncap_first 
        3. 首字母大写输出 ?cap_first 
        4. 字母转小写输出 ?lower_case 
        5. 字母转大写输出 ?upper_case 
        6. 获取字符串长度 ?length 
        7. 是否以指定字符开头(boolean类型) ?starts_with("xx")?string 
        8. 是否以指定字符结尾(boolean类型) ?ends_with("xx")?string 
        9. 获取指定字符的索引 ?index_of("xx") 
        10. 去除字符串前后空格 ?trim 
        11. 替换指定字符串 ?replace("xx","xx")
    
  • 示例:

// 在servlet中设置数值类型 
        request.setAttribute("msg","Hello "); 
		request.setAttribute("msg2","freemarker");
<#--.ftl文件中获取数据 -->
    
<#-- 直接输出 -->
${msg} - ${msg2} <br>

<#--1. 截取字符串(左闭右开) ?substring(start,end)-->
${msg?substring(0,2)}<br>

<#--2. 首字母小写输出  ?uncap_first-->
${msg?uncap_first}<br>

<#--3. 首字母大写输出  ?cap_first-->
${msg2?cap_first}<br>

<#--4. 字母转小写输出  ?lower_case-->
${msg?lower_case}<br>

<#--5. 字母转大写输出  ?upper_case-->
${msg2?upper_case}<br>

<#--6. 获取字符串长度  ?length-->
${msg2?length}<br>

<#--7. 是否以指定字符开头(boolean类型) ?starts_with("xx")?string-->
${msg?starts_with("H")?c}<br>

<#--8. 是否以指定字符结尾(boolean类型) ?ends_with("xx")?string-->
${msg2?ends_with("e")?c}<br>

<#--9. 获取指定字符的索引  ?index_of("xx")-->
${msg2?index_of("r")}<br>

<#--10. 去除字符串前后空格 ?trim-->
${msg2?trim}<br>

<#--11. 替换指定字符串  ?replace("xx","xx")-->
${msg2?replace("ker","abc")}<br>
    
5.4.5 sequence类型

在Servlet中设置序列类型(数组、List、Set)的数据

  • List格式:

      <#list 序列名 as 元素名> 
    
      ${名称} 
    
      </#list>
    
  • 序列类型常用方法

    获取序列的长度        ${序列名?size}
    获取序列元素的下标     ${元素名?index}
    获取第一个元素        ${序列名?first}
    获取最后一个元素      ${序列名?last}
    倒序输出    	 序列名?reverse
    升序输出    	 序列名?sort
    降序输出    	 序列名?sort?reverse
    指定字段名排序    序列名?sort_by("字段名")
    
  • 示例:

    // 在servlet中设置数值类型 
        // 数组操作 
    	String[] stars = new String[]{"周杰伦","林俊杰","陈奕迅","五月天"}; 					request.setAttribute("stars",stars); 
    	// List操作 
    	List<String> citys = Arrays.asList("上海","北京","杭州","深圳");
    	request.setAttribute("cityList",citys); 
    	// JavaBean集合 
    	List<User> userList = new ArrayList<>(); 
    	userList.add(new User(1,"zhangsan",22)); 
    	userList.add(new User(2,"lisi",18)); 
    	userList.add(new User(3,"wangwu",20)); 
    	request.setAttribute("userList",userList);
    
    <#-- 数组操作 --> 
        <#list stars as star> 
        下标:${star?index} -- 名字:${star} <br> 
        </#list> 
        数组的长度:${stars?size} <br> 
        <#-- 获取第一个元素 --> 
        第一个元素:${stars?first} <br> 
        <#-- 获取最后一个元素 --> 
        最后一个元素:${stars?last} <br> 
        <hr> 
    <#-- List操作 --> 
        <#list cityList as city > ${city} <br> 
        </#list> 
        List的size:${cityList?size} <br> 
    <#-- 倒序输出 --> 
        <#list cityList?reverse as city > 
        ${city} - </#list> <br> 
    <#-- 升序输出 -->
        <#list cityList?sort as city > 
        ${city} - 
        </#list> <br> 
    <#-- 降序输出 --> 
        <#list cityList?sort?reverse as city >
    
    
5.4.6 hash 类型
  • 格式:

    key遍历输出 
    	<#list hash?keys as key> 
    		${key} -- ${hash[key]} 
    	</#list> 
    	
    value遍历输出 
    	<#list hash?values as value> 
    		${value} 
    	</#list>
    
  • 示例:

    // Map操作 
    Map<String,String> cityMap = new HashMap<>(); 
    cityMap.put("sh","上海"); 
    cityMap.put("bj","北京"); 
    cityMap.put("sz","深圳"); 
    request.setAttribute("cityMap",cityMap);
    
    <#-- key遍历输出 --> 
        <#list cityMap?keys as key> 
        ${key} -- ${cityMap[key]} <br> 
        </#list> 
    <#-- value遍历输出 --> 
        <#list cityMap?values as value> 
        ${value}
        </#list>
    

5.5 FreeMarker 常用指令

5.5.1自定义变量指令

使用 assign 指令你可以创建一个新的变量, 或者替换一个已经存在的变量。

  • 语法:

    • <#assign 变量名=值>

    • <#assign 变量名=值 变量名=值> (定义多个变量)

  • 示例

    <#-- 直接在.ftl文件中定义后直接运行输出-->
    <#assign str="hello"> 
    ${str} <br> 
    <#assign num=1 names=["zhangsan","lisi","wangwu"] > 
    ${num} -- ${names?join(",")}
    
5.5.2 if elseif else 逻辑判断指令

可以使用 if , elseif 和 else 指令来条件判断是否满足某些条件。

  • 格式:

    <#if condition>
       ...
      <#elseif condition2>
       ...
      <#else>
       ...
    </#if>
    
    • 注意
      1. condition, condition2等:将被计算成布尔值的表达式。
      2. elseif 和 else 指令 是可选的。
      3. elseif中的比较运算符 > 改成 gt <改成 lt
  • 示例:

    <#assign score =99>
    <#if score<60  >
        不及格
        <#elseif score gt 60 && score lt 80 >
        及格
        <#else>
        优秀
    </#if>
    
5.5.3 list遍历指令
  • 格式1:

    <#list sequence as item>

    </#list>

  • 格式2:

    <#list sequence as item>

    <#else>

    ​ 当没有选项时,执行else指令

    </#list>

  • 注意:

    1. else 部分是可选的
    2. sequence: 想要迭代的项,可以是序列或集合的表达式
    3. item: 循环变量 的名称
    4. 当没有迭代项时,才使用 else 指令, 可以输出一些特殊的内容而不只是空在那里
  • 示例:

    <#assign users = ["张三","李四","王五"]> 
    <#-- 遍历序列 --> 
    <#list users as user> 
        ${user} 
    </#list>
    
5.5.4 macro 自定义指令 宏

自定义指令需要先定义,再使用(用@来使用)

  1. 基本使用定义:
  • 定义格式:

    <#macro 指令名>

    指令内容

    </#macro>

  • 使用:

    <@指令名>< /@指令名>

  1. 带有参数的自定义指令
  • 格式:

    <#macro 指令名 参数名1 参数名2>

    指令内容

    </#macro>

  • 使用:

    <@指令名 参数名1=参数值1 参数名2=参数值2>< /@指令名 >

  1. 注意:

    1. 指令可以被多次使用。

    2. 自定义指令中可以包含字符串,也可包含内置指令

  • 示例:

    <#--宏  自定义指令-->
    <#macro test>
        <h4>test指令</h4>
    </#macro>
    
    <#--宏  自定义指令 一个参数的宏定义方法-->
    <#macro printCFB num>
        <#list 1..num as i>
            <#list 1..i as j>
                ${j} * ${i} = ${i*j}
            </#list>
            <br>
        </#list>
    </#macro>
    
    <#--宏  自定义指令 多参数-->
    <#macro pr num1 num2>
        ${num1}--${num2}
    </#macro>
    
    <#--宏  自定义指令的使用-->
    <@test></@test>
    
    <@printCFB 5></@printCFB>
    
    <@pr num1=1 num2=3></@pr>
    
5.5.5 nested占位指令

nested 相当于占位符,一般结合macro指令一起使用。

可以将自定义指令中的内容通过nested指令占位,当使用自定义指令时,会将占位内容显示。

<#macro test> 
	这是一段文本! 
	<#nested> 
	<#nested> 
</#macro>

<#--使用test宏-->
<@test>
	<h4>这是文本后面的内容!</h4>
</@test>
5.5.6 import导入指令

import 指令可以引入一个库。也就是说,它创建一个新的命名空间, 然后在那个命名空间中执行给定路径的模板。可以使用引入的空间中的指令。

在其他ftl页面中通过import导入你想要页面的.ftl的模板,然后就可以使用该命名空间中的指令

  • 示例:

    <#--import导入-->
    <#import "freemarker03.ftl" as zl>
    <@zl.printCFB 3></@zl.printCFB>
    

    通过导入freemarker03.ftl的路径,就可以使用该路径下的模板内容以及自定义的宏的方法

5.5.7 include包含标签

可以使用 include 指令在你的模板中插入另外一个 FreeMarker 模板文件 。 被包含模板的输出格式是在 include 标签出现的位置插入的。 被包含的文件和包含它的模板共享变量,就像是被复制粘贴进去的一样。

  • 示例:

    <#--包含指令(引入其他页面文件) include--> 
        <#--html文件--> 
        <#include "test.html"> 
        <#--freemarker文件--> 
        <#include "test.ftl"> 
        <#--text文件--> 
        <#include "test.txt">
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值