Java-Freemarker

x33g5p2x  于2022-04-12 转载在 Java  
字(11.7k)|赞(0)|评价(0)|浏览(309)

Freemarker

介绍

FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker与 Web 容器无关,即在 Web 运行时,它并不知道 Servlet 或 HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成 XML,JSP 或 Java 等。

Freemarker入门

1.创建maven工程并导入Freemarker的maven坐标

<dependency>
        <groupId>org.FreeMarker</groupId>
        <artifactId>FreeMarker</artifactId>
        <version>2.3.28</version>
    </dependency>

2.创建模板文件

在D盘根目录创建模板文件夹名称ftl 然后在此文件夹下创建模板文件

模板文件中有四种元素:
1、文本,直接输出的部分

2、注释,即<#–…–>格式不会输出

3、插值(Interpolation):即${…}部分,将使用数据模型中的部分替代输出

4、FTL指令:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出

Freemarker的模板文件后缀可以任意,一般建议为ftl

列:

test.ftl

<html>
<head>
<meta charset="utf-8">
<title>Freemarker入门</title>
</head>
<body>
<#--我只是一个注释,我不会有任何输出 -->
${name}你好,${message}
</body>
</html>

3.生成文件

使用步骤:
第一步:创建一个 Configuration 对象,直接 new 一个对象。构造方法的参数就是 freemarker的版本号。
第二步:设置模板文件所在的路径。
第三步:设置模板文件使用的字符集。一般就是 utf-8。
第四步:加载一个模板,创建一个模板对象。
第五步:创建一个模板使用的数据集,可以是 pojo 也可以是 map。一般是 Map。
第六步:创建一个 Writer 对象,一般创建 FileWriter 对象,指定生成的文件名。
第七步:调用模板对象的 process 方法输出文件。
第八步:关闭流。

public static void main(String[] args) throws Exception {
        //1.创建配置类
        Configuration configuration=new Configuration(Configuration.getVersion());
//2.设置模板所在的目录
        configuration.setDirectoryForTemplateLoading(new File("D:\\ftl"));
//3.设置字符集
        configuration.setDefaultEncoding("utf-8");
//4.加载模板
        Template template = configuration.getTemplate("hello.ftl");
//5.创建数据模型
        Map map=new HashMap();
        map.put("name", "张三");
        map.put("message", "欢迎来使用Freemarker!");
//6.创建Writer对象
        Writer out =new FileWriter(new File("D:\\ftl\\hello.html"));
//7.输出
        template.process(map, out);
//8.关闭Writer对象
        out.close();

    }

然后运行你就会发现多出来一个hello.html文件 你点击就可以运行

访问值和对象的方式

使用${} 和在jsp中使用EL一样 注意实体类必须有get set方法

值得注意的是,${…}只能用于文本部分,不能用于表达式,

下面的代码是错误的: <#if ${isBig} >Wow!</#if>

应该写成:<#if isBig >Wow!</#if>

也就是说在表达式中不需要${} 而是直接就能获取到

直接访问值: ${name}

从哈希表(map)中检索数据: ${user.name} , ${user[“name”]}

从序列(array list set)中检索数据: ${list[5]} 而不是 ${list.get(1) }这样会报错的

注意:

如果是 数组或者list set 这些 那么我们只想获取元素中第几个内容我们可以使用array[1]的方式

下面我们就演示访问对象的方式

在java代码中为student赋值

Map map=new HashMap();
        map.put("student", new Student("张三丰", "男", "26"));

模板

姓名: ${student.name}  年龄: ${student.age} 性别${student.sex} <br/>

assign指令

assign指令用于在页面上定义一个变量 语法: <#assign xx >

(1)定义简单类型 可以是数字和字符串

<#assign linkman="周先生">
联系人:${linkman}

(2)定义对象类型

<#assign info={"mobile":"13812345678",'address':'北京市昌平区'} >
电话:${info.mobile} 地址:${info.address}

然后我们将上面的代码添加到我们模板里

<html>
<head>
    <meta charset="utf-8">
    <title>Freemarker入门</title>
</head>
<body>
<#--我只是一个注释,我不会有任何输出 -->
${name}你好,${message}
<br/>
<#--  assign 定义简单类型 -->
<#assign linkman="周先生">
联系人:${linkman}
<br/>
<#--  assign 定义对象类型 -->
<#assign info={"mobile":"13812345678",'address':'北京市昌平区'} >
电话:${info.mobile} 地址:${info.address}

</body>
</html>

然后从新生成文件 看看效果

