Freemarker常用技巧(三)

freemarker模板解析过程

例如:一个freemarker表达式<body> ${hello} </body>,会被解析成三个部分,分别是
<body>
${hello}
</body>
前面和后面的body标签,在freemarker中被定义为TextBlock,中间的变量定义为DollarVariable。那么目前的结构也就是RootExpression = TextBlock DollarVariable TextBlock。解释器一进来将会对RootExpression进行解析,RootExpression将会依次调用TextBlock DollarVariable TextBlock进行解析。不同类型将会做不同操作,根据传进来的Context参数进行相应赋值并输出等。
当Template启动解释时,由Environment进入调用根元素的访问动作,根元素会依次访问所包含的TemplateElement,直到所有叶子节点访问完成,这些访问动作是通过调用Environment的visit方法控制,Environment做些相关必要操作,再根据访问的节点类型调用相应节点的访问操作。当访问到包含需要解释器的元素节点时,则会启动解释器做解释操作,根据Expression类型,调用getStringValue,并传入参数Environment,相应类型的表达式根据Environment解释得到输入字符串的值,返回并写到响应流,即解释完成。

freemarker内建函数介绍

Sequence的内置函数
1.sequence?first 返回sequence的第一个值。
2.sequence?last 返回sequence的最后一个值。
3.sequence?reverse 将sequence的现有顺序反转,即倒序排序
4.sequence?size 返回sequence的大小
5.sequence?sort 将sequence中的对象转化为字符串后顺序排序
6.sequence?sort_by(value) 按sequence中对象的属性value进行排序
注意:Sequence不能为null
Hash的内置函数
1.hash?keys 返回hash里的所有key,返回结果为sequence
2.hash?values 返回hash里的所有value,返回结果为sequence
操作字符串内置函数
1.substring(start,end)从一个字符串中截取子串
start:截取子串开始的索引,start必须大于等于0,小于等于end
end: 截取子串的长度,end必须大于等于0,小于等于字符串长度,如果省略该参数,默认为字符串长度。
2.cap_first 将字符串中的第一个单词的首字母变为大写。
3.uncap_first将字符串中的第一个单词的首字母变为小写。
4.capitalize将字符串中的所有单词的首字母变为大写
5.date,time,datetime将字符串转换为日期
注意:如果指定的字符串格式不正确将引发错误
6.ends_with 判断某个字符串是否由某个子串结尾,返回布尔值
注意:布尔值必须转换为字符串才能输出
7.html 用于将字符串中的<、>、&和"替换为对应得<>&quot:&amp
8.index_of(substring,start)在字符串中查找某个子串,返回找到子串的第一个字符的索引,如果没有找到子串,则返回-1。
Start参数用于指定从字符串的那个索引处开始搜索,start为数字值。
如果start大于字符串长度,则start取值等于字符串长度,如果start小于0,则start取值为0。
9.length返回字符串的长度
10.lower_case将字符串转为小写
11.upper_case将字符串转为大写
12.contains 判断字符中是否包含某个子串。返回布尔值
注意:布尔值必须转换为字符串才能输出
13.number将字符串转换为数字
14.replace用于将字符串中的一部分从左到右替换为另外的字符串。
15.split使用指定的分隔符将一个字符串拆分为一组字符串
16.trim 删除字符串首尾空格
操作数字内置函数
1.c 用于将数字转换为字符串
2.string用于将数字转换为字符串
Freemarker中预订义了三种数字格式:number,currency(货币)和percent(百分比)其中number为默认的数字格式转换
操作布尔值内置函数
string用于将布尔值转换为字符串输出
true转为"true",false转换为"false"
foo?string("yes","no")如果布尔值是true,那么返回"yes",否则返回no

freemarker日志实现过程分析

freemarker有自己的log类,这是一个抽象类,具体的日志打印委托给classpath里面合适的日志jar包来执行,寻找合适日志jar的查找顺序是:Apache Log4J, Apache Avalon LogKit, JDK log。如果一个合适的日志实现类都没有找到,日志功能将被抑制,并会使用System.err打印出错误提示信息。
如果我们想自己指定使用的日志类型,那么可以通过:
Loger.selectLoggerLibrary(int library);
注意:一定要在freemarker初始化阶段进行设置,在调用任何freemarker api之前进行设置,否则freemarker将会与默认的日志实现进行绑定,从而自己指定的日志修改将不会起到作用。

Freemarker中大于号>的使用

在Freemarker中,比较数据的大小时候,要注意大于号(>)的使用。如果不注意,程序就会发生异常信息,如下面的例子:

1

2

3

4

<#assign x = 4>

<#if x>5 >

x >5

</#if>

以上的方式进行比较,就会发生异常,原因是Freemarker内部的解析处理原因,x>5中的大于号将会跟<#if中的小于号进行配对,导致解析出现问题。针对这种情况,有两种方式解决:
方法一:加上括号。

1

2

3

4

<#assign x = 4>

<#if (x>5) >

x > 5

</#if>

方法二:使用gt符号。

1

2

3

4

<#assign x = 4>

<#if x gt 5 >

