• FreeMarker 快速入门学习


    一、简介

    FreeMarker 是一个很值得去学习的模版引擎。它是基于模板文件生成其他文本的通用工具。本章内容通过如何使用FreeMarker生成Html web 页面 和 代码自动生成工具来快速了解FreeMarker。

    FreeMarker 是一款用java语言编写的模版引擎,它虽然不是web应用框架,但它很合适作为web应用框架的一个组件。

    特点:

    • 轻量级模版引擎,不需要Servlet环境就可以很轻松的嵌入到应用程序中
    • 能生成各种文本,如html,xml,java等
    • 入门简单,它是用java编写的,很多语法和java相似

    二、FreeMarker 程序

    这里通过模拟简单的代码自动生产工具来感受第一个FreeMarker程序。

    1、项目目录结构

    2、项目创建流程

    第一步:创建一个maven项目导入 FreeMarker jar 包

    第二步:创建目录templates,并创建一个 FreeMarker模版文件 hello.ftl

    第三步:创建一个运行FreeMarker模版引擎的 FreeMarkerDemo.java 文件

    第四步:运行main方法后刷新项目

    pom.xml 文件 ,maven 项目核心文件,管理 jar 包。

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.freemark</groupId>
        <artifactId>freemarkerStudy</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>org.freemarker</groupId>
                <artifactId>freemarker</artifactId>
                <version>2.3.20</version>
            </dependency>
        </dependencies>
        
    </project>
    

    FreeMarker基本语法: ${xxx} ,xxx 相当于占位符,java后台给xxx赋值后,再通过 ${} 输出

    package ${classPath};
    
    public class ${className} {
        public static void main(String[] args) {
            System.out.println("${helloWorld}");
        }
    }
    

    FreeMarkerDemo.java 核心方法,使用 FreeMarker 模版引擎。

    package com.freemark.hello;
    
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.OutputStreamWriter;
    import java.io.Writer;
    import java.util.HashMap;
    import java.util.Map;
    
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    
    /**
     * 最常见的问题: 
     *     java.io.FileNotFoundException: xxx does not exist. 解决方法:要有耐心
     *     FreeMarker jar 最新的版本(2.3.23)提示 Configuration 方法被弃用
     * 代码自动生产基本原理:
     *     数据填充 freeMarker 占位符
     */
    public class FreemarkerDemo {
        
        private static final String TEMPLATE_PATH = "src/main/java/com/freemark/hello/templates";
        private static final String CLASS_PATH = "src/main/java/com/freemark/hello";
        
        public static void main(String[] args) {
            // step1 创建freeMarker配置实例
            Configuration configuration = new Configuration();
            Writer out = null;
            try {
                // step2 获取模版路径
                configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
                // step3 创建数据模型
                Map<String, Object> dataMap = new HashMap<String, Object>();
                dataMap.put("classPath", "com.freemark.hello");
                dataMap.put("className", "AutoCodeDemo");
                dataMap.put("helloWorld", "通过简单的 <代码自动生产程序> 演示 FreeMarker的HelloWorld!");
                // step4 加载模版文件
                Template template = configuration.getTemplate("hello.ftl");
                // step5 生成数据
                File docFile = new File(CLASS_PATH + "\" + "AutoCodeDemo.java");
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
                // step6 输出文件
                template.process(dataMap, out);
                System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^AutoCodeDemo.java 文件创建成功 !");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != out) {
                        out.flush();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
    }
    

    运行程序后刷新项目,会发现多了一个AutoCodeDemo.java类。不仅仅是java类,xml也是可以。

    三、FreeMarker 语法示例

    语法和java很类似,其中宏的概念可能比较陌生,先上代码

    FreeMarker 主要核心知识点

    字符串输出:
    ${"Hello ${name} !"} / ${"Hello " + name + " !"}
    <#assign cname=r"特殊字符完成输出(http:www.baidu.com)">
    ${cname}
    
    字符串截取 : 
    通过下标直接获取下标对应的字母: ${name[2]}
    起点下标..结尾下标截取字符串:${name[0..5]}
    
    算数运算:
    <#-- 支持"+"、"-"、"*"、"/"、"%"运算符 -->
    <#assign number1 = 10>
    <#assign number2 = 5>
    "+" : ${number1 + number2}
    "-" : ${number1 - number2}
    "*" : ${number1 * number2}
    "/" : ${number1 / number2}
    "%" : ${number1 % number2}
    
    比较运算符:
    <#if number1 + number2 gte 12 || number1 - number2 lt 6>
    "*" : ${number1 * number2}
    <#else>
    "/" : ${number1 / number2}
    </#if>
    
    内建函数:
    <#assign data = "abcd1234">
    第一个字母大写:${data?cap_first}
    所有字母小写:${data?lower_case}
    所有字母大写:${data?upper_case}
    <#assign floatData = 12.34>
    数值取整数:${floatData?int}
    获取集合的长度:${users?size}
    时间格式化:${dateTime?string("yyyy-MM-dd")}
    
    空判断和对象集合:
    <#if users??>
    <#list users as user >
    ${user.id} - ${user.name}
    </#list>
    <#else>
    ${user!"变量为空则给一个默认值"}
    </#if>
    
    Map集合:
    <#assign mapData={"name":"程序员", "salary":15000}>
    直接通过Key获取 Value值:${mapData["name"]}
    通过Key遍历Map:
    <#list mapData?keys as key>
    Key: ${key} - Value: ${mapData[key]}
    </#list>
    通过Value遍历Map:
    <#list mapData?values as value>
    Value: ${value}
    </#list>
    
    List集合:
    <#assign listData=["newRyan", "blog", "is", "cool"]>
    <#list listData as value>${value} </#list>
    
    include指令:
    引入其他文件:<#include "otherFreeMarker.ftl" />
    
    macro宏指令:
    <#macro mo>
    定义无参数的宏macro--${name}
    </#macro>
    使用宏macro: <@mo />
    <#macro moArgs a b c>
    定义带参数的宏macro-- ${a+b+c}
    </#macro>
    使用带参数的宏macro: <@moArgs a=1 b=2 c=3 />
    
    命名空间:
    <#import "otherFreeMarker.ftl" as otherFtl>
    ${otherFtl.otherName}
    <@otherFtl.addMethod a=10 b=20 />
    <#assign otherName="修改otherFreeMarker.ftl中的otherName变量值"/>
    ${otherFtl.otherName}
    <#assign otherName="修改otherFreeMarker.ftl中的otherName变量值" in otherFtl />
    ${otherFtl.otherName}
    

    otherFreeMarker.ftl 为了测试命名空间 和 include 指令的FreeMarker文件

    其他FreeMarker文件
    <#macro addMethod a b >
    result : ${a + b}
    </#macro>
    <#assign otherName="另外一个FreeMarker的变量">
    

    FreeMarkerDemo.java 核心方法

    package com.freemark.demo;
    
    import java.util.List;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.OutputStreamWriter;
    import java.io.Writer;
    import java.util.Date;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;
    
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    
    public class FreeMarkerDemo {
        
        private static final String TEMPLATE_PATH = "src/main/java/com/freemark/demo/templates";
        
        public static void main(String[] args) {
            // step1 创建freeMarker配置实例
            Configuration configuration = new Configuration();
            Writer out = null;
            try {
                // step2 获取模版路径
                configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
                // step3 创建数据模型
                Map<String, Object> dataMap = new HashMap<String, Object>();
                dataMap.put("name", "newRyan博客");
                dataMap.put("dateTime", new Date());
                
                List<User> users = new ArrayList<User>();
                users.add(new User(1, "newRyan 博客"));
                users.add(new User(2, "欢迎"));
                users.add(new User(3, "You!"));
                dataMap.put("users", users);
                // step4 加载模版文件
                Template template = configuration.getTemplate("stringFreeMarker.ftl");
                // step5 生成数据
                out = new OutputStreamWriter(System.out);
                // step6 输出文件
                template.process(dataMap, out);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != out) {
                        out.flush();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
    
    }
    

    User.java 为了测试 FreeMarker的集合对象

    package com.freemark.demo;
    
    public class User {
    
        private Integer id;
        private String name;
    
        public User() {
        }
    
        public User(Integer id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "User [id=" + id + ", name=" + name + "]";
        }
    
    }
    

    最后的打印结果

    字符串输出:
    Hello newRyan博客 ! / Hello newRyan博客 !
    特殊字符完成输出(http:www.baidu.com)
    
    字符串截取 : 
    通过下标直接获取下标对应的字母: w
    起点下标..结尾下标截取字符串:newRya
    
    算数运算:
    "+" : 15
    "-" : 5
    "*" : 50
    "/" : 2
    "%" : 0
    
    比较运算符:
    "*" : 50
    
    内建函数:
    第一个字母大写:Abcd1234
    所有字母小写:abcd1234
    所有字母大写:ABCD1234
    数值取整数:12
    获取集合的长度:3
    时间格式化:2017-10-29
    
    空判断和对象集合:
    - newRyan 博客
    - 欢迎
    - You!
    
    Map集合:
    直接通过Key获取 Value值:程序员
    通过Key遍历Map:
    Key: name - Value: 程序员
    Key: salary - Value: 15,000
    通过Value遍历Map:
    Value: 程序员
    Value: 15,000
    
    List集合:
    newRyan blog is cool 
    
    include指令:
    其他FreeMarker文件
    
    macro宏指令:
    使用宏macro: 定义无参数的宏macro--newRyan博客
    使用带参数的宏macro: 定义带参数的宏macro-- 6
    
    命名空间:
    另外一个FreeMarker的变量
    result : 30
    另外一个FreeMarker的变量
    修改otherFreeMarker.ftl中的otherName变量值
    

    四、FreeMarker 语法详解

    数据类型

    和java不同,FreeMarker不需要定义变量的类型,直接赋值即可。

    字符串: value = "xxxx" 。如果有特殊字符 string = r"xxxx" 。单引号和双引号是一样的。

    数值:value = 1.2。数值可以直接等于,但是不能用科学计数法。

    布尔值:true or false。

    List集合:list = [1,2,3] ; list=[1..100] 表示 1 到 100 的集合,反之亦然。

    Map集合:map = {"key" : "value" , "key2" : "value2"},key 必须是字符串哦!

    实体类:和EL表达式差不多,直接点出来。

    字符串操作

    字符串连接:可以直接嵌套${"hello , ${name}"} ; 也可以用加号${"hello , " + name}

    字符串截取:string[index]。index 可以是一个值,也可以是形如 0..2 表示下标从0开始,到下标为2结束。一共是三个数。

    比较运算符

    == (等于),!= (不等于),gt(大于),gte(大于或者等于),lt(小于),lte(小于或者等于)。不建议用 >,< 可能会报错!

    一般和 if 配合使用

    内建函数

    FreeMarker 提供了一些内建函数来转换输出,其结构:变量?内建函数,这样就可以通过内建函数来转换输出变量。

    (1) html: 对字符串进行HTML编码;
    (2) cap_first: 使字符串第一个字母大写;
    (3) lower_case: 将字符串转成小写;
    (4) upper_case: 将字符串转成大写;
    (5) size: 获得集合中元素的个数;
    (6) int: 取得数字的整数部分。

    变量空判断

    !   指定缺失变量的默认值;一般配置变量输出使用
    ??  判断变量是否存在。一般配合if使用 <#if value??></#if>

    宏指令

    可以理解为java的封装方法,供其他地方使用。宏指令也称为自定义指令,macro指令

    语法很简单: <#macro val > 声明macro </#macro>; 使用macro <@val />

    命名空间

    可以理解为java的import语句,为避免变量重复。一个重要的规则就是:路径不应该包含大写字母,使用下划线_分隔词语,myName --> my_name

    语法很简单:<#import "xxx.ftl" as val>

    其他没有说明的语法是因为和java一样,没什么特别之处。所以没有列出来。

    五、FreeMarker Web

    这里是和SpringMVC整合的,导入相关的jar pom.xml

    <!-- freeMarker start -->
        <dependency>
             <groupId>org.freemarker</groupId>
             <artifactId>freemarker</artifactId>
             <version>2.3.20</version>
         </dependency>
         <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context-support</artifactId>
              <version>4.1.4.RELEASE</version>
          </dependency>
      </dependencies> 
      <!-- freeMarker end -->
    

    springmvc的配置文件:

    <!-- 整合Freemarker -->
        <!-- 放在InternalResourceViewResolver的前面,优先找freemarker -->  
        <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">  
            <property name="templateLoaderPath" value="/WEB-INF/views/templates"/>  
        </bean>  
        <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">  
            <property name="prefix" value=""/>  
            <property name="suffix" value=".ftl"/>  
            <property name="contentType" value="text/html; charset=UTF-8"/>
        </bean>
    

    Controller 层

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class HelloFreeMarkerController {
        
        @RequestMapping("/helloFreeMarker")
        public String helloFreeMarker(Model model) {
            model.addAttribute("name","newRyan博客");  
            return "helloFreeMarker";
        }
    
    }
    

    最后是Freemarker文件

    <html>  
        <head>  
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
            <title>FreeMarker Web</title>  
        </head>  
        <body>  
            <h1>Hello ${name} !</h1>  
        </body>  
    </html>
    

    源码地址:https://gitee.com/itdragon/springmvc

    六、小结

    1. 知道了FreeMarker是一块模版引擎,可以生产xml,html,java等文件

    2. 知道了FreeMarker文件提供占位符,java文件提供数据,通过FreeMarker模版引擎生产有数据的页面,文中是将数据放在Map中。web应用可以用setter/getter 方法

    3. 知道了FreeMarker语法中字符串的显示特殊字符,截取的操作。以及一些内置方法的使用

    4. 重点了解FreeMarker的空判断知识点。判断变量是否为空用 "??" ,如果变量为空设置默认值。如果不注意空问题,可能会出现黄色页面的提示哦!

    5. FreeMarker的宏概念,命名空间,引入文件,给变量赋值,集合的遍历等。

    6. Freemarker 整合SpringMVC。

  • 相关阅读:
    时间戳计算
    .NET/C#/Oracle数据库操作类
    memcached安装及.NET中的Memcached.ClientLibrary使用
    C# Redis
    Jmeter教程 简单的压力测试
    Elasticsearch查询类型
    Windows 如何查看本地端口被进程占用的情况?
    Log4net 配置
    NLog 配置
    RPC原理
  • 原文地址:https://www.cnblogs.com/newRyan/p/12611705.html
Copyright © 2020-2023  润新知