修改的话也是一样 的直接进行覆盖就行 和在java中变量的用法一样

include指令

include指令用于模板文件的嵌套 语法:<#include “url”/>

列:

我们在创建一个模板head.ftl 和hello.ftl放在同一个目录下

head.ftl内容:

<html>
<head>
    <meta charset="utf-8">
    <title>Freemarker入门</title>
</head>
<body>

我是head.ftl

<br/>
${name}你好,${message}
<br/>

联系人:${linkman}
<br/>

电话:${info.mobile} 地址:${info.address}

</body>
</html>

hello.ftl内容:

<html>
<head>
    <meta charset="utf-8">
    <title>Freemarker入门</title>
</head>
<body>
<#--我只是一个注释,我不会有任何输出 -->
${name}你好,${message}
<br/>
<#--  assign 定义简单类型 -->
<#assign linkman="周先生">
联系人:${linkman}
<br/>
<#--  assign 定义对象类型 -->
<#assign info={"mobile":"13812345678",'address':'北京市昌平区'} >
电话:${info.mobile} 地址:${info.address}
<br/>

<#--  include指令 -->
<#include "head.ftl"/>

</body>
</html>

java代码和入门案例中代码一样

然后从新生成文件 看看效果

注意无论你嵌套多少个include指令 他们的变量是共享的 但是是有原则的

全局变量: include嵌套文件无论在任何位置都能获取到 ,全局变量就是在后台使用map生成的变量然后在模板文件中使用${}进行获取的

局部变量:就是 assign 指令变量include嵌套文件只会获取到他前面的 assign 指令变量内容,后面的就不会获取到 会在生成文件时候报错

if指令

语法:

<#if  var ??> 
不是空
<#else> 
为空 
</#if>
<#if condition>
    ...

<#elseif condition2>
    ...

<#elseif condition3>
    ...

<#else>
    ...

</#if>

(1)在模板文件中使用if指令进行判断

<#if success=true>
你已通过实名认证
<#else>
你未通过实名认证
</#if>

(2)在java代码中为success变量赋值

map.put("success", true);

然后从新生成文件 看看效果

list指令

list指令用于遍历

list语法:

<#list nameList as names>    
  ${names}   
</#list>

map方式语法:

<#list map?keys as k>
     <option value="${k}">${map[k]}</option>
</#list>

可以是map list 类

自定义循环次数

循环1到100

<#list 1..100 as t>
${t}
</#list>

或者

<#list 1..max as i>    
  <li><a href="#">${i}</a></li>
</#list>

从1开始,每次迭代1,到max结束。如果max是5,则会输出1、2、3、4、5

获取或者设置list相关信息

获取list的size长度 ${goodsList?size}

模板:

<#list goodsList as goods>
    
        <!-- _index获取每次遍历的下标 -->
  	   ${goods_index}  <br/>
        
            <!-- 遍历list的值 -->
        ${goods}    <br/>
    
      <!--  _has_next是否是最后一个元素  如果是 执行if里的内容 -->
     <#if !goods_has_next>
        ${goods}
    </#if>
		
</#list>

list循环过程中,如果您想跳出循环即<#break>来完成, 如果你想返回循环使用 <#continue>

列:

遍历map的方式

这种方式常用于下拉列表

后端

Map map=new HashMap();

        Map map_name=new HashMap();
        map_name.put("name","a1");
        map_name.put("name1","a2");
        map_name.put("name2","a3");

        map.put("typeMap",map_name);

模板

<#list typeMap?keys as k>
     <option value="${k}">${typeMap[k]}</option>
</#list>

key 就是 k

value就是 typeMap[k]

还可以这样

模板

<#list typeMap?values as v>
${v}<br/>
</#list>

返回全部的vuale

遍历数组的方式

在java代码中为goodsList赋值

Map map=new HashMap();
        List goodsList=new ArrayList();
        goodsList.add(1);
        goodsList.add(2);
        goodsList.add(3);
        goodsList.add(4);
        map.put("goodsList", goodsList);

模板

<#list goodsList as goods>
序号: ${goods} 
</#list>

遍历list集合的方式

list map的方式 在java代码中为goodsList赋值

Map map=new HashMap();
        List goodsList=new ArrayList();
        Map goods1=new HashMap();
        goods1.put("name", "苹果");
        goods1.put("price", 5.8);
        Map goods2=new HashMap();
        goods2.put("name", "香蕉");
        goods2.put("price", 2.5);
        Map goods3=new HashMap();
        goods3.put("name", "橘子");
        goods3.put("price", 3.2);
        goodsList.add(goods1);
        goodsList.add(goods2);
        goodsList.add(goods3);
        map.put("goodsList", goodsList);

