[img][/img]FreeMarke开发指南
1概念
2指令
if, else, elseif
switch, case, default, break
list, break
include
Import
compress
escape, noescape
assign
global
setting
macro, nested, return
t, lt, rt
3一些常用方法或注意事项
表达式转换类
数字循环
对浮点取整数
给变量默认值
判断对象是不是null
常用格式化日期
添加全局共享变量数据模型
直接调用java对象的方法
字符串处理(内置方法)
在模板里对sequences和hashes初始化
注释标志
sequences内置方法
hashes内置方法
4 freemarker在web开发中注意事项
web中常用的几个对象
view中值的搜索顺序
在模板里ftl里使用标签
如何初始化共享变量
与webwork整合配置
5高级方法
自定义方法
自定义 Transforms
1概念
最常用的3个概念
sequence 序列,对应java里的list、数组等非键值对的集合
hash 键值对的集合
namespace 对一个ftl文件的引用,利用这个名字可以访问到该ftl文件的资源
2指令
if, else, elseif
语法
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
...
<#else>
...
</#if>
用例
<#if x = 1>
x is 1
</#if>
<#if x = 1>
x is 1
<#else>
x is not 1
</#if>
switch, case, default, break
语法
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
用例
字符串
<#switch being.size>
<#case "small">
This will be processed if it is small
<#break>
<#case "medium">
This will be processed if it is medium
<#break>
<#case "large">
This will be processed if it is large
<#break>
<#default>
This will be processed if it is neither
</#switch>
数字
<#switch x>
<#case x = 1>
1
<#case x = 2>
2
<#default>
d
</#switch>
如果x=1 输出 1 2, x=2输出 2, x=3 输出d
list, break
语法
<#list sequence as item>
...
<#if item = "spring"><#break></#if>
...
</#list>
关键字
item_index:是list当前值的下标
item_has_next:判断list是否还有值
用例
<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>
输出
1. winter,
2. spring,
3. summer,
4. autumn
include
语法
<#include filename>
or
<#include filename options>
options包含两个属性
encoding=”GBK” 编码格式
parse=true 是否作为ftl语法解析,默认是true,false就是以文本方式引入.注意在ftl文件里布尔值都是直接赋值的如parse=true,而不是parse=”true”
用例
/common/copyright.ftl包含内容
Copyright 2001-2002 ${me}<br>
All rights reserved.
模板文件
<#assign me = "Juila Smith">
<h1>Some test</h1>
<p>Yeah.
<hr>
<#include "/common/copyright.ftl" encoding=”GBK”>
输出结果
<h1>Some test</h1>
<p>Yeah.
<hr>
Copyright 2001-2002 Juila Smith
All rights reserved.
Import
语法
<#import path as hash>
类似于java里的import,它导入文件,然后就可以在当前文件里使用被导入文件里的宏组件
用例
假设mylib.ftl里定义了宏copyright那么我们在其他模板页面里可以这样使用
<#import "/libs/mylib.ftl" as my>
<@my.copyright date="1999-2002"/>
"my"在freemarker里被称作namespace
compress
语法
<#compress>
...
</#compress>
用来压缩空白空间和空白的行
用例
<#assign x = " moo \n\n ">
(<#compress>
1 2 3 4 5
${moo}
test only
I said, test only
</#compress>)
输出
(1 2 3 4 5
moo
test only
I said, test only)
escape, noescape
语法
<#escape identifier as expression>
...
<#noescape>...</#noescape>
...
</#escape>
用例
主要使用在相似的字符串变量输出,比如某一个模块的所有字符串输出都必须是html安全的,这个时候就可以使用该表达式
<#escape x as x?html>
First name: ${firstName}
<#noescape>Last name: ${lastName}</#noescape>
Maiden name: ${maidenName}
</#escape>
相同表达式
First name: ${firstName?html}
Last name: ${lastName }
Maiden name: ${maidenName?html}
assign
语法
<#assign name=value>
or
<#assign name1=value1 name2=value2 ... nameN=valueN>
or
<#assign same as above... in namespacehash>
or
<#assign name>
capture this
</#assign>
or
<#assign name in namespacehash>
capture this
</#assign>
用例
生成变量,并且给变量赋值
给seasons赋予序列值
<#assign seasons = ["winter", "spring", "summer", "autumn"]>
给变量test加1
<#assign test = test + 1>
给my namespage 赋予一个变量bgColor,下面可以通过my.bgColor来访问这个变量
<#import "/mylib.ftl" as my>
<#assign bgColor="red" in my>
将一段输出的文本作为变量保存在x里
下面的阴影部分输出的文本将被赋值给x
<#assign x>
<#list 1..3 as n>
${n} <@myMacro />
</#list>
</#assign>
Number of words: ${x?word_list?size}
${x}
<#assign x>Hello ${user}!</#assign> error
<#assign x=” Hello ${user}!”> true
同时也支持中文赋值,如:
<#assign 语法>
java
</#assign>
${语法}
打印输出:
java
global
语法
<#global name=value>
or
<#global name1=value1 name2=value2 ... nameN=valueN>
or
<#global name>
capture this
</#global>
全局赋值语法,利用这个语法给变量赋值,那么这个变量在所有的namespace中是可见的,如果这个变量被当前的assign语法覆盖 如<#global x=2> <#assign x=1> 在当前页面里x=2将被隐藏,或者通过${.global.x}来访问
setting
语法
<#setting name=value>
用来设置整个系统的一个环境
locale
number_format
boolean_format
date_format, time_format, datetime_format
time_zone
classic_compatible
用例
假如当前是匈牙利的设置,然后修改成美国
${1.2}
<#setting locale="en_US">
${1.2}
输出
1,2
1.2
因为匈牙利是采用“,”作为十进制的分隔符,美国是用“.”
macro, nested, return
语法
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>
用例
<#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"/>
输出
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
定义循环输出的宏
<#macro list title items>
<p>${title?cap_first}:
<ul>
<#list items as x>
<li>${x?cap_first}
</#list>
</ul>
</#macro>
<@list items=["mouse", "elephant", "python"] title="Animals"/>
输出结果
<p>Animals:
<ul>
<li>Mouse
<li>Elephant
<li>Python
</ul>
包含body的宏
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4 ; c halfc last>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
输出
1. 0.5
2. 1
3. 1.5
4. 2 Last!
t, lt, rt
语法
<#t> 去掉左右空白和回车换行
<#lt>去掉左边空白和回车换行
<#rt>去掉右边空白和回车换行
<#nt>取消上面的效果
3一些常用方法或注意事项
表达式转换类
${expression}计算expression并输出
#{ expression }数字计算#{ expression ;format}安格式输出数字format为M和m
M表示小数点后最多的位数,m表示小数点后最少的位数如#{121.2322;m2M2}输出121.23
数字循环
1..5 表示从1到5,原型number..number
对浮点取整数
${123.23?int} 输出123
给变量默认值
${var?default(“hello world<br>”)?html}如果var is null那么将会被hello world<br>替代
判断对象是不是null
<#if mouse?exists>
Mouse found
<#else>
也可以直接${mouse?if_exists})输出布尔形
常用格式化日期
openingTime必须是Date型,详细查看freemarker文档 Reference->build-in referece->build-in for date
${openingTime?date}
${openingTime?date_time}
${openingTime?time}
添加全局共享变量数据模型
在代码里的实现
cfg = Configuration.getDefaultConfiguration();
cfg.setSharedVariable("global", "you good");
页面实现可以通过global指令,具体查看指令里的global部分
直接调用java对象的方法
${object.methed(args)}
字符串处理(内置方法)
html安全输出
“abc<table>sdfsf”?html
返回安全的html输出,替换掉html代码
xml安全输出
var?xml
substring的用法
<#assign user=”hello jeen”>
${user[0]}${user[4]}
${user[1..4]}
输出 :
ho
ello
类似String.split的用法
“abc;def;ghi”?split(“;”)返回sequence
将字符串按空格转化成sequence,然后取sequence的长度
var?word_list 效果同 var?split(“ ”)
var?word_list?size
取得字符串长度
var?length
大写输出字符
var?upper_case
小写输出字符
var?lower_case
首字符大写
var?cap_first
首字符小写
var?uncap_first
去掉字符串前后空格
var?trim
每个单词的首字符大写
var?capitalize
类似String.indexof:
“babcdabcd”?index_of(“abc”) 返回1
“babcdabcd”?index_of(“abc”,2) 返回5
类似String.lastIndexOf
last_index_of和String.lastIndexOf类似,同上
下面两个可能在代码生成的时候使用(在引号前加”\”)
j_string: 在字符串引号前加”\”
<#assign beanName = 'The "foo" bean.'>
String BEAN_NAME = "${beanName?j_string}";
打印输出:
String BEAN_NAME = "The \"foo\" bean.";
js_string:
<#assign user = "Big Joe's \"right hand\".">
<script>
alert("Welcome ${user}!");
</script>
打印输出
alert("Welcome Big Joe\'s \"right hand\"!");
替换字符串 replace
${s?replace(‘ba’, ‘XY’ )}
${s?replace(‘ba’, ‘XY’ , ‘规则参数’)}将s里的所有的ba替换成xy 规则参数包含: i r m s c f 具体含义如下:
• i: 大小写不区分.
• f: 只替换第一个出现被替换字符串的字符串
• r: XY是正则表达式
• m: Multi-line mode for regular expressions. In multi-line mode the expressions ^ and $ match just after or just before, respectively, a line terminator or the end of the string. By default these expressions only match at the beginning and the end of the entire string.
• s: Enables dotall mode for regular expressions (same as Perl singe-line mode). In dotall mode, the expression . matches any character, including a line terminator. By default this expression does not match line terminators.
• c: Permits whitespace and comments in regular expressions.
在模板里对sequences和hashes初始化
sequences
1. [“you”,”me”,”he”]
2. 1..100
3. [ {“Akey”:”Avalue”},{“Akey1”:”Avalue1”},
{“Bkey”:”Bvalue”},{“Bkey1”:”Bvalue1”},
]
hashes {“you”:”a”,”me”:”b”,”he”:”c”}
注释标志
<#--
这里是注释
-->
旧版本的freemarker采用的是<#comment> 注释 </#comment>方法
sequences内置方法
sequence?first
返回sequence的第一个值;前提条件sequence不能是null
sequence?last
返回sequence最后一个值
sequence?reverse
反转sequence的值
sequence?size
返回sequence的大小
sequence?sort
对sequence按里面的对象toString()的结果进行排序
sequence?sort_by(value)
对sequence 按里面的对象的属性value进行排序
如: sequence里面放入的是10 个user对象,user对象里面包含name,age等属性
sequence?sort_by(name) 表示所有的user按user.name进行排序
hashes内置方法
hash?keys
返回hash里的所有keys, 返回结果类型sequence
hash?values
返回hash里的所有value, 返回结果类型sequence
4 freemarker在web开发中注意事项
freemarker与webwork整合
web中常用的几个对象
Freemarker的ftl文件中直接使用内部对象:
${Request ["a"]}
${RequestParameters["a"]}
${Session ["a"]}
${Application ["a"]}
${JspTaglibs ["a"]}
与webwork整合之后 通过配置的servlet 已经把request,session等对象置入了数据模型中
在view中存在下面的对象
我们可以在ftl中${req}来打印req对象
• req - the current HttpServletRequest
• res - the current HttpServletResponse
• stack - the current OgnlValueStack
• ognl - the OgnlTool instance
• webwork - an instance of FreemarkerWebWorkUtil
• action - the current WebWork action
• exception - optional the Exception instance, if the view is a JSP exception or Servlet exception view
view中值的搜索顺序
${name}将会以下面的顺序查找name值
• freemarker variables
• value stack
• request attributes
• session attributes
• servlet context attributes
在模板里ftl里使用标签
注意,如果标签的属性值是数字,那么必须采用nubmer=123方式给属性赋值
JSP页面
<%@page contentType="text/html;charset=ISO-8859-2" language="java"%>
<%@taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<html>
<body>
<h1><bean:message key="welcome.title"/></h1>
<html:errors/>
<html:form action="/query">
Keyword: <html:text property="keyword"/><br>
Exclude: <html:text property="exclude"/><br>
<html:submit value="Send"/>
</html:form>
</body>
</html>
模板ftl页面
<#assign html=JspTaglibs["/WEB-INF/struts-html.tld"]>
<#assign bean=JspTaglibs["/WEB-INF/struts-bean.tld"]>
<html>
<body>
<h1><@bean.message key="welcome.title"/></h1>
<@html.errors/>
<@html.form action="/query">
Keyword: <@html.text property="keyword"/><br>
Exclude: <@html.text property="exclude"/><br>
<@html.submit value="Send"/>
</@html.form>
</body>
</html>
如何初始化共享变量
1. 初始化全局共享数据模型
freemark在web上使用的时候对共享数据的初始化支持的不够,不能在配置初始化的时候实现,而必须通过ftl文件来初始化全局变量。这是不能满主需求的,我们需要在servlet init的时候留出一个接口来初始化系统的共享数据
具体到和webwork整合,因为本身webwork提供了整合servlet,如果要增加全局共享变量,可以通过修改com.opensymphony.webwork.views.freemarker.FreemarkerServlet来实现,我们可以在这个servlet初始化的时候来初始化全局共享变量
与webwork整合配置
配置web.xml
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>com.opensymphony.webwork.views.freemarker.FreemarkerServlet</servlet-class>
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
<!—模板载入文件夹,这里相对context root,递归获取该文件夹下的所有模板-->
</init-param>
<init-param>
<param-name>NoCache</param-name> <!—是否对模板缓存-->
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>ContentType</param-name>
<param-value>text/html</param-value>
</init-param>
<init-param>
<param-name>template_update_delay</param-name>
<!—模板更新时间,0表示每次都更新,这个适合开发时候-->
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>default_encoding</param-name>
<param-value>GBK</param-value>
</init-param>
<init-param>
<param-name>number_format</param-name>
<param-value>0.##########</param-value><!—数字显示格式-->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
5高级方法
自定义方法
${timer("yyyy-MM-dd H:mm:ss", x)}
${timer("yyyy-MM-dd ", x)}
在模板中除了可以通过对象来调用方法外(${object.methed(args)})也可以直接调用java实现的方法,java类必须实现接口TemplateMethodModel的方法exec(List args). 下面以把毫秒的时间转换成按格式输出的时间为例子
public class LongToDate implements TemplateMethodModel {
public TemplateModel exec(List args) throws TemplateModelException {
SimpleDateFormat mydate = new SimpleDateFormat((String) args.get(0)));
return mydate.format(new Date(Long.parseLong((String)args.get(1)));
}
}
将LongToDate对象放入到数据模型中
root.put("timer", new IndexOfMethod());
ftl模板里使用
<#assign x = "123112455445">
${timer("yyyy-MM-dd H:mm:ss", x)}
${timer("yyyy-MM-dd ", x)}
输出
2001-10-12 5:21:12
2001-10-12
自定义 Transforms
实现自定义的<@transform>文本或表达式</@transform>的功能,允许对中间的最终文本进行解析转换
例子:实现<@upcase>str</@upcase> 将str转换成STR 的功能
代码如下:
import java.io.*;
import java.util.*;
import freemarker.template.TemplateTransformModel;
class UpperCaseTransform implements TemplateTransformModel {
public Writer getWriter(Writer out, Map args) {
return new UpperCaseWriter(out);
}
private class UpperCaseWriter extends Writer {
private Writer out;
UpperCaseWriter (Writer out) {
this.out = out;
}
public void write(char[] cbuf, int off, int len)
throws IOException {
out.write(new String(cbuf, off, len).toUpperCase());
}
public void flush() throws IOException {
out.flush();
}
public void close() {
}
}
}
然后将此对象put到数据模型中
root.put("upcase", new UpperCaseTransform());
在view(ftl)页面中可以如下方式使用
<@upcase>
hello world
</@upcase>
打印输出:
HELLO WORLD
FreeMarker2.3
一 介绍 2
二 HelloWorld 3
1 java应用程序中 3
1.1 aa.ftl---------模板文件 3
1.2 FreeMarkerTest调用模板及使用方法 3
1.3 FreeMarkerTest.java----------调用freeMarker的测试程序 4
2 web应用程序 7
1.1 web与java应用程序的区别在于: 7
1.2 完整代码 7
3 读XML数据源----- java应用程序中 9
三 语法 10
1 常用 10
1.1 ${ varName!" value"}---------指定缺省值 10
1.2 <#-- aaaaaaaa --> 注释 10
1.3 条件语句 <#if condition><#elseif condition><#else></#if> 10
1.4 变量定义 <#assign varName=value> 11
1.5 <#local var = value> 在 macro 或者 function 中定义局部变量并初始化 11
1.6 <#global var = value > 定义全局变量并初始化 11
1.7 序列 [item1,item2,item3,…] 11
1.8 list-----遍历指令 11
1.9 条件分支 <#switch 条件> <#case "值n" > <#default></#switch> 12
1.10 key:value, key2:value2 ...} 直接定义一个hash表 12
1.11 macro-----宏 12
1.12 <#nested>-----FreeMarker个性十足的指令 13
1.13 function-------函数 14
1.14 内部函数调用---------由问号、函数名与实参构成 14
四 常用函数 15
1 字符串 15
1.1 取子串--substirng 15
1.2 第一个字母大写-------cap_first 15
1.3 第一个字母不大写-----uncap_first 15
1.4 以空格间格的字符串,第一个字母大写--------capitalize 15
1.5 日期、时间函数---------date, time, datetime 15
1.6 html-----把字符串转成html传输的格式 16
1.7 index_of--------求字串在原串中的位置 16
1.8 j_string--------把空格替换成左斜线 16
1.9 js_string--------把左斜线换成 空格 16
1.10 其他字符串函数 16
2 数字 16
1.1 带常见单位的数字 16
1.2 格式化数字 16
1.3 其他函数round, floor, ceiling 17
3 日期 17
一 介绍
FreeMarker是一个文本文件模板。
文本文件中,设定特定字符串,FreeMarker会把用户指定的数据,按规定替代这些字符串,从而产生新的文件,或流数据。
例:有文本文件-------a.ftl 如下:
你好!${userName}
用户把“张三”数据放入FreeMarker中,FreeMarker将会产生新的文件,其内容会变成:
你好!张三!
作用:
非常 精致强悍,可生成网页、生成java文件、.net文件,总之任何格式的文本文件。
当然,模板文件要按这些格式书写!
说明:
(1) FreeMarker的数据源:
--------来自xml文件,或
-------- 用Map作为基本的存储单元;且必须是树结构。
(2) 官方网址
FreeMarker是开源的;官方网址http://freemarker.org/
二 HelloWorld
1 java应用程序中
1.1 aa.ftl---------模板文件
<html>
<head>
<title>Welcome!</title>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
</head>
<body>
<h1>Welcome ${user}!</h1>
</body>
</html>
说明:
${user}-----是freemarker指令。意思用 user所存数据对它进行替换。
user所存数据-----放在数据源中。
Freemarker----是模板,程序,数据相分离。
1.2 FreeMarkerTest调用模板及使用方法
下面是加载模板文件
Configuration cfg = new Configuration();
cfg.setEncoding(Locale.getDefault(),"UTF-8");
// 指定模板文件的数据源,这里是一个文件目录。
cfg.setDirectoryForTemplateLoading( new File("d:\\aaa") );
cfg.setObjectWrapper(new DefaultObjectWrapper()); //这条语句可省略
//加载文件,模板文件,输出文件都要保证用UTF-8-----解决乱码
Template template = cfg.getTemplate("aa.ftl");//加载模板文件
下面是使用方法
template.setEncoding("UTF-8");
File htmlFile = new File("t.html");
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(htmlFile), "UTF-8"));//输出文件
HashMap propMap = new HashMap();//定义Map树结构数据源
propMap.put("user", "张三");
template.process(propMap, out);
注意:加载文件,模板文件,输出文件都要保证用UTF-8-----解决乱码
Configuration. setEncoding//要在Configuration对象后就要加入
template.setEncoding("UTF-8")
OutputStreamWriter(new FileOutputStream(htmlFile), "UTF-8")
1.3 FreeMarkerTest.java----------调用freeMarker的测试程序
package jap1;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Locale;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class FreeMarkerTest {
public static void main(String[] args) throws IOException {
FreeMarkerTest test = new FreeMarkerTest();
test.getFile();
test.getFile(Locale.CHINA);
}
private String basePath;
public String getBasePath() {
return basePath;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
}
public FreeMarkerTest(){
basePath="";
}
public FreeMarkerTest(String basePath ){
this.basePath=basePath;
}
public void getFile() throws IOException {
Configuration cfg = new Configuration();//加载FreeMarker配置文件
if (basePath.equals("")){
//设本类运行时所在的路径为路劲
cfg.setClassForTemplateLoading(this.getClass(),"/");
} else{
//设用户指定路径为基路径
cfg.setDirectoryForTemplateLoading(new File(basePath));
}
cfg.setEncoding(Locale.getDefault(),"UTF-8");
Template template;
try {
template = cfg.getTemplate("aa.ftl");
template.setEncoding("UTF-8");
File htmlFile = new File("t.html");
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(htmlFile), "UTF-8"));
HashMap propMap = new HashMap();
propMap.put("user", "张三");
template.process(propMap, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//FreeMarker国际化支持,
public void getFile(Locale loc) {
Configuration cfg = new Configuration();
cfg.setClassForTemplateLoading(this.getClass(),"/");
cfg.setEncoding(Locale.getDefault(),"UTF-8");
Template template;
try {
template = cfg.getTemplate("aa.ftl",loc);
template.setEncoding("UTF-8");
String fileName="t_"+loc.getLanguage()+"_"
+loc.getCountry()+".html";
File htmlFile = new File(fileName);
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(htmlFile), "UTF-8"));
HashMap propMap = new HashMap();
propMap.put("user", "张三");
template.process(propMap, out);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2 web应用程序
1.1 web与java应用程序的区别在于:
(1) 配置类的路径指定:
有两种方式: (在web程序中)
A 模板文件在web中。针对servlet.。
下例的表示模板文件位于WEB-INF的子文件a中。
configuration.setServletContextForTemplateLoading(
getServletContext(), "WEB-INF/a");
B 模板文件在class中。
下像表示模板文件在src\java下。注:在netbeans6.5中调试。
configuration.setObjectWrapper(new DefaultObjectWrapper());
configuration.setTemplateLoader(new ClassTemplateLoader(
NewServlet1.class, "/"));
(2) 文件输出
web文件用response对象输出文件。或用像StringWriter之类的对象输出 。
1.2 完整代码
(1) 模板文件---------test.ftl-----------位于web /web-inf/a
<body>
sdad描述信息是 : ${message}
</body>
(2) NewServlet1.java---------调用FreeMarker把模板输出到浏览器中。
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.util.Locale;
import javax.servlet.http.HttpServlet;
public class NewServlet1 extends HttpServlet {
private Configuration configuration;
public NewServlet1() {
super();
}
@Override
public void destroy() {
configuration = null;
}
@Override
public void init() throws ServletException {
configuration = new Configuration();
configuration.setEncoding(Locale.getDefault(),"UTF-8");
configuration.setServletContextForTemplateLoading(
getServletContext(), "WEB-INF/a");
// configuration.setObjectWrapper(new DefaultObjectWrapper());
// configuration.setTemplateLoader(new ClassTemplateLoader(
// NewServlet1.class, "/"));
}
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
Map root = new HashMap();
root.put("message", "Hello World!帅哥,靓女!");
Template t = configuration.getTemplate("test.ftl");
Writer out = response.getWriter();
try {
t.process(root, out);
StringWriter stringWriter = new StringWriter();
t.process(root, stringWriter);
System.out.println(stringWriter.toString());
} catch (TemplateException e) {
throw new ServletException(
"Error while processing FreeMarker template", e);
}
}
}
注意:
1 configuration.setEncoding(Locale.getDefault(),"UTF-8");
要紧随configuration生成设置;否则,模板中的中文会成乱码。
2 response.setContentType("text/html;charset=UTF-8");
这句不设置;输进模板中的数据,将有可能是乱码。
3 读XML数据源----- java应用程序中
FreeMark2.3支持 XML;在程序中可直接把xml文件作为数据模型,按用户模板文件的要求,输出相应的文件(或流)给用户。
与前面相比,关键有:
1 freemarker.ext.dom.NodeModel.parse这个方法将把xml文件处理成map树状结构的模型;该方法支持以File对象,读xml;也提供了一个流适配器,从面能用InsputStream流对象读xml文件。
2 Map root = new HashMap();
root.put("doc", freemarker.ext.dom.NodeModel.parse( ins));
这里要注意:经处理后:”doc”,在数据模型中是根;而xml文件的根是它的子节点;
在读数据时,要从doc开始,否则出错。当然,”doc”也可改成其他名字。
3 增加了一个recurse指令。
FreeMarker这样处理的xml结构的数据模型的:
(1) 按层定义宏;宏名---就是节点名。(这是强行约定的)
(2) recurse----将循环调用处理子节点的宏
下面是在java应用程序中,应用freemarker的示例:
(1) ddd.xml
注意:ddd.xml位于classpath下的jap1文件夹下,与下面的 FMtest.java的位置相同。在netbean开发环境中,位于 src\java\jsp1下。
<?xml version="1.0" encoding="UTF-8"?>
<root>
<user>
<name>张三1111</name>
</user>
<user>
<name>李四hhhh</name>
</user>
</root>
(2) FMTest.java -------应用freemarker的类
package jap1;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class FMTest {
public static void main(String[] args) throws Exception {
FMTest test=new FMTest();
test.getFile();
}
@SuppressWarnings("empty-statement")
public void getFile() throws IOException, TemplateException,
SAXException, ParserConfigurationException{
//得FreeMarker配置对象
Configuration cfg = new Configuration();
cfg.setEncoding(Locale.getDefault(), "UTF-8");
cfg.setClassForTemplateLoading(this.getClass(),"/jap1");
//得FreeMarker的关键对象---------模板
Template temp = cfg.getTemplate("test.ftl");
//得FMTest类运行时/jap1/ddd.xml的输入流文件,以便FreeMarker读出来
//注意:FMTest运行时,ddd.xml在工程打包的包中。Java强烈要求只能读包内
//文件。如果要得到运行的绝对路径,再用可写的流打包,java会严重抗议!
InputStream in =FMTest.class.getResourceAsStream("/jap1/ddd.xml");
//下面是FreeMarker的输入接口,这里与上面的in流建立关系,
//以便读取ddd.xml文件
InputSource ins=new org.xml.sax.InputSource(in);
Map root = new HashMap();
//特别注意此时的doc,这个符号将是,FreeMarker模板中取数的根!!!!!
//这里读取xml文件,并处理成root对象
root.put("doc", freemarker.ext.dom.NodeModel.parse( ins));
//建立内存字符串流
java.io.StringWriter w =new StringWriter();
//模板开始按模板中的要求把用户输入的数据进行转换,并输出到字符串流中
temp.process(root, w);
//字符串流输出到屏幕
System.out.println(w.toString());
}
}
(3) test.ftl --------模板文件
测试单个读数操作-----${doc.root.user[0].name}
列表测试:
<#list doc.root.user as dd>
${dd.name}
</#list>
<#--recurse指令,按层读取整个xml节点,并循环调用处理这些节点的宏-->
<#recurse doc><#--root是doc的子节点,这里将循环调用<#marco root>宏 -->
读doc
<#macro root>
读root <#recurse><#--user是root的子节点,这里将循环调用<#marco user>宏 -->
</#macro>
<#macro user>
姓名:${.node.name};测试recurse指令,user
</#macro>
(4) 运行结果
测试单个读数操作-----张三1111
列表测试:
张三1111
李四hhhh
读root
姓名:张三1111;测试recurse指令,user
姓名:李四hhhh;测试recurse指令,user
读doc
三 语法
说明:大多数运算符号与java相同
算术加、减、乘、除运算:+、 -、 *、 /
逻辑 或 与 非:: || 、&& 、!
比较运算符-----大于、小于、小于等于、等于、不等于: >、< 、<=、= 或==、!=
或----大于、小于、小于等于: gt、lt、lte
子界:.. 例:1..5表示1到5
1 常用
${ varName }----------替换符
其中: ” varName” 是数据源中的变量名;作用,会用变量值,对该符号进行替换。
例: 假定数据源中 varName 值为“张三”
你好,${ varName } !
结果:你好,张三
补充: 数据源中变量访问形式:root开始,各部分用“.”分隔,到本变量名位置置。
如: aninmal 中有dog,dog下有名称。访问为”aninmal.dog.name”;中间是小数点间隔。
与java程序中,类对象对其属性的方法类似。
1.1 ${ varName!" value"}---------指定缺省值
当“varName”不存在时,用感叹号后中的字符替代。
例:假定varName的数据源中不存在:
你好,${useraa !""}!
结果为:你好,
1.2 <#-- aaaaaaaa --> 注释
1.3 条件语句 <#if condition><#elseif condition><#else></#if>
例:
<#if user="王五">
<#elseif user="李四">
<#else>
你好,${user !""}!
</#if>
1.4 变量定义 <#assign varName=value>
例:
<#assign seq ="上帝">
Oh,${seq !""}!
结果:Oh,上帝!
1.5 <#local var = value> 在 macro 或者 function 中定义局部变量并初始化
1.6 <#global var = value > 定义全局变量并初始化
1.7 序列 [item1,item2,item3,…]
1.8 list-----遍历指令
其中有两个内定变量:
item_index 遍历过程中,元素的索引值;
item_has_next: 逻辑变量,为false表时, 已经遍历到尾。
例:
<#assign seq = ["winter", "spring", "summer", "autumn"]>
${seq[0]}
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>
结果:
winter
1. winter,
2. spring,
3. summer,
4. autumn
1.9 条件分支 <#switch 条件> <#case "值n" > <#default></#switch>
例:
<#assign x =10>
<#switch x>
<#case 10 >
d
</#switch>
1.10 key:value, key2:value2 ...} 直接定义一个hash表
例:
<#assign ages = {"张三":23, "李四":25} + {"王二":30, "小李":18}>
- 张三 是 ${ages.张三}
- 王二 是 ${ages["王二"]}
结果:
- 张三 是 23
- 王二 是 30
1.11 macro-----宏
定义:
<@macro 宏名 形参1 形参2 >
指令n
</@macro>
调用:
<@宏名 实参1 实参n>
</@宏名>
或:<@宏名 实参1 实参n/>
例:
<#macro greet user>
<font size="+2">你好,${user}{</font>
</#macro>
<@greet "张三"/>
结果: <font size="+2">你好,张三{</font>
说明:
A 宏不调用,不执行
B 此时的宏,相当于java中无返回值的方法。
1.12 <#nested>-----FreeMarker个性十足的指令
这条指令,过性十足!要与宏配合使用,实现函数相互调用。
个性表现在:
<#nested> 与宏调用,又构成一个 ---------
方法定义 与方法调用的关系
1 出现<#nested>的地方,将由宏用的“<@宏名 实参1 实参n>” 与“</@宏名>”之间的值替代。
2 还可以传递参数。
宏调用:<@宏名 实参1 实参n; nested指令的形参1, nested指令的形参2>
被nested指令代替部份 以及 nested的实现部份
</@宏名>
宏定义中的形式为 nested:
<@nested 形参1,形参n>
其中:参数指------- 宏调用分号“;”后的参数
例1:
<#macro test>
<#nested >
<#nested >
</#macro>
<@test > 看nested指令调用我 </@test>
<@test > 看nested指令调用我111
</@test>
结果
看nested指令调用我 看nested指令调用我
看nested指令调用我
看nested指令调用我
例2
<#macro test>
<#nested 1,"张三">
<#nested 2,"李四" >
</#macro>
<@test;aa,user>
看 nested第${aa}次调用;这是${user};
------------------------------------------
真TMD好玩,老子调用你,你还反过来调用我!
</@test>
结果
看 nested第1次调用;这是张三;
------------------------------------------
真TMD好玩,老子调用你,你还反过来调用我!
看 nested第2次调用;这是李四;
------------------------------------------
真TMD好玩,老子调用你,你还反过来调用我!
1.13 function-------函数
与macro的区别是:它有返回值
定义:
<#function 函数名 形参1 参n>
<#return 返回值>
</#function
调用:
函数名 实参1 实参n
例:
1.14 内部函数调用---------由问号、函数名与实参构成
例:
<#assign x = 1.234>$
${x?string("0.####")}
结果:1.234
四 常用函数
说明:表格左边例,右边结果.
1 字符串
1.1 取子串--substirng
- ${'abc'?substring(0, 0)}
- ${'abc'?substring(0, 1)}
- ${'abc'?substring(0, 2)}
- ${'abc'?substring(0, 3)} -
- a
- ab
- abc
1.2 第一个字母大写-------cap_first
${" green mouse"?cap_first}
${"GreEN mouse"?cap_first}
${"- green mouse"?cap_first} Green mouse
GreEN mouse
- green mouse
1.3 第一个字母不大写-----uncap_first
1.4 以空格间格的字符串,第一个字母大写--------capitalize
${" green mouse"?capitalize}
${"GreEN mouse"?capitalize} Green Mouse
Green Mouse
1.5 日期、时间函数---------date, time, datetime
<#assign test1 = "10/25/1995"?date("MM/dd/yyyy")>
${test1}
<#assign test2 = "15:05:30"?time("HH:mm:ss")>
${test2}
<#assign test3 = "1995-10-25 22:05:10 "?datetime("yyyy-MM-dd hh:mm:ss")>
${test3} 1995-10-25
15:05:30
1995-10-25 22:05:10
1.6 html-----把字符串转成html传输的格式
1.7 index_of--------求字串在原串中的位置
${"ddabcabc"?index_of("bc")} 3
1.8 j_string--------把空格替换成左斜线
1.9 js_string--------把左斜线换成 空格
<#assign user = "Big Joe's \"right hand\"">
${user?js_string} Big Joe\'s \"right hand\"
1.10 其他字符串函数
length、 number、replace、split、trim、upper_case
2 数字
1.1 带常见单位的数字
<#assign x=42>
${x}
${x?string} <#-- the same as ${x} -->
${x?string.number}
${x?string.currency}
${x?string.percent}
${x?string.computer} 42
42
42
¥42.00
4,200%
42
1.2 格式化数字
<#assign x = 1.234>
${x?string("0")}
${x?string("0.####")}
${1?string("000.00")}
${12.1?string("000.00")}
${123.456?string("000.00")}
${2.7?string("0")} <-- 注意:全四舍五入 1
1.234
001.00
012.10
123.46
3 <-- 注意:全四舍五入
1.3 其他函数round, floor, ceiling
3 日期
${openingTime?string.short}
${openingTime?string.medium}
${openingTime?string.long}
${openingTime?string.full}
${nextDiscountDay?string.short}
${nextDiscountDay?string.medium}
${nextDiscountDay?string.long}
${nextDiscountDay?string.full}
${lastUpdated?string.short}
${lastUpdated?string.medium}
${lastUpdated?string.long}
${lastUpdated?string.full} ${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}
${lastUpdated?string("EEE, MMM d, ''yy")}
${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")
说明:左右两边都是示指令,都没有结果。官方的这个调试没通过,也懒得理了
1概念
2指令
if, else, elseif
switch, case, default, break
list, break
include
Import
compress
escape, noescape
assign
global
setting
macro, nested, return
t, lt, rt
3一些常用方法或注意事项
表达式转换类
数字循环
对浮点取整数
给变量默认值
判断对象是不是null
常用格式化日期
添加全局共享变量数据模型
直接调用java对象的方法
字符串处理(内置方法)
在模板里对sequences和hashes初始化
注释标志
sequences内置方法
hashes内置方法
4 freemarker在web开发中注意事项
web中常用的几个对象
view中值的搜索顺序
在模板里ftl里使用标签
如何初始化共享变量
与webwork整合配置
5高级方法
自定义方法
自定义 Transforms
1概念
最常用的3个概念
sequence 序列,对应java里的list、数组等非键值对的集合
hash 键值对的集合
namespace 对一个ftl文件的引用,利用这个名字可以访问到该ftl文件的资源
2指令
if, else, elseif
语法
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
...
<#else>
...
</#if>
用例
<#if x = 1>
x is 1
</#if>
<#if x = 1>
x is 1
<#else>
x is not 1
</#if>
switch, case, default, break
语法
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
用例
字符串
<#switch being.size>
<#case "small">
This will be processed if it is small
<#break>
<#case "medium">
This will be processed if it is medium
<#break>
<#case "large">
This will be processed if it is large
<#break>
<#default>
This will be processed if it is neither
</#switch>
数字
<#switch x>
<#case x = 1>
1
<#case x = 2>
2
<#default>
d
</#switch>
如果x=1 输出 1 2, x=2输出 2, x=3 输出d
list, break
语法
<#list sequence as item>
...
<#if item = "spring"><#break></#if>
...
</#list>
关键字
item_index:是list当前值的下标
item_has_next:判断list是否还有值
用例
<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>
输出
1. winter,
2. spring,
3. summer,
4. autumn
include
语法
<#include filename>
or
<#include filename options>
options包含两个属性
encoding=”GBK” 编码格式
parse=true 是否作为ftl语法解析,默认是true,false就是以文本方式引入.注意在ftl文件里布尔值都是直接赋值的如parse=true,而不是parse=”true”
用例
/common/copyright.ftl包含内容
Copyright 2001-2002 ${me}<br>
All rights reserved.
模板文件
<#assign me = "Juila Smith">
<h1>Some test</h1>
<p>Yeah.
<hr>
<#include "/common/copyright.ftl" encoding=”GBK”>
输出结果
<h1>Some test</h1>
<p>Yeah.
<hr>
Copyright 2001-2002 Juila Smith
All rights reserved.
Import
语法
<#import path as hash>
类似于java里的import,它导入文件,然后就可以在当前文件里使用被导入文件里的宏组件
用例
假设mylib.ftl里定义了宏copyright那么我们在其他模板页面里可以这样使用
<#import "/libs/mylib.ftl" as my>
<@my.copyright date="1999-2002"/>
"my"在freemarker里被称作namespace
compress
语法
<#compress>
...
</#compress>
用来压缩空白空间和空白的行
用例
<#assign x = " moo \n\n ">
(<#compress>
1 2 3 4 5
${moo}
test only
I said, test only
</#compress>)
输出
(1 2 3 4 5
moo
test only
I said, test only)
escape, noescape
语法
<#escape identifier as expression>
...
<#noescape>...</#noescape>
...
</#escape>
用例
主要使用在相似的字符串变量输出,比如某一个模块的所有字符串输出都必须是html安全的,这个时候就可以使用该表达式
<#escape x as x?html>
First name: ${firstName}
<#noescape>Last name: ${lastName}</#noescape>
Maiden name: ${maidenName}
</#escape>
相同表达式
First name: ${firstName?html}
Last name: ${lastName }
Maiden name: ${maidenName?html}
assign
语法
<#assign name=value>
or
<#assign name1=value1 name2=value2 ... nameN=valueN>
or
<#assign same as above... in namespacehash>
or
<#assign name>
capture this
</#assign>
or
<#assign name in namespacehash>
capture this
</#assign>
用例
生成变量,并且给变量赋值
给seasons赋予序列值
<#assign seasons = ["winter", "spring", "summer", "autumn"]>
给变量test加1
<#assign test = test + 1>
给my namespage 赋予一个变量bgColor,下面可以通过my.bgColor来访问这个变量
<#import "/mylib.ftl" as my>
<#assign bgColor="red" in my>
将一段输出的文本作为变量保存在x里
下面的阴影部分输出的文本将被赋值给x
<#assign x>
<#list 1..3 as n>
${n} <@myMacro />
</#list>
</#assign>
Number of words: ${x?word_list?size}
${x}
<#assign x>Hello ${user}!</#assign> error
<#assign x=” Hello ${user}!”> true
同时也支持中文赋值,如:
<#assign 语法>
java
</#assign>
${语法}
打印输出:
java
global
语法
<#global name=value>
or
<#global name1=value1 name2=value2 ... nameN=valueN>
or
<#global name>
capture this
</#global>
全局赋值语法,利用这个语法给变量赋值,那么这个变量在所有的namespace中是可见的,如果这个变量被当前的assign语法覆盖 如<#global x=2> <#assign x=1> 在当前页面里x=2将被隐藏,或者通过${.global.x}来访问
setting
语法
<#setting name=value>
用来设置整个系统的一个环境
locale
number_format
boolean_format
date_format, time_format, datetime_format
time_zone
classic_compatible
用例
假如当前是匈牙利的设置,然后修改成美国
${1.2}
<#setting locale="en_US">
${1.2}
输出
1,2
1.2
因为匈牙利是采用“,”作为十进制的分隔符,美国是用“.”
macro, nested, return
语法
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>
用例
<#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"/>
输出
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
定义循环输出的宏
<#macro list title items>
<p>${title?cap_first}:
<ul>
<#list items as x>
<li>${x?cap_first}
</#list>
</ul>
</#macro>
<@list items=["mouse", "elephant", "python"] title="Animals"/>
输出结果
<p>Animals:
<ul>
<li>Mouse
<li>Elephant
<li>Python
</ul>
包含body的宏
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4 ; c halfc last>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
输出
1. 0.5
2. 1
3. 1.5
4. 2 Last!
t, lt, rt
语法
<#t> 去掉左右空白和回车换行
<#lt>去掉左边空白和回车换行
<#rt>去掉右边空白和回车换行
<#nt>取消上面的效果
3一些常用方法或注意事项
表达式转换类
${expression}计算expression并输出
#{ expression }数字计算#{ expression ;format}安格式输出数字format为M和m
M表示小数点后最多的位数,m表示小数点后最少的位数如#{121.2322;m2M2}输出121.23
数字循环
1..5 表示从1到5,原型number..number
对浮点取整数
${123.23?int} 输出123
给变量默认值
${var?default(“hello world<br>”)?html}如果var is null那么将会被hello world<br>替代
判断对象是不是null
<#if mouse?exists>
Mouse found
<#else>
也可以直接${mouse?if_exists})输出布尔形
常用格式化日期
openingTime必须是Date型,详细查看freemarker文档 Reference->build-in referece->build-in for date
${openingTime?date}
${openingTime?date_time}
${openingTime?time}
添加全局共享变量数据模型
在代码里的实现
cfg = Configuration.getDefaultConfiguration();
cfg.setSharedVariable("global", "you good");
页面实现可以通过global指令,具体查看指令里的global部分
直接调用java对象的方法
${object.methed(args)}
字符串处理(内置方法)
html安全输出
“abc<table>sdfsf”?html
返回安全的html输出,替换掉html代码
xml安全输出
var?xml
substring的用法
<#assign user=”hello jeen”>
${user[0]}${user[4]}
${user[1..4]}
输出 :
ho
ello
类似String.split的用法
“abc;def;ghi”?split(“;”)返回sequence
将字符串按空格转化成sequence,然后取sequence的长度
var?word_list 效果同 var?split(“ ”)
var?word_list?size
取得字符串长度
var?length
大写输出字符
var?upper_case
小写输出字符
var?lower_case
首字符大写
var?cap_first
首字符小写
var?uncap_first
去掉字符串前后空格
var?trim
每个单词的首字符大写
var?capitalize
类似String.indexof:
“babcdabcd”?index_of(“abc”) 返回1
“babcdabcd”?index_of(“abc”,2) 返回5
类似String.lastIndexOf
last_index_of和String.lastIndexOf类似,同上
下面两个可能在代码生成的时候使用(在引号前加”\”)
j_string: 在字符串引号前加”\”
<#assign beanName = 'The "foo" bean.'>
String BEAN_NAME = "${beanName?j_string}";
打印输出:
String BEAN_NAME = "The \"foo\" bean.";
js_string:
<#assign user = "Big Joe's \"right hand\".">
<script>
alert("Welcome ${user}!");
</script>
打印输出
alert("Welcome Big Joe\'s \"right hand\"!");
替换字符串 replace
${s?replace(‘ba’, ‘XY’ )}
${s?replace(‘ba’, ‘XY’ , ‘规则参数’)}将s里的所有的ba替换成xy 规则参数包含: i r m s c f 具体含义如下:
• i: 大小写不区分.
• f: 只替换第一个出现被替换字符串的字符串
• r: XY是正则表达式
• m: Multi-line mode for regular expressions. In multi-line mode the expressions ^ and $ match just after or just before, respectively, a line terminator or the end of the string. By default these expressions only match at the beginning and the end of the entire string.
• s: Enables dotall mode for regular expressions (same as Perl singe-line mode). In dotall mode, the expression . matches any character, including a line terminator. By default this expression does not match line terminators.
• c: Permits whitespace and comments in regular expressions.
在模板里对sequences和hashes初始化
sequences
1. [“you”,”me”,”he”]
2. 1..100
3. [ {“Akey”:”Avalue”},{“Akey1”:”Avalue1”},
{“Bkey”:”Bvalue”},{“Bkey1”:”Bvalue1”},
]
hashes {“you”:”a”,”me”:”b”,”he”:”c”}
注释标志
<#--
这里是注释
-->
旧版本的freemarker采用的是<#comment> 注释 </#comment>方法
sequences内置方法
sequence?first
返回sequence的第一个值;前提条件sequence不能是null
sequence?last
返回sequence最后一个值
sequence?reverse
反转sequence的值
sequence?size
返回sequence的大小
sequence?sort
对sequence按里面的对象toString()的结果进行排序
sequence?sort_by(value)
对sequence 按里面的对象的属性value进行排序
如: sequence里面放入的是10 个user对象,user对象里面包含name,age等属性
sequence?sort_by(name) 表示所有的user按user.name进行排序
hashes内置方法
hash?keys
返回hash里的所有keys, 返回结果类型sequence
hash?values
返回hash里的所有value, 返回结果类型sequence
4 freemarker在web开发中注意事项
freemarker与webwork整合
web中常用的几个对象
Freemarker的ftl文件中直接使用内部对象:
${Request ["a"]}
${RequestParameters["a"]}
${Session ["a"]}
${Application ["a"]}
${JspTaglibs ["a"]}
与webwork整合之后 通过配置的servlet 已经把request,session等对象置入了数据模型中
在view中存在下面的对象
我们可以在ftl中${req}来打印req对象
• req - the current HttpServletRequest
• res - the current HttpServletResponse
• stack - the current OgnlValueStack
• ognl - the OgnlTool instance
• webwork - an instance of FreemarkerWebWorkUtil
• action - the current WebWork action
• exception - optional the Exception instance, if the view is a JSP exception or Servlet exception view
view中值的搜索顺序
${name}将会以下面的顺序查找name值
• freemarker variables
• value stack
• request attributes
• session attributes
• servlet context attributes
在模板里ftl里使用标签
注意,如果标签的属性值是数字,那么必须采用nubmer=123方式给属性赋值
JSP页面
<%@page contentType="text/html;charset=ISO-8859-2" language="java"%>
<%@taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<html>
<body>
<h1><bean:message key="welcome.title"/></h1>
<html:errors/>
<html:form action="/query">
Keyword: <html:text property="keyword"/><br>
Exclude: <html:text property="exclude"/><br>
<html:submit value="Send"/>
</html:form>
</body>
</html>
模板ftl页面
<#assign html=JspTaglibs["/WEB-INF/struts-html.tld"]>
<#assign bean=JspTaglibs["/WEB-INF/struts-bean.tld"]>
<html>
<body>
<h1><@bean.message key="welcome.title"/></h1>
<@html.errors/>
<@html.form action="/query">
Keyword: <@html.text property="keyword"/><br>
Exclude: <@html.text property="exclude"/><br>
<@html.submit value="Send"/>
</@html.form>
</body>
</html>
如何初始化共享变量
1. 初始化全局共享数据模型
freemark在web上使用的时候对共享数据的初始化支持的不够,不能在配置初始化的时候实现,而必须通过ftl文件来初始化全局变量。这是不能满主需求的,我们需要在servlet init的时候留出一个接口来初始化系统的共享数据
具体到和webwork整合,因为本身webwork提供了整合servlet,如果要增加全局共享变量,可以通过修改com.opensymphony.webwork.views.freemarker.FreemarkerServlet来实现,我们可以在这个servlet初始化的时候来初始化全局共享变量
与webwork整合配置
配置web.xml
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>com.opensymphony.webwork.views.freemarker.FreemarkerServlet</servlet-class>
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
<!—模板载入文件夹,这里相对context root,递归获取该文件夹下的所有模板-->
</init-param>
<init-param>
<param-name>NoCache</param-name> <!—是否对模板缓存-->
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>ContentType</param-name>
<param-value>text/html</param-value>
</init-param>
<init-param>
<param-name>template_update_delay</param-name>
<!—模板更新时间,0表示每次都更新,这个适合开发时候-->
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>default_encoding</param-name>
<param-value>GBK</param-value>
</init-param>
<init-param>
<param-name>number_format</param-name>
<param-value>0.##########</param-value><!—数字显示格式-->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
5高级方法
自定义方法
${timer("yyyy-MM-dd H:mm:ss", x)}
${timer("yyyy-MM-dd ", x)}
在模板中除了可以通过对象来调用方法外(${object.methed(args)})也可以直接调用java实现的方法,java类必须实现接口TemplateMethodModel的方法exec(List args). 下面以把毫秒的时间转换成按格式输出的时间为例子
public class LongToDate implements TemplateMethodModel {
public TemplateModel exec(List args) throws TemplateModelException {
SimpleDateFormat mydate = new SimpleDateFormat((String) args.get(0)));
return mydate.format(new Date(Long.parseLong((String)args.get(1)));
}
}
将LongToDate对象放入到数据模型中
root.put("timer", new IndexOfMethod());
ftl模板里使用
<#assign x = "123112455445">
${timer("yyyy-MM-dd H:mm:ss", x)}
${timer("yyyy-MM-dd ", x)}
输出
2001-10-12 5:21:12
2001-10-12
自定义 Transforms
实现自定义的<@transform>文本或表达式</@transform>的功能,允许对中间的最终文本进行解析转换
例子:实现<@upcase>str</@upcase> 将str转换成STR 的功能
代码如下:
import java.io.*;
import java.util.*;
import freemarker.template.TemplateTransformModel;
class UpperCaseTransform implements TemplateTransformModel {
public Writer getWriter(Writer out, Map args) {
return new UpperCaseWriter(out);
}
private class UpperCaseWriter extends Writer {
private Writer out;
UpperCaseWriter (Writer out) {
this.out = out;
}
public void write(char[] cbuf, int off, int len)
throws IOException {
out.write(new String(cbuf, off, len).toUpperCase());
}
public void flush() throws IOException {
out.flush();
}
public void close() {
}
}
}
然后将此对象put到数据模型中
root.put("upcase", new UpperCaseTransform());
在view(ftl)页面中可以如下方式使用
<@upcase>
hello world
</@upcase>
打印输出:
HELLO WORLD
FreeMarker2.3
一 介绍 2
二 HelloWorld 3
1 java应用程序中 3
1.1 aa.ftl---------模板文件 3
1.2 FreeMarkerTest调用模板及使用方法 3
1.3 FreeMarkerTest.java----------调用freeMarker的测试程序 4
2 web应用程序 7
1.1 web与java应用程序的区别在于: 7
1.2 完整代码 7
3 读XML数据源----- java应用程序中 9
三 语法 10
1 常用 10
1.1 ${ varName!" value"}---------指定缺省值 10
1.2 <#-- aaaaaaaa --> 注释 10
1.3 条件语句 <#if condition><#elseif condition><#else></#if> 10
1.4 变量定义 <#assign varName=value> 11
1.5 <#local var = value> 在 macro 或者 function 中定义局部变量并初始化 11
1.6 <#global var = value > 定义全局变量并初始化 11
1.7 序列 [item1,item2,item3,…] 11
1.8 list-----遍历指令 11
1.9 条件分支 <#switch 条件> <#case "值n" > <#default></#switch> 12
1.10 key:value, key2:value2 ...} 直接定义一个hash表 12
1.11 macro-----宏 12
1.12 <#nested>-----FreeMarker个性十足的指令 13
1.13 function-------函数 14
1.14 内部函数调用---------由问号、函数名与实参构成 14
四 常用函数 15
1 字符串 15
1.1 取子串--substirng 15
1.2 第一个字母大写-------cap_first 15
1.3 第一个字母不大写-----uncap_first 15
1.4 以空格间格的字符串,第一个字母大写--------capitalize 15
1.5 日期、时间函数---------date, time, datetime 15
1.6 html-----把字符串转成html传输的格式 16
1.7 index_of--------求字串在原串中的位置 16
1.8 j_string--------把空格替换成左斜线 16
1.9 js_string--------把左斜线换成 空格 16
1.10 其他字符串函数 16
2 数字 16
1.1 带常见单位的数字 16
1.2 格式化数字 16
1.3 其他函数round, floor, ceiling 17
3 日期 17
一 介绍
FreeMarker是一个文本文件模板。
文本文件中,设定特定字符串,FreeMarker会把用户指定的数据,按规定替代这些字符串,从而产生新的文件,或流数据。
例:有文本文件-------a.ftl 如下:
你好!${userName}
用户把“张三”数据放入FreeMarker中,FreeMarker将会产生新的文件,其内容会变成:
你好!张三!
作用:
非常 精致强悍,可生成网页、生成java文件、.net文件,总之任何格式的文本文件。
当然,模板文件要按这些格式书写!
说明:
(1) FreeMarker的数据源:
--------来自xml文件,或
-------- 用Map作为基本的存储单元;且必须是树结构。
(2) 官方网址
FreeMarker是开源的;官方网址http://freemarker.org/
二 HelloWorld
1 java应用程序中
1.1 aa.ftl---------模板文件
<html>
<head>
<title>Welcome!</title>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
</head>
<body>
<h1>Welcome ${user}!</h1>
</body>
</html>
说明:
${user}-----是freemarker指令。意思用 user所存数据对它进行替换。
user所存数据-----放在数据源中。
Freemarker----是模板,程序,数据相分离。
1.2 FreeMarkerTest调用模板及使用方法
下面是加载模板文件
Configuration cfg = new Configuration();
cfg.setEncoding(Locale.getDefault(),"UTF-8");
// 指定模板文件的数据源,这里是一个文件目录。
cfg.setDirectoryForTemplateLoading( new File("d:\\aaa") );
cfg.setObjectWrapper(new DefaultObjectWrapper()); //这条语句可省略
//加载文件,模板文件,输出文件都要保证用UTF-8-----解决乱码
Template template = cfg.getTemplate("aa.ftl");//加载模板文件
下面是使用方法
template.setEncoding("UTF-8");
File htmlFile = new File("t.html");
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(htmlFile), "UTF-8"));//输出文件
HashMap propMap = new HashMap();//定义Map树结构数据源
propMap.put("user", "张三");
template.process(propMap, out);
注意:加载文件,模板文件,输出文件都要保证用UTF-8-----解决乱码
Configuration. setEncoding//要在Configuration对象后就要加入
template.setEncoding("UTF-8")
OutputStreamWriter(new FileOutputStream(htmlFile), "UTF-8")
1.3 FreeMarkerTest.java----------调用freeMarker的测试程序
package jap1;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Locale;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class FreeMarkerTest {
public static void main(String[] args) throws IOException {
FreeMarkerTest test = new FreeMarkerTest();
test.getFile();
test.getFile(Locale.CHINA);
}
private String basePath;
public String getBasePath() {
return basePath;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
}
public FreeMarkerTest(){
basePath="";
}
public FreeMarkerTest(String basePath ){
this.basePath=basePath;
}
public void getFile() throws IOException {
Configuration cfg = new Configuration();//加载FreeMarker配置文件
if (basePath.equals("")){
//设本类运行时所在的路径为路劲
cfg.setClassForTemplateLoading(this.getClass(),"/");
} else{
//设用户指定路径为基路径
cfg.setDirectoryForTemplateLoading(new File(basePath));
}
cfg.setEncoding(Locale.getDefault(),"UTF-8");
Template template;
try {
template = cfg.getTemplate("aa.ftl");
template.setEncoding("UTF-8");
File htmlFile = new File("t.html");
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(htmlFile), "UTF-8"));
HashMap propMap = new HashMap();
propMap.put("user", "张三");
template.process(propMap, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//FreeMarker国际化支持,
public void getFile(Locale loc) {
Configuration cfg = new Configuration();
cfg.setClassForTemplateLoading(this.getClass(),"/");
cfg.setEncoding(Locale.getDefault(),"UTF-8");
Template template;
try {
template = cfg.getTemplate("aa.ftl",loc);
template.setEncoding("UTF-8");
String fileName="t_"+loc.getLanguage()+"_"
+loc.getCountry()+".html";
File htmlFile = new File(fileName);
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(htmlFile), "UTF-8"));
HashMap propMap = new HashMap();
propMap.put("user", "张三");
template.process(propMap, out);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2 web应用程序
1.1 web与java应用程序的区别在于:
(1) 配置类的路径指定:
有两种方式: (在web程序中)
A 模板文件在web中。针对servlet.。
下例的表示模板文件位于WEB-INF的子文件a中。
configuration.setServletContextForTemplateLoading(
getServletContext(), "WEB-INF/a");
B 模板文件在class中。
下像表示模板文件在src\java下。注:在netbeans6.5中调试。
configuration.setObjectWrapper(new DefaultObjectWrapper());
configuration.setTemplateLoader(new ClassTemplateLoader(
NewServlet1.class, "/"));
(2) 文件输出
web文件用response对象输出文件。或用像StringWriter之类的对象输出 。
1.2 完整代码
(1) 模板文件---------test.ftl-----------位于web /web-inf/a
<body>
sdad描述信息是 : ${message}
</body>
(2) NewServlet1.java---------调用FreeMarker把模板输出到浏览器中。
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.util.Locale;
import javax.servlet.http.HttpServlet;
public class NewServlet1 extends HttpServlet {
private Configuration configuration;
public NewServlet1() {
super();
}
@Override
public void destroy() {
configuration = null;
}
@Override
public void init() throws ServletException {
configuration = new Configuration();
configuration.setEncoding(Locale.getDefault(),"UTF-8");
configuration.setServletContextForTemplateLoading(
getServletContext(), "WEB-INF/a");
// configuration.setObjectWrapper(new DefaultObjectWrapper());
// configuration.setTemplateLoader(new ClassTemplateLoader(
// NewServlet1.class, "/"));
}
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
Map root = new HashMap();
root.put("message", "Hello World!帅哥,靓女!");
Template t = configuration.getTemplate("test.ftl");
Writer out = response.getWriter();
try {
t.process(root, out);
StringWriter stringWriter = new StringWriter();
t.process(root, stringWriter);
System.out.println(stringWriter.toString());
} catch (TemplateException e) {
throw new ServletException(
"Error while processing FreeMarker template", e);
}
}
}
注意:
1 configuration.setEncoding(Locale.getDefault(),"UTF-8");
要紧随configuration生成设置;否则,模板中的中文会成乱码。
2 response.setContentType("text/html;charset=UTF-8");
这句不设置;输进模板中的数据,将有可能是乱码。
3 读XML数据源----- java应用程序中
FreeMark2.3支持 XML;在程序中可直接把xml文件作为数据模型,按用户模板文件的要求,输出相应的文件(或流)给用户。
与前面相比,关键有:
1 freemarker.ext.dom.NodeModel.parse这个方法将把xml文件处理成map树状结构的模型;该方法支持以File对象,读xml;也提供了一个流适配器,从面能用InsputStream流对象读xml文件。
2 Map root = new HashMap();
root.put("doc", freemarker.ext.dom.NodeModel.parse( ins));
这里要注意:经处理后:”doc”,在数据模型中是根;而xml文件的根是它的子节点;
在读数据时,要从doc开始,否则出错。当然,”doc”也可改成其他名字。
3 增加了一个recurse指令。
FreeMarker这样处理的xml结构的数据模型的:
(1) 按层定义宏;宏名---就是节点名。(这是强行约定的)
(2) recurse----将循环调用处理子节点的宏
下面是在java应用程序中,应用freemarker的示例:
(1) ddd.xml
注意:ddd.xml位于classpath下的jap1文件夹下,与下面的 FMtest.java的位置相同。在netbean开发环境中,位于 src\java\jsp1下。
<?xml version="1.0" encoding="UTF-8"?>
<root>
<user>
<name>张三1111</name>
</user>
<user>
<name>李四hhhh</name>
</user>
</root>
(2) FMTest.java -------应用freemarker的类
package jap1;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class FMTest {
public static void main(String[] args) throws Exception {
FMTest test=new FMTest();
test.getFile();
}
@SuppressWarnings("empty-statement")
public void getFile() throws IOException, TemplateException,
SAXException, ParserConfigurationException{
//得FreeMarker配置对象
Configuration cfg = new Configuration();
cfg.setEncoding(Locale.getDefault(), "UTF-8");
cfg.setClassForTemplateLoading(this.getClass(),"/jap1");
//得FreeMarker的关键对象---------模板
Template temp = cfg.getTemplate("test.ftl");
//得FMTest类运行时/jap1/ddd.xml的输入流文件,以便FreeMarker读出来
//注意:FMTest运行时,ddd.xml在工程打包的包中。Java强烈要求只能读包内
//文件。如果要得到运行的绝对路径,再用可写的流打包,java会严重抗议!
InputStream in =FMTest.class.getResourceAsStream("/jap1/ddd.xml");
//下面是FreeMarker的输入接口,这里与上面的in流建立关系,
//以便读取ddd.xml文件
InputSource ins=new org.xml.sax.InputSource(in);
Map root = new HashMap();
//特别注意此时的doc,这个符号将是,FreeMarker模板中取数的根!!!!!
//这里读取xml文件,并处理成root对象
root.put("doc", freemarker.ext.dom.NodeModel.parse( ins));
//建立内存字符串流
java.io.StringWriter w =new StringWriter();
//模板开始按模板中的要求把用户输入的数据进行转换,并输出到字符串流中
temp.process(root, w);
//字符串流输出到屏幕
System.out.println(w.toString());
}
}
(3) test.ftl --------模板文件
测试单个读数操作-----${doc.root.user[0].name}
列表测试:
<#list doc.root.user as dd>
${dd.name}
</#list>
<#--recurse指令,按层读取整个xml节点,并循环调用处理这些节点的宏-->
<#recurse doc><#--root是doc的子节点,这里将循环调用<#marco root>宏 -->
读doc
<#macro root>
读root <#recurse><#--user是root的子节点,这里将循环调用<#marco user>宏 -->
</#macro>
<#macro user>
姓名:${.node.name};测试recurse指令,user
</#macro>
(4) 运行结果
测试单个读数操作-----张三1111
列表测试:
张三1111
李四hhhh
读root
姓名:张三1111;测试recurse指令,user
姓名:李四hhhh;测试recurse指令,user
读doc
三 语法
说明:大多数运算符号与java相同
算术加、减、乘、除运算:+、 -、 *、 /
逻辑 或 与 非:: || 、&& 、!
比较运算符-----大于、小于、小于等于、等于、不等于: >、< 、<=、= 或==、!=
或----大于、小于、小于等于: gt、lt、lte
子界:.. 例:1..5表示1到5
1 常用
${ varName }----------替换符
其中: ” varName” 是数据源中的变量名;作用,会用变量值,对该符号进行替换。
例: 假定数据源中 varName 值为“张三”
你好,${ varName } !
结果:你好,张三
补充: 数据源中变量访问形式:root开始,各部分用“.”分隔,到本变量名位置置。
如: aninmal 中有dog,dog下有名称。访问为”aninmal.dog.name”;中间是小数点间隔。
与java程序中,类对象对其属性的方法类似。
1.1 ${ varName!" value"}---------指定缺省值
当“varName”不存在时,用感叹号后中的字符替代。
例:假定varName的数据源中不存在:
你好,${useraa !""}!
结果为:你好,
1.2 <#-- aaaaaaaa --> 注释
1.3 条件语句 <#if condition><#elseif condition><#else></#if>
例:
<#if user="王五">
<#elseif user="李四">
<#else>
你好,${user !""}!
</#if>
1.4 变量定义 <#assign varName=value>
例:
<#assign seq ="上帝">
Oh,${seq !""}!
结果:Oh,上帝!
1.5 <#local var = value> 在 macro 或者 function 中定义局部变量并初始化
1.6 <#global var = value > 定义全局变量并初始化
1.7 序列 [item1,item2,item3,…]
1.8 list-----遍历指令
其中有两个内定变量:
item_index 遍历过程中,元素的索引值;
item_has_next: 逻辑变量,为false表时, 已经遍历到尾。
例:
<#assign seq = ["winter", "spring", "summer", "autumn"]>
${seq[0]}
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>
结果:
winter
1. winter,
2. spring,
3. summer,
4. autumn
1.9 条件分支 <#switch 条件> <#case "值n" > <#default></#switch>
例:
<#assign x =10>
<#switch x>
<#case 10 >
d
</#switch>
1.10 key:value, key2:value2 ...} 直接定义一个hash表
例:
<#assign ages = {"张三":23, "李四":25} + {"王二":30, "小李":18}>
- 张三 是 ${ages.张三}
- 王二 是 ${ages["王二"]}
结果:
- 张三 是 23
- 王二 是 30
1.11 macro-----宏
定义:
<@macro 宏名 形参1 形参2 >
指令n
</@macro>
调用:
<@宏名 实参1 实参n>
</@宏名>
或:<@宏名 实参1 实参n/>
例:
<#macro greet user>
<font size="+2">你好,${user}{</font>
</#macro>
<@greet "张三"/>
结果: <font size="+2">你好,张三{</font>
说明:
A 宏不调用,不执行
B 此时的宏,相当于java中无返回值的方法。
1.12 <#nested>-----FreeMarker个性十足的指令
这条指令,过性十足!要与宏配合使用,实现函数相互调用。
个性表现在:
<#nested> 与宏调用,又构成一个 ---------
方法定义 与方法调用的关系
1 出现<#nested>的地方,将由宏用的“<@宏名 实参1 实参n>” 与“</@宏名>”之间的值替代。
2 还可以传递参数。
宏调用:<@宏名 实参1 实参n; nested指令的形参1, nested指令的形参2>
被nested指令代替部份 以及 nested的实现部份
</@宏名>
宏定义中的形式为 nested:
<@nested 形参1,形参n>
其中:参数指------- 宏调用分号“;”后的参数
例1:
<#macro test>
<#nested >
<#nested >
</#macro>
<@test > 看nested指令调用我 </@test>
<@test > 看nested指令调用我111
</@test>
结果
看nested指令调用我 看nested指令调用我
看nested指令调用我
看nested指令调用我
例2
<#macro test>
<#nested 1,"张三">
<#nested 2,"李四" >
</#macro>
<@test;aa,user>
看 nested第${aa}次调用;这是${user};
------------------------------------------
真TMD好玩,老子调用你,你还反过来调用我!
</@test>
结果
看 nested第1次调用;这是张三;
------------------------------------------
真TMD好玩,老子调用你,你还反过来调用我!
看 nested第2次调用;这是李四;
------------------------------------------
真TMD好玩,老子调用你,你还反过来调用我!
1.13 function-------函数
与macro的区别是:它有返回值
定义:
<#function 函数名 形参1 参n>
<#return 返回值>
</#function
调用:
函数名 实参1 实参n
例:
1.14 内部函数调用---------由问号、函数名与实参构成
例:
<#assign x = 1.234>$
${x?string("0.####")}
结果:1.234
四 常用函数
说明:表格左边例,右边结果.
1 字符串
1.1 取子串--substirng
- ${'abc'?substring(0, 0)}
- ${'abc'?substring(0, 1)}
- ${'abc'?substring(0, 2)}
- ${'abc'?substring(0, 3)} -
- a
- ab
- abc
1.2 第一个字母大写-------cap_first
${" green mouse"?cap_first}
${"GreEN mouse"?cap_first}
${"- green mouse"?cap_first} Green mouse
GreEN mouse
- green mouse
1.3 第一个字母不大写-----uncap_first
1.4 以空格间格的字符串,第一个字母大写--------capitalize
${" green mouse"?capitalize}
${"GreEN mouse"?capitalize} Green Mouse
Green Mouse
1.5 日期、时间函数---------date, time, datetime
<#assign test1 = "10/25/1995"?date("MM/dd/yyyy")>
${test1}
<#assign test2 = "15:05:30"?time("HH:mm:ss")>
${test2}
<#assign test3 = "1995-10-25 22:05:10 "?datetime("yyyy-MM-dd hh:mm:ss")>
${test3} 1995-10-25
15:05:30
1995-10-25 22:05:10
1.6 html-----把字符串转成html传输的格式
1.7 index_of--------求字串在原串中的位置
${"ddabcabc"?index_of("bc")} 3
1.8 j_string--------把空格替换成左斜线
1.9 js_string--------把左斜线换成 空格
<#assign user = "Big Joe's \"right hand\"">
${user?js_string} Big Joe\'s \"right hand\"
1.10 其他字符串函数
length、 number、replace、split、trim、upper_case
2 数字
1.1 带常见单位的数字
<#assign x=42>
${x}
${x?string} <#-- the same as ${x} -->
${x?string.number}
${x?string.currency}
${x?string.percent}
${x?string.computer} 42
42
42
¥42.00
4,200%
42
1.2 格式化数字
<#assign x = 1.234>
${x?string("0")}
${x?string("0.####")}
${1?string("000.00")}
${12.1?string("000.00")}
${123.456?string("000.00")}
${2.7?string("0")} <-- 注意:全四舍五入 1
1.234
001.00
012.10
123.46
3 <-- 注意:全四舍五入
1.3 其他函数round, floor, ceiling
3 日期
${openingTime?string.short}
${openingTime?string.medium}
${openingTime?string.long}
${openingTime?string.full}
${nextDiscountDay?string.short}
${nextDiscountDay?string.medium}
${nextDiscountDay?string.long}
${nextDiscountDay?string.full}
${lastUpdated?string.short}
${lastUpdated?string.medium}
${lastUpdated?string.long}
${lastUpdated?string.full} ${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}
${lastUpdated?string("EEE, MMM d, ''yy")}
${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")
说明:左右两边都是示指令,都没有结果。官方的这个调试没通过,也懒得理了