Freemarker研究

1.1 FreeMarker介紹

1、 freemarker是一個(gè)用Java開(kāi)發(fā)的模板引擎

FreeMarker是一款模板引擎: 即一種基于模板和要改變的數(shù)據(jù), 并用來(lái)生成輸出文本(HTML網(wǎng)頁(yè)、電子郵件、配置文件、源代碼等)的通用工具。 它不是面向最終用戶的,而是一個(gè)Java類庫(kù),是一款程序員可以嵌入他們所開(kāi)發(fā)產(chǎn)品的組件。
FreeMarker是免費(fèi)的,基于Apache許可證2.0版本發(fā)布。其模板編寫為FreeMarker Template Language(FTL),屬于簡(jiǎn)單、專用的語(yǔ)言。需要準(zhǔn)備數(shù)據(jù)在真實(shí)編程語(yǔ)言中來(lái)顯示,比如數(shù)據(jù)庫(kù)查詢和業(yè)務(wù)運(yùn)算, 之后模板顯示已經(jīng)準(zhǔn)備好的數(shù)據(jù)。在模板中,主要用于如何展現(xiàn)數(shù)據(jù), 而在模板之外注意于要展示什么數(shù)據(jù) [1]

image.png

常用的java模板引擎還有哪些?

Jsp、Freemarker、Thymeleaf 、Velocity 等

2、模板+數(shù)據(jù)模型=輸出

freemarker并不關(guān)心數(shù)據(jù)的來(lái)源,只是根據(jù)模板的內(nèi)容,將數(shù)據(jù)模型在模板中顯示并輸出文件(通常為html,也可以生成其它格式的文本文件)
1、數(shù)據(jù)模型
數(shù)據(jù)模型在java中可以是基本類型也可以List、Map、Pojo等復(fù)雜類型。
2、來(lái)自官方的例子:(https://freemarker.apache.org/docs/dgui_quickstart_basics.html

數(shù)據(jù)模型:


模板:
image.png

輸出:
image.png

1.2 FreeMarker快速入門

freemarker作為springmvc一種視圖格式,默認(rèn)情況下SpringMVC支持freemarker視圖格式。
需要?jiǎng)?chuàng)建Spring Boot+Freemarker工程用于測(cè)試模板。

1.2.1 創(chuàng)建測(cè)試工程

創(chuàng)建一個(gè)freemarker 的測(cè)試工程專門用于freemarker的功能測(cè)試與模板的測(cè)試。
pom如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>
    </dependencies>
1.2.2 配置文件

yaml

server:
  port: 8088

spring:
  application:
    name: test‐freemarker #指定服務(wù)名
  freemarker:
    cache: false #關(guān)閉模板緩存,方便測(cè)試
    settings:
      template_update_delay: 0 #檢查模板更新延遲時(shí)間,設(shè)置為0表示立即檢查,如果時(shí)間大于0會(huì)有緩存不方便進(jìn)行模板測(cè)試
1.2.3 創(chuàng)建模型類

在freemarker的測(cè)試工程下創(chuàng)建模型類型用于測(cè)試

@Data
@ToString
public class Student {
    private String name;//姓名
    private int age;//年齡
    private Date birthday;//生日
    private Float money;//錢包
    private List<Student> friends;//朋友列表
    private Student bestFriend;//最好的朋友
}

1.2.4 創(chuàng)建模板

在 src/main/resources下創(chuàng)建templates,此目錄為freemarker的默認(rèn)模板存放目錄。在templates下創(chuàng)建模板文件test1.ftl,模板中的${name}最終會(huì)被freemarker替換成具體的

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf‐8">
    <title>Hello World!</title>
</head>
<body>
Hello ${name}!
</body>
</html>
1.2.5 創(chuàng)建controller

創(chuàng)建Controller類,向Map中添加name,最后返回模板文件

@RequestMapping("/freemarker")
@Controller
public class FreemarkerController {

    @RequestMapping("/test1")
    public String freemarker(Map<String, Object> map){
        map.put("name","小小程序員");
        //返回模板文件名稱,默認(rèn)是templates包下的
        return "test1";
    }

}
1.2.6 測(cè)試

