Freemarker入门

1,356 阅读6分钟

写在前面的话

从2016年开始工作到现在, 从来没有整理汇总过自己所学。 所以趁着现在在做新项目,打算把自己所接触到的技术点通过文档的形式记录下来。 一方面是巩固下之前所学,加深印象。另一方面也是为了形成自己的知识库, 方便以后查看。

那么就先从Freemarker开始

什么是Freemarker

Freemarker是一款模板生成引擎, 是一种基于模板生成静态文件的通用技术。比如生成静态html文件, 代码生成器中生成通用Java文件等等。现在也用来替代jsp进行数据展示

Freemarker是采用Java语言编写的

Freemarker 使用步骤

  1. 首先需要定义模板页面 freemarker文件后缀为.ftl
  2. 后台读取模板页面,已键值对的形式给Freemarker传递数据替换模板中的取值表达式
  3. 根据配置的路径生成静态文件

实例代码: 生成一个java文件

环境: maven生成的java项目

<!--依赖-->
<dependency>
  <groupId>org.freemarker</groupId>
  <artifactId>freemarker</artifactId>
  <version>2.3.23</version>
</dependency>
  1. FreemarkerUtil 包含对Freemarker的配置和生成文件的工具

public class FreemarkerUtil {

    /**
     * 获取Freemarker的Template
     *
     * @param fileName 模板名称
     * @return
     * @throws IOException
     */
    public Template getTemplate(String fileName) throws IOException {
        Configuration cfg = new Configuration();

        // 定义模版的位置
        //从指定文件夹中获取
        //cfg.setDirectoryForTemplateLoading(new File(""));
        //从类路径中
        cfg.setClassForTemplateLoading(getClass(), "/templates");
        // 设置对象包装器
        cfg.setObjectWrapper(new DefaultObjectWrapper());
        // 设置异常处理器
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);

        return cfg.getTemplate(fileName);
    }

    /**
     * 输出文件
     * @param fileName  模板名称
     * @param map       数据
     * @param path      生成后的文件路径
     */
    public void out(String fileName, Map<String, Object> map, String path) {
        PrintWriter printWriter = null;

        try {
            Template template = getTemplate(fileName);
            
            printWriter = new PrintWriter(new FileWriter(path));

            //生成文件
            template.process(map, printWriter);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        } finally {
            if (printWriter != null) {
                printWriter.close();
            }
        }
    }
}
  1. 在resources中新建templates文件夹, 在其中配置App.ftl模板文件
<#-- 我是freemarker中的注释 -->
<#-- 生成文件 -->
public class App {
    public static void main(String[] args) {
        System.out.println("${name}");
    }
}

很简单的java输出文件

  1. Junit进行测试
public class App {

    FreemarkerUtil mFreemarkerUtil;

    @Before
    public void before() {
        mFreemarkerUtil = new FreemarkerUtil(); //初始化
    }

    @Test
    public void outFile() {
      //传递数据
      Map<String, Object> map = new HashMap<String, Object>() {{
        put("name", "hello world");
      }};

      //在D盘下生成App.java文件
      mFreemarkerUtil.out("App.ftl", map, "D:\\tmp\\App.java");
    }

}
  1. 展示:完美生成可执行的java文件。 就这样简单的小例子,先熟悉下Freemarker的用法

展示效果

Freemarker是通过键值对的方式传递数据, 所以在ftl中间中要展示后台传递的数据 只需要${key}的形式即可 类似于jsp的EL表达式

常用指令

list指令

对传递过来的集合数据进行迭代

语法

//普通数据
<#list lists as item> //lists:集合数据  item:循环变量 item_index: 循环索引
  ${item}
</#list>

//循环map
<#list maps?keys as key>
  ${maps[key]}
</#list>

//循环集合中的对象
<#list lists as item>
  ${item.字段}
</#list>

//其他属性
${lists?size}   //获取集合的长度

if else 指令

主要是做if判断用的,要注意的是条件等式必须用括号括起来。

语法

<#if 条件>
  //一个判断
<#elseif 条件>
  //另外一种判断
<#else>
  //除以上之外的其他判断
</#if>

注意点:

  1. elseif 和 else 必须包含在 if 中
  2. if 中不是必须出现elseif 和else 也可以单独if 判断,然后结束

小实例:结合list指令和if else指令 展示列表 并隔行换色

template1.ftl文件 (节省篇幅 只贴出有用代码)