x > 5

</#if>

总结一下:

使用>=和>的时候有一点小问题。FreeMarker解释>的时候可以把它当作FTL标签的结束符。为了避免这种问题,不得不将表达式放到括号内:<#if (x > y) >,另外,可以使用lt代替<,lte代替<=,gt代替>,gte代替>=。由于历史遗留的原因,FTL也支持\lt,\lte,\gt和\gte,使用他们和使用不带反斜杠的效果一样。

序列的重点知识小结

(1)序列的默认值为[],看下面的例子:

<#if (winnersList![])?size gt 0>
    <table class="winner_table" border="0" cellspacing="0" cellpadding="0">
        <tr>
            <th class="bdr_gray">中奖账号</th>
            <th>猜测差值</th>
        </tr>
    <#list winnersList as list>
        <tr>
            <td class="bdr_gray">${list.accountId!""}</td>
            <td>${list.deviation!""}</td>
        </tr>
    </#list>
    </table>
</#if>
说明:在上面例子中,winnersList默认为[],它的内建函数为size

(2)序列的连接:

可以将两个序列连接成一个新的序列,连接序列的运算符是‘+‘,见下面的例子:
<#list ["一","二","三"] + ["四","五","六"] as x>
    ${x}
</#list>
输出结果如下:
一二三四五六

(3)序列的切分:

举个例子看序列的切分应用场景:有的时候我们在页面中不需要显示那么长的字符串,比如新闻标题,这样用下面的例子就可以自定义显示的长度
<#if title.content?length lt 8>
           <a href>${title.content?default("")}</a>
      <#else>
           <a href title="${title.content}">${title.content[0..3]?default("")}</a>
</#if>
上面例子的作用是:如果这个字符串的长度小于8,那么就正常显示,反之则取4位。
序列的切分要注意下面两点:
从FreeMarker 2.3.3版本以后lastindex才能省略。
如果试图访问一个序列首变量之前的项或末变量之后的项将会引起错误,模板的执行也会中断。

(4)子序列的定义:

序列中的项是表达式,那么也可以这样做:[2 + 2, [1, 2, 3, 4], "what"],其中第一个子变量是数字4,第二个子变量是一个序列,第三个子变量是字符串"what"。

(5)数字序列的定义:

第一种定义序列的方式:
<#assign nums=[1,2,3,4,5,77,8,99]/>
使用list指令将序列输出,
<#list nums as num>
   ${num}
</#list>
第二种定义序列的方式
定义了一个连续的序列,
<#assign nums=12..99/>
这种方式定义的序列的内容是12到99
说明:
从上面的例子可以看出,序列也可以用start..end定义存储数字范围的序列,这里的start和end是处理数字值表达式,比如2..5和[2, 3, 4, 5]是相同的,但是使用前者会更有效率(内存占用少而且速度快)。可以看出前者也没有使用方括号,这样也可以用来定义递减的数字范围,比如5..2。(此外,还可以省略end,只需5..即可,但这样序列默认包含5,6,7,8等递增量直到无穷大)。

(6)判断序列是否包含某个元素

如果要判断序列中是否包含某个指定的元素,可以使用序列的内建函数seq_contains。
注:seq_contains这个内建函数从FreeMarker 2.3.1 版本开始可用。而在2.3 版本中不存在。
<#--声明一个序列,包含若干个元素-->
<#assign x = ["red", 16, "blue", "cyan"]>
<#--使用seq_contains判断序列中的元素是否存在-->
"blue": ${x?seq_contains("blue")?string("yes", "no")}
"yellow": ${x?seq_contains("yellow")?string("yes", "no")}
16: ${x?seq_contains(16)?string("yes", "no")}
"16": ${x?seq_contains("16")?string("yes", "no")}
输出结果:
"blue": yes
"yellow": no
16: yes
"16": no
附:seq_前缀在这个内建函数中是需要的,用来和contains 区分开。contains函数用来在字符串中查找子串(因为变量可以同时当作字符串和序列)。

StringTemplateLoader的用法

作为一个模板框架,freemarker的功能还是很强大的。在模板处理方面,freemarker有多种形式,最常见的方式是将模板文件放在一个统一的文件夹下面,如下形式:
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(new File("templates"));
如果我想把模板存放到数据库中,可以实现吗?答案是肯定的。在这里可以使用StringTemplateLoader来加载模板内容。主要的代码实现如下所示:
Configuration cfg = new Configuration(); 
StringTemplateLoader stringLoader = new StringTemplateLoader();  
String templateContent="hello ${name}!";  
stringLoader.putTemplate("myTemplate",templateContent);  
cfg.setTemplateLoader(stringLoader);  
Template template = cfg.getTemplate("myTemplate","utf-8");

freemarker报错的处理方案

freemarker文件如果出错,网站的前台页面会报出很明显的错误-焦黄的背景,血红的文字,很不利于用户体验的。如何修改这个问题呢?
首先需要在struts.xml配置文件里添加下面一行代码:

1

<constant name="struts.freemarker.manager.classname" value="net.swiftlet.freemarker.MyFreemarkerManager" />