請(qǐng)求:http://localhost:8088/freemarker/test1
屏幕顯示:Hello 小小程序員!

1.3 FreeMarker基礎(chǔ)

1.3.1 核心基礎(chǔ)
1.3.1.1 數(shù)據(jù)模型

Freemarker靜態(tài)化依賴數(shù)據(jù)模型和模板,下邊定義數(shù)據(jù)模型:
下邊方法形參map即為freemarker靜態(tài)化所需要的數(shù)據(jù)模型,在map中填充數(shù)據(jù):

@RequestMapping("/test1")
    public String freemarker(Map<String, Object> map){
        //向數(shù)據(jù)模型放數(shù)據(jù)
        map.put("name","小小程序員");
        Student stu1 = new Student();
        stu1.setName("小明");
        stu1.setAge(18);
        stu1.setMoney(1000.86f);
        stu1.setBirthday(new Date());
        Student stu2 = new Student();
        stu2.setName("小紅");
        stu2.setMoney(200.1f);
        stu2.setAge(19);
//        stu2.setBirthday(new Date());
        List<Student> friends = new ArrayList<>();
        friends.add(stu1);
        //給第二名學(xué)生好朋友列表
        stu2.setFriends(friends);
        //給第二名學(xué)生最好的朋友
        stu2.setBestFriend(stu1);
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);
        //向數(shù)據(jù)模型放數(shù)據(jù)
        map.put("stus",stus);
        //準(zhǔn)備map數(shù)據(jù)
        HashMap<String,Student> stuMap = new HashMap<>();
        stuMap.put("stu1",stu1);
        stuMap.put("stu2",stu2);
        //向數(shù)據(jù)模型放數(shù)據(jù)
        map.put("stu1",stu1);
        //向數(shù)據(jù)模型放數(shù)據(jù)
        map.put("stuMap",stuMap);
        //返回模板文件名稱
        return "test1";
    }
1.3.1.2 List指令

1、注釋,即<#‐‐和‐‐>,介于其之間的內(nèi)容會(huì)被freemarker忽略
2、插值(Interpolation):即${..}部分,freemarker會(huì)用真實(shí)的值代替${..}
3、FTL指令:和HTML標(biāo)記類似,名字前加#予以區(qū)分,F(xiàn)reemarker會(huì)解析標(biāo)簽中的表達(dá)式或邏輯。
4、文本,僅文本信息,這些不是freemarker的注釋、插值、FTL指令的內(nèi)容會(huì)被freemarker忽略解析,直接輸出內(nèi)容。

在test1.ftl模板中使用list指令遍歷數(shù)據(jù)模型中的數(shù)據(jù):

<table>
    <tr>
        <td>序號(hào)</td>
        <td>姓名</td>
        <td>年齡</td>
        <td>錢包</td>
    </tr>
    <#list stus as stu>
        <tr>
            <td>${stu_index+1}</td>
            <td>${stu.name}</td>
            <td>${stu.age}</td>
            <td>${stu.money}</td>
        </tr>
    </#list>
</table>
1.3.1.3 遍歷Map數(shù)據(jù)

1、數(shù)據(jù)模型
使用map指令遍歷數(shù)據(jù)模型中的stuMap。
2、模板

   <#--遍歷map-->
    姓名:${stuMap['stu1'].name}<br/>
    年齡:${stuMap['stu1'].age}<br/>

    姓名:${stuMap.stu1.name}<br/>
    年齡:${stuMap.stu1.age}<br/>
<table>
    <tr>
        <td>序號(hào)</td>
        <td>姓名</td>
        <td>年齡</td>
        <td>錢包</td>
    </tr>
    <#list stuMap?keys as k>
        <tr>
        <td>${k_index + 1}</td>
        <td>${stuMap[k].name}</td>
        <td>${stuMap[k].age}</td>
        <td>${stuMap[k].mondy}</td>
        </tr>
    </#list>
</table>
1.3.1.4 if指令

if 指令即判斷指令,是常用的FTL指令,freemarker在解析時(shí)遇到if會(huì)進(jìn)行判斷,條件為真則輸出if中間的內(nèi)容,否
則跳過(guò)內(nèi)容不再輸出。
1、數(shù)據(jù)模型:
使用list指令中測(cè)試數(shù)據(jù)模型。
2、模板:

<table>
    <tr>
        <td>序號(hào)</td>
        <td>姓名</td>
        <td>年齡</td>
        <td>錢包</td>
    </tr>
    <#--list指令-->
    <#list stus as stu>
        <tr>
            <td>${stu_index+1}</td>
            <td <#if stu.name=='小明'>style="background:red;"</#if> >${stu.name}</td>
            <td>${stu.age}</td>
            <td <#if (stu.money > 200)>style="background:red;"</#if> >${stu.money}</td>
        </tr>
    </#list>
</table>

3、輸出:
通過(guò)測(cè)試發(fā)現(xiàn) 姓名為小明的背景色為紅色。

1.3.2 其它指令

1.3.2.1 運(yùn)算符

1、算數(shù)運(yùn)算符 FreeMarker表達(dá)式中完全支持算術(shù)運(yùn)算,FreeMarker支持的算術(shù)運(yùn)算符包括:+, - , * , / , %

2、邏輯運(yùn)算符 邏輯運(yùn)算符有如下幾個(gè): 邏輯與:&& 邏輯或:|| 邏輯非:! 邏輯運(yùn)算符只能作用于布爾值,否則將產(chǎn)生錯(cuò)誤

3、比較運(yùn)算符 表達(dá)式中支持的比較運(yùn)算符有如下幾個(gè):1 =或者==:判斷兩個(gè)值是否相等. 2 !=:判斷兩個(gè)值是否不等. 3 >或者gt:判斷左邊值是否大于右邊值

4 >=或者gte:判斷左邊值是否大于等于右邊值

5 <或者lt:判斷左邊值是否小于右邊值

6 <=或者lte:判斷左邊值是否小于等于右邊值

注意: =和!=可以用于字符串,數(shù)值和日期來(lái)比較是否相等,但=和!=兩邊必須是相同類型的值,否則會(huì)產(chǎn)生錯(cuò)誤,而且FreeMarker是精確比較,"x","x ","X"是不等的.其它的運(yùn)行符可以作用于數(shù)字和日期,但不能作用于字符串,大部分的時(shí)候,使用gt等字母運(yùn)算符代替>會(huì)有更好的效果,因?yàn)?FreeMarker會(huì)把>解釋成FTL標(biāo)簽的結(jié)束字符,當(dāng)然,也可以使用括號(hào)來(lái)避免這種情況,如:<#if (x>y)

1.3.2.2 空值處理

1、判斷某變量是否存在使用 “??” 用法為:variable??,如果該變量存在,返回true,否則返回false
例:為防止stus為空?qǐng)?bào)錯(cuò)可以加上判斷如下:

<#if stus??>
<#list stus as stu>
......
</#list>
</#if>

2、缺失變量默認(rèn)值使用 “!” 使用!要以指定一個(gè)默認(rèn)值,當(dāng)變量為空時(shí)顯示默認(rèn)值。
例: ${name!''}表示如果name為空顯示空字符串。

//默認(rèn)為空
<td>${(stuMap[k].mondy)!""}</td>
1.3.2.3 內(nèi)建函數(shù)

內(nèi)建函數(shù)語(yǔ)法格式: 變量+?+函數(shù)名稱
1、和到某個(gè)集合的大小
${集合名?size}

2、日期格式化

顯示年月日: ${today?date}
顯示時(shí)分秒:${today?time}
顯示日期+時(shí)間:${today?datetime} <br>
自定義格式化: ${today?string("yyyy年MM月")}

3、內(nèi)建函數(shù)c
map.put("point", 102920122);
point是數(shù)字型,使用{point}會(huì)顯示這個(gè)數(shù)字的值,不并每三位使用逗號(hào)分隔。 如果不想顯示為每三位分隔的數(shù)字,可以使用c函數(shù)將數(shù)字型轉(zhuǎn)成字符串輸出{point?c}

4、將json字符串轉(zhuǎn)成對(duì)象
一個(gè)例子:
其中用到了 assign標(biāo)簽,assign的作用是定義一個(gè)變量。

