layout: post title: freemark集成到项目中 categories: [work] date: 2016-04-18

tags: [freemarker]

1.集成

1.1添加jar包

在web/pom.xml中添加jar包。

<!--freemark -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
</dependency>

1.2在mvc-dispatcher.xml中添加视频解析器

<bean id="freemarkConfig"
        class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="location" value="classpath:messages/freemark.properties" />
    </bean>

    <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />

    <!-- 配置FreeMark视图 -->
    <bean id="freeMarkerViewResolver"
        class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <property name="contentType" value="text/html;charset=UTF-8" />
        <property name="viewClass"
            value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
        <property name="suffix" value=".ftl" />
        <property name="cache" value="true" />
        <property name="exposeSessionAttributes" value="true" />
        <property name="exposeRequestAttributes" value="true" />
        <property name="exposeSpringMacroHelpers" value="true" />
        <!-- 在页面中使用${rc.contextPath}就可获得contextPath -->
        <property name="requestContextAttribute" value="rc" />
        <property name="order" value="0" />
    </bean>

    <bean id="FreeMarkerConfigurer"
        class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/ftl/" />
        <property name="defaultEncoding" value="UTF-8" />
        <property name="freemarkerSettings" ref="freemarkConfig" />
        <property name="freemarkerVariables">
            <map>
                <entry key="xml_escape" value-ref="fmXmlEscape" />
            </map>
        </property>
    </bean>

在messages下添加messages/freemark.properties

tag_syntax=auto_detect
template_update_delay=30
default_encoding=UTF-8
output_encoding=UTF-8
locale=zh_CN
date_format=yyyy-MM-dd
time_format=HH:mm:ss
datetime_format=yyyy-MM-dd HH:mm:ss
number_format=0.######
whitespace_stripping=true
url_escaping_charset=UTF-8

添加jsp视图解析器order属性。

<!--  Freemark找不到找jsp -->
<property name="order" value="1" />

简单测试略。默认先找freemark解析,找不到找jsp。返回json与他们无关。

2.freemark

2.1 简单介绍

Apache FreeMarker is a template engine: a Java library to generate text output (HTML web pages, e-mails, configuration files, source code, etc.) based on templates and changing data.