接着新建MyFreemarkerManager类,如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public class MyFreemarkerManager extends org.apache.struts2.views.freemarker.FreemarkerManager

{

private static final Logger LOG = LoggerFactory.getLogger(MyFreemarkerManager.class);

public void init(ServletContext servletContext) throws TemplateException

{

config = createConfiguration(servletContext);

config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);

contentType = DEFAULT_CONTENT_TYPE;

wrapper = createObjectWrapper(servletContext);

if (LOG.isDebugEnabled())

{

LOG.debug("Using object wrapper of class " + wrapper.getClass().getName());

}

config.setObjectWrapper(wrapper);

templatePath = servletContext.getInitParameter(INITPARAM_TEMPLATE_PATH);

if (templatePath == null)

{

templatePath = servletContext.getInitParameter("templatePath");

}

configureTemplateLoader(createTemplateLoader(servletContext, templatePath));

loadSettings(servletContext);

}

}

时间: 2024-12-13 14:09:56

Freemarker常用技巧(三)的相关文章

Linux Shell常用技巧(三) sed

Linux Shell常用技巧(三) sed 八.流编辑器sed 8.1 sed简介 sed是stream editor的缩写,一种流编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为"模式空间"(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕.接着处理下一行,这样不断重复,直到文件末尾.文件内容并没有 改变,除非你使用重定向存储输出.sed主要用来自动编辑一个或多个文件,简化对文件的反复操作,编写转换程序等

Linux Shell常用技巧(三)

八. 流编辑器sed: sed一次处理一行文件并把输出送往屏幕.sed把当前处理的行存储在临时缓冲区中,称为模式空间(pattern space).一旦sed完成对模式空间中的行的处理,模式空间中的行就被送往屏幕.行被处理完成之后,就被移出模式空间,程序接着读入下一行,处理,显示,移出......文件输入的最后一行被处理完以后sed结束.通过存储每一行在临时缓冲区,然后在缓冲区中操作该行,保证了原始文件不会被破坏.        1.  sed的命令和选项: 命令 功能描述 a\  在当前行的后

Freemarker常用技巧

1,截取字符串 有的时候我们在页面中不需要显示那么长的字符串,比如新闻标题,这样用下面的例子就可以自定义显示的长度 < lt. <= lte. > gt. >= gte <#if jstbqkVO.gzdd?length lt 8> <a href>${jstbqkVO.gzdd?default("")}</a> <#else> <a href title="${jstbqkVO.gzdd}&quo

Freemarker常用技巧(一)

1 截取字符串有的时候我们在页面中不需要显示那么长的字符串,比如新闻标题,这样用下面的例子就可以自定义显示的长度<#if title.content?length lt 8>           <a href>${title.content?default("")}</a>      <#else>           <a href title="${title.content}">${title.co

Freemarker常用技巧(二)

1 list.break指令<#list sequence as item>  ...</#list>tem_index:当前变量的索引值.item_has_next:是否存在下一个对象.<#list ["星期一","星期二","星期三","星期四","星期五","星期六"] as x>${x_index + 1}.${x}<#if x_has_

Linux Shell常用技巧(目录)

Linux Shell常用技巧(一) http://www.cnblogs.com/stephen-liu74/archive/2011/11/10/2240461.html一. 特殊文件: /dev/null和/dev/tty二. 简单的命令跟踪三. 正则表达式基本语法描述四. 使用cut命令选定字段五. 计算行数.字数以及字符数六. 提取开头或结尾数行 Linux Shell常用技巧(二) http://www.cnblogs.com/stephen-liu74/archive/2011/1

Freemarker的常用技巧总结

Freemarker的常用技巧总结 1,截取字符串 有的时候我们在页面中不需要显示那么长的字符串,比如新闻标题,这样用下面的例子就可以自定义显示的长度 < lt. <= lte. > gt. >= gte <#if jstbqkVO.gzdd?length lt 8>            <a href>${jstbqkVO.gzdd?default("")}</a>       <#else>         

HTML5-移动开发常用技巧与弹性布局的使用

一.移动开发常用技巧 Viewport基本知识 设置布局Viewport的各种信息 1.width=device-width: 设置Viewport视口宽度等于设备宽度 2.initial-scale=1: 网页默认缩放比为1(网页在手持设备上,不会进行默认缩放 3.minimum-scale=1 网页最小缩放比为1 4.maximum-scale=1 网页最小大缩放比为1 5.user-scalable=no 禁止用户手动缩放网页(ios10+ 的设备失效) 在手机站及响应式网站的制作中,网页

【转】oracle存储过程常用技巧

原文链接 http://www.cnblogs.com/chinafine/archive/2010/07/12/1776102.html 我们在进行pl/sql编程时打交道最多的就是存储过程了.存储过程的结构是非常的简单的,我们在这里除了学习存储过程的基本结构外,还会学习编写存储过程时相关的一些实用的知识.如:游标的处理,异常的处理,集合的选择等等 1.存储过程结构 1.1 第一个存储过程 create or replace procedure proc1( p_para1 varchar2,