【后端】FreeMarker学习笔记


【后端目录贴】
FreeMarker视频教程

1. 介绍

中文官网
英文官网

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

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

在这里插入图片描述

这种方式通常被称为 MVC (模型 视图 控制器) 模式,对于动态网页来说,是一种特别流行的模式。 它帮助从开发人员(Java 程序员)中分离出网页设计师(HTML设计师)。设计师无需面对模板中的复杂逻辑, 在没有程序员来修改或重新编译代码时,也可以修改页面的样式。
而FreeMarker最初的设计,是被用来在MVC模式的Web开发框架中生成HTML页面的,它没有被绑定到 Servlet或HTML或任意Web相关的东西上。它也可以用于非Web应用环境中。

FreeMarker 不是一个Web应用框架,而适合作为Web应用框架一个组件
FreeMarker与容器无关,因为他并不直到HTTP或Servlet。FreeMarker同样可以应用于非Web应用程序环境。
FreeMarker更适合作为Model2框架(如Struts)的视图组件,你也可以再模板中使用JSP标记库。
ftl文件不能通过浏览器直接访问到,必须通过java代码进行访问,不然不能够解析里面的表达式

2.FreeMarker环境搭建(maven版本)

  • 引入pom依赖
 <!--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>
  • 使用jetty启动,配置jetty插件(版本很重要,不知道为啥其他版本启动后不能访问)
<!--配置jetty插件-->
<plugins>
            <!--配置jetty插件,默认端口8080-->
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.1.v20140609</version>
            </plugin>
        </plugins>
  • 配置web.xml
 <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>
    </servlet>
    <!--处理所有以.ftl结尾的插件;ftl是freemarker默认的文件后缀-->
    <servlet-mapping>
        <servlet-name>freemarker</servlet-name>
        <url-pattern>*.ftl</url-pattern>
    </servlet-mapping>
  • 配置jetty启动
    在这里插入图片描述

<#-- ftl注释,浏览器中无法看到 -->
<!-- html注释,浏览器中可以看到-->

在这里插入图片描述

3. 语法

freemarker的语法:

  1. html中所有的标签都适用
  2. js与css的使用,与html中语法一致

3.1 freemarker的数据类型

在这里插入图片描述

3.1.1 布尔类型

在servlet中设置布尔类型的数据

req.setAttribute("flag", true);

${flag?c}
${flag?string}
${flag?string('yes','no')}

3.1.2 日期类型

在servlet中设置时间的数据

req.setAttribute("createDate", new Date());
  1. 年月日 ?date
  2. 时分秒 ?time
  3. 年月日时分秒 ?datetime
  4. 指定格式 ?sting("自定义格式")
    y:年, M:月, d:日
    H:时, m:分, s:秒

<#–输出日期格式–>
${createDate?date}

<#–输出时间格式–>
${createDate?time}

<#–输出日期时间格式–>
${createDate?datetime}

<#–输出格式化日期–>
${createDate?string(“yyyy年MM月dd日 HH:mm:ss”)}

3.1.3 数值类型

在servlet中设置数值类型