模板

<#list goodsList as goods>
商品名称: ${goods.name} 价格:${goods.price}<br>
</#list>

遍历list bean的方式

在java代码中为goodsList赋值

Map map=new HashMap();

        List < Student > goodsList = Arrays.asList(
                new Student("张三丰", "男", "26"),
                new Student("李雪", "女", "20"),
                new Student("刘刘", "男", "22"),
                new Student("吴明", "女", "21"));

        map.put("goodsList", goodsList);

模板

<#list goodsList as goods>
姓名: ${goods.name}  年龄: ${goods.age} 性别${goods.sex} <br/>  
</#list>

list的嵌套

一般用于判断一个容器里的值是否在另一个容器也存在

后端

Map map=new HashMap();
        List goodsList1=new ArrayList();
        goodsList1.add("胡");
        goodsList1.add("安");
        goodsList1.add("名");
        List goodsList2=new ArrayList();
        goodsList2.add("想");
        goodsList2.add("胡");
        goodsList2.add("阳");

        map.put("goodsList1", goodsList1);

        map.put("goodsList2", goodsList2);

模板内容

<#--创建多重循环跳出标记-->
<#assign break=false>

<#list goodsList1 as list1>
   <#list goodsList2 as list2>
  <#--使用标记跳出循环-->
	   <#if break==true>
	   <#break>
	   </#if>
	   
           <#if list1==list2> 
		   <#--打印内容-->
                  ${list2} 	
				  
			<#--改变标记状态-->
			<#assign break=true>
			
			<#--跳出当前循环-->
			 <#break>
         </#if>

   </#list>

</#list>

跳出多重循环 使用if 加 <#break>进行跳出

然后配合<#assign break=true> 进行全部跳出

格式化日期

语法:

默认格式

  1. date
    ${cur_time?date} 2021-3-1 2
  2. datetime
    ${cur_time?datetime} 2021-3-1 1:05:54 3
  3. time
    ${cur_time?time} 1:05:54

自定义格式
${cur_time?string(“yyyy-MM-dd HH:mm:ss”)} 2021-03-01 01:07:35

列:

java代码

Map map=new HashMap();
        map.put("cur_time", new Date());

模板

默认格式 <br/>
1:date 
${cur_time?date}  <br/>
2:datetime 
${cur_time?datetime}  <br/>
3:time 
${cur_time?time}  <br/>
自定义格式 <br/>
${cur_time?string("yyyy-MM-dd HH:mm:ss")}

必须null和空字符串处理

在Freemarker中如果不处理null 那么就会报错,然后不会显示报错后面的信息

建议在后端就把空值给处理好,或者传空字符串

解决办法

  1. null 变 空串
    ${val!} 什么都不显示
  2. 为Null时给默认值
    ${val!“我是默认值”}
  3. 使用if判断 (字符串)
    <#if val??!=false && val?length gt 0>
    不是空
    <#else>
    为空
    </#if>

同时判断是否是null和空字符串

  1. 判断不是空 (对象)
<#if  var ??> 
不是空
<#else> 
为空 
</#if>

运算符

算数运算符

FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , %

列:

${10-1}<br>
${10+1}<br>
${10/2}<br>
${10*2}

逻辑运算符

逻辑运算符有如下几个:
逻辑与:&&
逻辑或:||
逻辑非:!
逻辑运算符只能作用于布尔值,否则将产生错误

简单演示:

<#if true && true>
正确
<#else> 
错误
</#if>
    
<#if !true && true>
正确
<#else> 
错误
</#if>  
    
<#if (!true && true)||true>
正确
<#else> 
错误
</#if>

比较运算符

可以比较日期和数字

表达式中支持的比较运算符有如下几个:

1 =或者==:判断两个值是否相等.
2 !=:判断两个值是否不等.
3 >或者gt:判断左边值是否大于右边值
4 >=或者gte:判断左边值是否大于等于右边值
5 <或者lt:判断左边值是否小于右边值
6 <=或者lte:判断左边值是否小于等于右边值

如果不使用()括起来的话那么 就不要使用 < > <= >= 这些运算符而是使用英文的方式

否则会当成html的< >标签符号处理了

使用方式:

<#if (1>2)>
正确
<#else> 
错误
</#if>

三元表达式

${true ? '0': '1'}

比较字符串的方式:

必须用""括起来表示是字符串

可以使用 == 和 != 这两个运算符

<#if val=="我">
正确
<#else> 
错误
</#if>