![](http://freemarker.org/images/overview.png)
Template + data-model = output

2.2 data-model

和程序开发数据类型基本一致。

  • 树状基本结构,树可以复杂而且有很大的深度。
  • 字符串,数字,日期/时间,布尔值。
  • 哈希表,Map:${product.proPic.price}
  • 序列器,如Java数组、List。变量通过数字索引来检索,索引通常从零开始。${products[0].name}

2.2.1日期的处理:

java.sql.date会自动转换 java.util.date: ${(date?string("yyyy-MM-dd HH:mm"))!}

FreeMarker中的日期时间处理 Built-ins for date/time/date-time values

2.2.2 空值处理

<h1>Welcome ${user!"visitor"}!</h1>
<#--user为空,显示"visitor"-->
<#if user??><h1>Welcome ${user}!</h1></#if>
<#-- ?? 判断用户是否为空-->

2.3 Templates

2.3.1 List

  • list的长度 ${books?size}
  • 集合迭代
<#list studentsList as student>
    <h1>id:${student.id}</h1>
    <h1>name:${student.name}</h1>
</#list>

如果studentsList没有元素,那么依旧会有如下输出 id:

name:

所以为了避免这一问题。可以使用如下的表示: 注意:在2.3.23后才支持官方网站更新日志

<#list studentsList>
    <#items as student>
        <h1>id:${student.id}</h1>
        <h1>name:${student.name}</h1>
    </#items>
</#list>

如果集合元素为空,那么还可以使用<#else>来进行为空时的操作,这时就会去do something,例如:

<#list studentsList>
    <#items as student>
        <h1>id:${student.id}</h1>
        <h1>name:${student.name}</h1>
</#items>
<#else>
    Do Something…
</#list>

可以使用<#sep>something</#sep>来分割输出的内容。例如:

<p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, </#list>

那么就会将输出的水果用逗号分开,like

Fruits: orange, banana

对于集合而言他有下面的属性: 集合本身有以下属性: index:索引,从0开始 counter:计数,从1开始 item_parity:奇偶性,返回当前counter的奇偶性,返回字符串"odd","even", 可以这样使用

 <td class="${animal?item_parity}Row">

一个简洁的例子

<#list books>
    <#items as book>
    <li class="abook clearFix"><img class="book-pic" src="${book.img}" alt=""/>
    <div class="book-text">
        <p class="book-title text-min">
            ${book.title}--index:${book_index} </br>
            ${book?counter}
            ${book?index}
            ${book?item_parity}

        </p>
        <a target="_blank" class="go-book" href="${book.url}">开始阅读</a>
    </div>
    </li>
    </#items>
</#list>

2.3.2控制语句

  • if..else 判断
    <#if expression>
    <#elseif expression >
    <#else>
    </#if>
    
    list和if可以嵌套使用。遍历的时候判断。

    2.3.3引用<#include url>

    使用这个标签,可以引入外部的另一段内容到当前的文件中。

2.3.4 一些内建函数

函数调用使用?,如: animal?item_parity

  • html:对字符串进行HTML编码
  • cap_first:使字符串第一个字母大写
  • lower_case:将字符串转换成小写
  • upper_case:将字符串转换成大写
  • trim:去掉字符串前后的空白字符
  • size:获得序列中元素的数目
  • int:取得数字的整数部分(如-1.9?int的结果是-1) 具体的可以看这

2.3.5 宏 自定义标签

macro, nested, return

<#macro name="" param1="" param2="" ...="" paramN="">
  ...
  <#nested loopvar1,="" loopvar2,="" ...,="" loopvarN="">
  ...
  <#return>
  ...

参数说明:

name: 宏的名字,调用时使用<@name> param1 param2: 传递进去的参数 nested: macro 开始和结束标签之间的内容。 return: 就是返回了,后边的不输出。

简单例子, 参数含有默认值。

<#macro test foo bar="Bar" baaz=-1>
  Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<@test foo="a" bar="b" baaz=5*5-2/>
<@test foo="a" bar="b"/>
<@test foo="a" baaz=5*5-2/>
<@test foo="a"/>

output:

Test text, and the params: a, b, 23
Test text, and the params: a, b, -1
Test text, and the params: a, Bar, 23
Test text, and the params: a, Bar, -1

人人通首页DEMO: template.ftl

<#macro htmlHead title charset="utf-8" lang="zh-CN">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=${charset}" />
        <meta http-equiv="Content-Language" content="${lang}"/>
        <title>${title}</title>
        <#nested>
    </head>
</#macro>

<#macro htmlBody>
    <body class="all-bj">
        <#nested>
    </body>
</html>
</#macro>

调用页面

<#include "templet.ftl"/>

<@htmlHead title="人人通 ">
    <link rel="stylesheet" href="${rc.contextPath}/static/css/comm.css">
</@htmlHead>

<@htmlBody>
    <#include "./header.ftl"/>
    <div class="wrap content">
        <#include "./body-hearder.ftl">
        <div id="work" class="content-body clearFix">
            <div class="content-left clearFix">
                <#include "prefile.ftl">
                <#include "app.ftl">
                <#include "books.ftl">
            </div>
        <#include "right.ftl">
        </div>
    </div>
    <#import "footer.ftl" as footer  />
    <@footer.copyright date="2009-2016"/>
</@htmlBody>

2.3.6 命名空间

就是assign 和 macro 指令创建的变量的集合。

  • 变量:

    • ''简单''变量: 它能从模板中的任何位置来访问,或者从使用 include 指令引入的模板访问。可以使用 assign 指令来创建或替换这些变量。因为宏和方法只是变量,那么 macro 指令 和 function 指令 也可以用来设置变量,就像 assign 那样。

    • 局部变量:它们只能被设置在 宏定义体内, 而且只在宏内可见。一个局部变量的生命周期只是宏的调用过程。可以使用 local指令 在宏定义体内创建或替换局部变量。

    • 循环变量:循环变量是由如 list 指令自动创建的,而且它们只在指令的开始和结束标记内有效。宏 的参数是局部变量而不是循环变量。

    • 全局变量:这是一个高级话题了, 并且这种变量最好别用。即便它们属于不同的命名空间, 全局变量也被所有模板共享,因为它们是被 import进来的, 不同于 include 进来的。那么它们的可见度就像数据模型那样。 全局变量通过 global指令来定义。

变量介绍

命名空间例子:

<#macro copyright date>
  <p>Copyright (C) ${date} Julia Smith. All rights reserved.</p>
</#macro>
<#assign mail = "jsmith@acme.com">

注意: import 导入命名空间,不是include。不同的命名空间变量名可以相同。

<#import "/lib/my_test.ftl" as my> <#-- the hash called "my" will be the "gate" -->
<@my.copyright date="1999-2002"/>
${my.mail}

output:

<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.</p>
jsmith@acme.com

声明相同的变量

<#import "/lib/my_test.ftl" as my>
<#assign mail="fred@acme.com">
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}

output:

<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
<br>Email: jsmith@acme.com</p>
jsmith@acme.com
fred@acme.com

如果想改掉命名空间内的变量该怎么办呢?

<#import "/lib/my_test.ftl" as my>
${my.mail}
<#assign mail="jsmith@other.com" in my>
${my.mail}

命名空间就和java中的类一样,宏是类中的静态方法。

Q: 和后台交互使用ajax, 页面局部更新的时候怎么使用freemarker? Q: 分页