//数值类型
    req.setAttribute("age",18);//数值型
    req.setAttribute("avg",0.545);//浮点型
  1. 转字符串
    1.1 普通字符串?c
    1.2 货币性字符串?string.currency
    1.3 百分比型字符串?string.percent
  2. 保留浮点型数值指定小数位(#表示一个小数位)?string["0.##"]

<#–直接输出数值型–>
${age}

${avg}

<#–将数值转换成字符串输出–>
${age?c}

<#–将数值转换成货币类型字符串输出–>
${age?string.currency}

<#–百分比型字符串输出–>
${age?string.percent}

<#–保留浮点型数值指定小数位(#表示一个小数位) ---->
${avg?string[“0.##”]}

3.1.4 字符串类型

在servlet中设置字符串类型数据

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

3.1.5 字符串空值情况处理

在servlet中设置空值类型

//空值类型
req.setAttribute("bb",null);

FreeMarker 的变量必须赋值,否则就会抛出异常。而对于FreeMarker来说,null不存在的变量是完全一样的,因为FreeMarker无法理解null值
FreeMarker提供两个运算符来避免控制;
! : 指定缺失变量的默认值
${value!}: 如果value值为空,则默认值是空字符串
${value!“默认值”}: 如果value值为空,则默认值是字符“默认值”
?? : 判断变量是否存在
如果变量存在, 返回true,否则返回false
${(value??)?string}

3.1.6 sequence类型

在servlet中设置系列类型

	    //序列类型(数组,list,set)
        //数组操作
        String[] stars=new String[]{"周杰伦","林俊杰","陈奕迅","五月天"};
        req.setAttribute("stars",stars);
        //List操作
        List<String> listStars = Arrays.asList("周杰伦", "林俊杰", "陈奕迅", "五月天");
        req.setAttribute("listStars",listStars);
        //JavaBean集合
        ArrayList<User> users = new ArrayList<>();
        users.add(new User(2,"lisi",22));
        users.add(new User(1,"zhangsan",22));
        users.add(new User(3,"wangwu",30));

<#list 系列名 as 元素名>
${名称}
</#list>
①获取系列的长度 ${序列名?size}
②获取系列元素的下标${元素名?index}
③获取第一个元素${序列名?first}
④获取最后一个元素${序列名?last}
倒序输出序列名?sort
⑥升序输出序列名?sort?reverse
降序输出序列名?sort_by("字段名")
⑧指定字段名排序
注:一般是javabean集合,对应的字段名需要提供get方法

3.1.7 hash类型

在servlet中设置hash类型

       //hash类型(map)
       HashMap<String, String> cityMap = new HashMap<>();
       cityMap.put("sh","上海");
       cityMap.put("bj","北京");
       cityMap.put("sz","深圳");
       req.setAttribute("cityMap",cityMap);

<#--key遍历输出-->
<#list hash?keys as key>
${key} -- ${hash[key]}
</#list>

<#--value遍历输出-->
<#list hash?values as value>
${value}
</#list>

3.2 freemarker常见指令

3.2.1 asign指令

定义多个/单个变量
<#assign name="chen" age=18 seq = ["foo", "bar", "baz"]>
<#–使用变量–>
${name}<br/>

3.2.2 if elseif else指令

<#if condition>
...
<#elseif condition2>
...
<#elseif condidion3>
...
<#else>
</#if>
注:`1.condition,condidtion2等;将被计算成布尔值的表达式
2.elseif和else指令时可选的
`
<#assign score=800>
    <#--小于等于-->
<#if score lte 60>
    小于60
    <#elseif score lt 80 && score gt 60>
    60-80中间
    <#elseif score lte 100 &&  score gte 60>
    大于等于80
    <#else>
    大于100
</#if>

3.2.3 list遍历

<#list sequence as item>
    Part repeated for each item
<#else>
    Part executed when there are 0 items
</#list>
注意:
1.else是可选的,去掉else和序列遍历无区别
2.sequence:想要迭代的项,可以是系列或结合的表达式
3.item:循环变量的名称
4.当没有迭代选项时,才使用else指令,可以输出一些特殊扥鹅绒而不是知识空再那里
<#assign   seq2 = ["foo", "bar", "baz"]>
<#list seq2 as s>
    ${s}<br/>
    <#else>
    空了
</#list>

3.2.4 macro宏定义

1.定义
<#macro 指令名>
   指令内容
</#macro>
使用:<@指令名></@指令名>
2.定义(含参数)
<#macro 指令名 参数一 参数二>
   指令内容
</#macro>
使用:<@指令名 参数一=xxx 参数二=mmm></@指令名>

注意:
1.指令可以被多次使用
2.自定义指令中可以包含字符串,也可以包含内置指令
<hr/>
<#--宏定义-->
<#macro welcom>
    hello world<br/>
</#macro>
<@welcom></@welcom>
<@welcom></@welcom>


<#macro welcome2 username>
    hello world:${username}<br/>
</#macro>
<@welcome2 username="张三"></@welcome2>

3.2.5 nested 占位指令

nested 指令执行自定义指令开始和结束标签中间的模板片段。 嵌套的片段可以包含模板中任意合法的内容:插值,指令等…它在上下文环境中被执行, 也就是宏被调用的地方,而不是宏定义体的上下文中。因此,比如, 你不能看到嵌套部分的宏的局部变量。如果你没有调用 nested 指令, 自定义指令开始和结束标记中的部分将会被忽略(自己输入的内容将被忽略)。


<#macro name param1 param2 ... paramN>
  <#nested loopvar1, loopvar2, ..., loopvarN>
</#macro>

3.2.6 import导入指令

引入一个库。也就是说,它创建一个新的空命名空间, 然后在那个命名空间中执行给定 path 参数中的模板, 所以模板用变量(宏,函数等)填充命名空间。 然后使得新创建的命名空间对哈希表的调用者可用。 这个哈希表变量将会在命名空间中,由 import (就像你可以用 assign 指令来创建一样。) 的调用者被创建成一个普通变量,名字就是 hash 参数给定的。

如果你用同一个 path 多次调用 import,它会创建命名空间, 但是只运行第一次 import 的调用。 后面的调用仅仅创建一个哈希表变量,你只是通过它来访问 同一个 命名空间。

<#import path as hash>

eg:
<#import "/libs/mylib.ftl" as my>
<@my.copyright date="1999-2002"/>

3.2.7 include包含指令

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

<#--包含指令(引入其他页面文件)-->
<#--html文件-->
<#include "../index.html">
<#--ftl文件-->
<#include "./f03.ftl">
<#--txt文件-->
<#include "./test.txt">

3.3 freemarker页面静态化

通过freemarker将数据库的数据合并到html中,再次访问,不至于再次访问数据库.

在这里插入图片描述

3.3.1 定义模板

<h1>${title}</h1>
<p>${content}</p>
   public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        //实例化模板对象
        Configuration configuration = new Configuration();
        //设置加载模板的上下文,以及加载模板的路径(模板存放路径)
        configuration.setServletContextForTemplateLoading(req.getServletContext(),"/template");
        //设置模板的编码格式
        configuration.setDefaultEncoding("UTF-8");
        //加载模板文件,获取模板对象
        Template template = configuration.getTemplate("f04.ftl");

        //设置数据类型
        HashMap<String, String> map = new HashMap<>();
        map.put("title","新闻标题");
        map.put("source","新闻来源");
        map.put("pubTime","发布时间");
        map.put("content","新闻内容");
        //获取项目的根目录
        String realPath = req.getServletContext().getRealPath("");
        //设置html的存放路径
        File htmlFile = new File(realPath + "/html");
        if (!htmlFile.exists()) {
            htmlFile.mkdir();
        }
//        String fileName = UUID.randomUUID() + ".html";
        String fileName =   "1.html";
//        FileWriter fileWriter = new Out(new File(htmlFile , fileName));
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(new File(htmlFile, fileName)), "UTF-8");
        //生成html(将数据填充到模板中)
        template.process(map,outputStreamWriter);
    }

3.4 FreeMarker运算符

3.4.1 算数运算符

${a1}+${a2}=${a1 + a2 }<br/>
${a1}-${a2}=${a1 - a2 }<br/>
${a1}*${a2}=${a1 * a2 }<br/>
${a1}/${a2}=${a1 / a2 }<br/>
${a1}%${a2}=${a1 % a2 }<br/>
<!--字符串运算-->
${"hello" + "hello2" }<br/>

3.4.2 逻辑运算符

&& || !

3.4.3 比较运算符

> (gt):大于,推荐使用gt
< (lt)
>= (gte)
<= (lt3)
== 
!=

3.4.4 空值运算符

! : 指定缺失变量的默认值
${value!}: 如果value值为空,则默认值是空字符串
${value!“默认值”}: 如果value值为空,则默认值是字符“默认值”
?? : 判断变量是否存在
如果变量存在, 返回true,否则返回false
${(value??)?string}

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值