字符串处理

  1. 字符串拼接 使用+就行
    ${“你”+“好”} 结果:你好
  2. 获取字符串的长度 从1开始
    ${“abc”?length} 结果:3
  3. 取第一次出现的索引 从0开始 没有就是 -1
    ${“abecdefg”?index_of(‘e’)} 结果:2
  4. 取最后一次出现的索引 从0开始 没有就是 -1
    ${“abecdefg”?last_index_of(‘e’)} 结果:5
  5. 字符串截取

从开头截取到指定位置 从0开始 包括开头 不包括结尾
${“abecdefg”?substring(0,2)} 结果: ab

从指定位置截取到结尾 从0开始 不包开头 包括结尾

${ “abecdefg”?substring( 2,“abecdefg”?length ) } 结果: ecdefg

其他截取方式请参照上代码就行

  1. 字符串替换
    ${“abcoaa”?replace(‘o’,‘dddd’)} 结果: abcddddaa
  2. 字符串分割
    ${ (“a_b_c_d_e”?split(“_”))[0]}

<#list (“a_b_c_d_e”?split(“_”) ) as item>

${item} <br/>

</#list>

  1. 去掉前后的空格
    去掉前的: ${" abc "?length} 结果:5

去掉后的: ${" abc "?trim?length} 结果:3

  1. 判断字符串是否包含指定的字符
    ${“abcdef”?contains(‘cd’)?c} 结果: true

${“abcdef”?contains(‘aac’)?c} 结果: false

注意?c必须有 否则报错

  1. 判断是否以指定的字符串开头
    ${“abcde”?starts_with(“abc”)?c} 结果: true
  2. 判断是否以指定的字符串结尾
    ${“abcde”?ends_with(“de”)?c} 结果: true
  3. 将字符串全部转换为大写
    ${“abcde”?upper_case} 结果: ABCDE
  4. 将字符串全部转换为小写
    ${“ABcDE”?lower_case} 结果: abcde
  5. 将字符串中的第一个单词的首字母变为大写
    ${“axc”?cap_first} 结果: Axc
  6. 将字符串中的所有单词的首字母变为大写
    ${“has to be done on schedule and”?capitalize}

结果: Has To Be Done On Schedule And

  1. 将字符串转换为数字
    ${“111.11”?number+11} 结果: 122.11
  2. 将数字转换为字符串
    ${123?c} 结果: 123
  3. 将布尔转换为字符串
    true?string (“yes”,”no”)

如果布尔值是true,那么返回“yes”,否则返回no

结果: yes

  1. Freemarker 中预订义了三种数字格式
number,currency(货币)和percent(百分比)其中number为默认的数字格式转换 

> <#assign tempNum=20> 
> ${tempNum}  
>
> \<br/>
> ${tempNum? string .number}    还可以这样写  ${tempNum? string ("number")}  \<br/>
> ${tempNum? string .currency}  还可以这样写  ${tempNum? string ("currency")}  \<br/>
> ${tempNum? string . percent}  还可以这样写  ${tempNum? string ("percent")}

结果:

20

¥20.00

2,000%

常用内置函数

序列Sequence (也就是 数组 list set)

  1. sequence?first 返回sequence的第一个值。
  2. sequence?last 返回sequence的最后一个值。
  3. sequence?reverse 将sequence的现有顺序反转,即倒序排序
  4. sequence?size 返回sequence的大小
  5. sequence?sort 将sequence中的对象转化为字符串后顺序排序
  6. sequence?sort_by(value) 按sequence中对象的属性value进行排序

注意:Sequence不能为null

Hash的内置函数

  1. hash?keys 返回hash里的所有key,返回结果为sequence
  2. hash?values 返回hash里的所有value,返回结果为sequence

html字符串转freemarker

Configuration cfg = new Configuration();
        StringTemplateLoader stringLoader = new StringTemplateLoader();
        String templateContent="欢迎:${name}";
        stringLoader.putTemplate("myTemplate",templateContent);
        
        cfg.setTemplateLoader(stringLoader);
        
        try {
            Template template = cfg.getTemplate("myTemplate","utf-8");
            Map root = new HashMap();  
            root.put("name", "javaboy2012");
            
            StringWriter writer = new StringWriter();  
            try {
                template.process(root, writer);
                System.out.println(writer.toString());  
            } catch (TemplateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }  
      
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

点赞 -收藏-关注-便于以后复习和收到最新内容有其他问题在评论区讨论-或者私信我-收到会在第一时间回复如有侵权,请私信联系我感谢,配合,希望我的努力对你有帮助^_^

相关文章