<#assign text="{'bank':'工商銀行','account':'10101920201920212'}" />
<#assign data=text?eval />
開(kāi)戶行:${data.bank} 賬號(hào):${data.account}

1.3.3 靜態(tài)化測(cè)試

在cms中使用freemarker將頁(yè)面生成html文件,本節(jié)測(cè)試html文件生成的方法:

1、使用模板文件靜態(tài)化
定義模板文件,使用freemarker靜態(tài)化程序生成html文件。

2、使用模板字符串靜態(tài)化
定義模板字符串,使用freemarker靜態(tài)化程序生成html文件。

package com.xuecheng.test.freemarker;

import com.xuecheng.test.freemarker.model.Student;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * Description:
 *
 * @author smile
 * @date 2018-12-24
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestFreemarker {


@Test
public void testGenerateHtml() throws IOException, TemplateException {
    //創(chuàng)建配置類
    Configuration configuration = new Configuration(Configuration.getVersion());
    String classpath = this.getClass().getResource("/").getPath();
    //設(shè)置模板路徑
    configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates/"));
    //設(shè)置字符集
    configuration.setDefaultEncoding("utf-8");
    //加載模板
    Template template = configuration.getTemplate("test1.ftl");
    //數(shù)據(jù)模型
    Map map = getMap();
    //靜態(tài)化
    String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
    //靜態(tài)化內(nèi)容
    System.out.println(content);
    InputStream inputStream = IOUtils.toInputStream(content);
    //輸出文件
    FileOutputStream fileOutputStream = new FileOutputStream(new File("d:/test1.html"));
    int copy = IOUtils.copy(inputStream, fileOutputStream);


}


    //基于模板字符串生成靜態(tài)化文件
    @Test
    public void testGenerateHtmlByString() throws IOException, TemplateException {
        //創(chuàng)建配置類
        Configuration configuration=new Configuration(Configuration.getVersion());
        //獲取模板內(nèi)容
        //模板內(nèi)容,這里測(cè)試時(shí)使用簡(jiǎn)單的字符串作為模板
        String templateString="" +
                "<html>\n" +
                "    <head></head>\n" +
                "    <body>\n" +
                "    名稱:${name}\n" +
                "    </body>\n" +
                "</html>";

        //加載模板
        //模板加載器
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template",templateString);
        configuration.setTemplateLoader(stringTemplateLoader);
        Template template = configuration.getTemplate("template","utf-8");

        //數(shù)據(jù)模型
        Map map = getMap();
        //靜態(tài)化
        String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
        //靜態(tài)化內(nèi)容
        System.out.println(content);
        InputStream inputStream = IOUtils.toInputStream(content);
        //輸出文件
        FileOutputStream fileOutputStream = new FileOutputStream(new File("d:/test1.html"));
        IOUtils.copy(inputStream, fileOutputStream);
    }




    //數(shù)據(jù)模型
    private Map getMap(){
        Map<String, Object> map = new HashMap<>();
        //向數(shù)據(jù)模型放數(shù)據(jù)
        map.put("name","小小程序員");
        Student stu1 = new Student();
        stu1.setName("小明");
        stu1.setAge(18);
        stu1.setMoney(1000.86f);
        stu1.setBirthday(new Date());
        Student stu2 = new Student();
        stu2.setName("小紅");
        stu2.setMoney(200.1f);
        stu2.setAge(19);
        stu2.setBirthday(new Date());
        List<Student> friends = new ArrayList<>();
        friends.add(stu1);
        //給第二名學(xué)生好朋友列表
        stu2.setFriends(friends);
        //給第二名學(xué)生最好的朋友
        stu2.setBestFriend(stu1);
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);
        //向數(shù)據(jù)模型放數(shù)據(jù)
        map.put("stus",stus);
        //準(zhǔn)備map數(shù)據(jù)
        HashMap<String,Student> stuMap = new HashMap<>();
        stuMap.put("stu1",stu1);
        stuMap.put("stu2",stu2);
        //向數(shù)據(jù)模型放數(shù)據(jù)
        map.put("stu1",stu1);
        //向數(shù)據(jù)模型放數(shù)據(jù)
        map.put("stuMap",stuMap);
        return map;
    }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容