<head>
  <style>
      li { background: #FFF; color: #000; }
      li.active { background: #F00; color: antiquewhite; }
      li.primary { background: #FF0; color: aqua; }
  </style>
</head>
<body>
<ul>
  <#-- 我是freemarker中的注释 -->
  <#--循环-->
  <#list list as l>           
  <#if (l_index + 1) % 2 == 0>      <#--判断 循环索引于2的余数是否为0-->
  <li class="active">
  <#elseif (l_index + 1) % 3 == 0>  <#--判断 循环索引于3的余数是否为0-->
  <li class="primary">
  <#else>
  <li>
  </#if>
    ${l}- ${l_index + 1}
  </li>
  </#list>
</ul>
</body>
</html>

java代码

@Test
public void template1() {
    List<String> list = new ArrayList<String>();
    for (int i = 'A'; i <= 'z'; i++) {
        list.add((char) i + "");
    }

    mRoot.put("list", list);

    //对应上的例子的FreemarkerUtil
    mFreemarkerUtil.out("template1.ftl", mRoot, "D:\\tmp\\template1.html");
}

展示效果

HTML展示效果

可以看到在html生成成功, 打开按照if 判断的形式循环展示 (-_- 完美)

include 指令

该指令表示导入其他的文件或者freemarker文件, 一般用于导入公共文件, 如网站的头部, 公共资源文件,版权信息等

语法

//这里的path代表文件的路径
<#include path>

import 指令

该指令类似于include, 不同的是import导入进来后, 可以在该文件中使用被导入文件的宏组件

语法

// path 文件路径  p 别名

<#import path as p>

小实例: include 和 import 展示其区别

include和import区别展示效果

setting 指令

该指令用于动态设置freeMarker的运行环境。

语法

<#setting name=value>

name的取值范围包括:

  1. locale: 指定该模板所用的国家/语言选项
  2. number_format: 定格式化输出数字的格式
  3. boolean_format: 指定两个布尔值的语法格式,默认值是true,false
  4. date_format, time_format, datetime_format: 指定显示的时间格式
  5. time_zone:设置格式化输出日期时所使用的时区

插值

插值就是${...}或#{...}格式的部分,将使用数据模型中的部分替代输出

字符串插值

${name} //直接输出

数字值

通过setting配置数字显示格式

<#setting number_format="0.##">
${150}  -->>>   150.00  
${150.568}  -->>>   150.57  //四舍五入的形式

通过string指令

${150?string("0.##")}  -->>>   150.00  //同样的展示效果

日期展示, 同样可以使用两种形式来配置, 这里只展示通过string指令来展示的效果

${.now?string("yyyy-MM-dd HH:mm:ss")}  ->>  2019-07-16 15:57:40 //展示当前时间 

字符串为空或者为null判断

${prices!"111"} //如果prices没有定义或者为null 那么就显示111 否则就显示prices的值

关于更多的的指令的描述和学习, 可以 点击这里查看中文在线手册

SpringMVC + Freemarker整合使用

前面说到Freemarker不只是模板引擎, 还可以替代jsp当做界面展示效果, 那么我们来看下和SpringMVC的整合

maven 配置 Freemarker的jar包

<dependency>
  <groupId>org.freemarker</groupId>
  <artifactId>freemarker</artifactId>
  <version>2.3.23</version>
</dependency>
<!-- ui.freemarker -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>4.3.18.RELEASE</version>
</dependency>

spring-mvc.xml

<!--视图解析器-->
<!--配置试图解析器  -->
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
  <property name="order" value="1"></property>
  <property name="suffix" value=".ftl"></property>
  <property name="contentType" value="text/html;charset=utf-8"></property>
  <property name="viewClass">
    <value>org.springframework.web.servlet.view.freemarker.FreeMarkerView</value>
  </property>
  <property name="requestContextAttribute" value="request"></property>
</bean>
<!--加载freemarker属性  -->
<bean id="propertySetting" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <property name="locations">
    <list>
      <value>classpath:freemarker.properties</value>
    </list>
  </property>
</bean>
<!--freemarker配置  -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath">
    <value>/WEB-INF/ftl/</value>
  </property>
  <property name="freemarkerSettings" ref="propertySetting"></property>
</bean>

freemarker.properties

#设置标签类型:square_bracket:[]     auto_detect:[]<>
tag_syntax=auto_detect
#模版缓存时间,单位:秒
template_update_delay=0
default_encoding=UTF-8
output_encoding=UTF-8
locale=zh_CN
#设置数字格式 ,防止出现 000.00
number_format=\#
#变量为空时,不会报错
classic_compatible=true
date_format=yyyy-MM-dd 
time_format=HH\:mm\:ss 
datetime_format=yyyy-MM-dd HH\:mm\:ss

controller中使用

@RequestMapping("/center")
public String center(HttpServletRequest request, ModelMap map) {

    map.put("name", "Hello World");

    //完整路径: /WEB-INF/ftl/index.ftl
    return "/index";
}

到此 关于SpringMVC + Freemarker整合就已经完成。

该内容只是讲解关于Freemarker简单的内容, 更多相关内容参考

  1. Freemarker官方文档
  2. Freemarker中文在线手册

预告

通过本章节Freemarker算是简单入门, 那么下一节通过实战来加深对Freemarker的印象

实战演练, Freemarker + MyBatis 配合开发我们的代码生成器