Beetl的基本用法

       本文参考BeetlSql官方网站,官网网站请点击这里~


       Beetl相对于其他java模板引擎,具有功能齐全,语法直观,性能超高,以及编写的模板容易维护等特点。它的特性如下:

       1、功能完备:作为主流模板引擎,Beetl具有相当多的功能和其他模板引擎不具备的功能。适用于各种应用场景,从对响应速度有很高要求的大网站到功能繁多的CMS管理系统都适合。Beetl本身还具有很多独特功能来完成模板编写和维护,这是其他模板引擎所不具有的。2、非常简单:类似JavaScript语法和习俗,同时也能支持html标签。3、超高的性能:Beetl远超过主流java模板引擎性能(引擎性能5-6倍于FreeMarker,2倍于JSP。参考附录),而且消耗较低的CPU。4、易于整合:Beetl能很容易的与各种web框架整合,如Spring MVC,JFinal,Struts,Nutz,Jodd,Servlet等。5、扩展和个性化:Beetl支持自定义方法,格式化函数,虚拟属性,标签,和HTML标签。同时Beetl支持自定义占位符和控制语句起始符号,也支持使用者完全可以打造适合自己的工具包。

一、一个简单的例子

package com.xzw.main;

import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.StringTemplateResourceLoader;

/**
 * @author: xzw
 * @create_date: 2019/9/23 10:03
 * @desc: Beetl测试
 * @modifier:
 * @modified_date:
 * @desc:
 */
public class BeetlTest {
    public static void main(String[] args) throws Exception{
        //初始化代码
        StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
        Configuration cfg = Configuration.defaultConfiguration();
        GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
        //获取模板
        Template t = gt.getTemplate("hello,${name}");
        t.binding("name", "Beetl");
        //渲染结果
        String str = t.render();
        System.out.println(str);
    }
}

       运行结果如下:

hello,Beetl

       Beetl的核心是GroupTemplate,是一个重量级对象,实际使用的时候建议使用单模式创建,创建GroupTemplate需要俩个参数,一个是模板资源加载器,一个是配置类,模板资源加载器Beetl内置了6种,分别是:1、StringTemplateResourceLoader:字符串模板加载器,用于加载字符串模板,如上例所示。2、FileResourceLoader:文件模板加载器,需要一个根目录作为参数构造,传入getTemplate方法的String是模板文件相对于Root目录的相对路径。3、ClasspathResourceLoader:文件模板加载器,模板文件位于Classpath里。4、WebAppResourceLoader:用于webapp集成,假定模板根目录就是WebRoot目录。5、MapResourceLoader : 可以动态存入模板。6、CompositeResourceLoader 混合使用多种加载方式。

       template提供了多种获得渲染输出的方法,如下:1、template.render()返回渲染结果,如上例所示。2、template.renderTo(Writer)渲染结果输出到Writer里。3、template.renderTo(OutputStream )渲染结果输出到OutputStream里。

二、Beetl模板基础配置

        Beetl不但功能齐全,而且还有很多独特功能,通过简单的配置文件,就可以定义众多的功能,默认情况下,Configuration类总是会先加载默认的配置文件(位于/org/beetl/core/beetl-default.properties。其内容片断如下:

#默认配置
# 配置引擎实现类,默认即可
ENGINE=org.beetl.core.engine.FastRutimeEngine 

# 指定占位符,默认${},也可以指定为其他占位符
DELIMITER_PLACEHOLDER_START=${
DELIMITER_PLACEHOLDER_END=}

# 指定语句的定界符,默认是<% %>,也可以使用其他的定界符
DELIMITER_STATEMENT_START=<%
DELIMITER_STATEMENT_END=%>

# 指定IO输出模式,默认是FALSE,即通常的字符输出,在考虑高性能情况下,可以设置成true。
DIRECT_BYTE_OUTPUT = FALSE

# 指定了支持HTML标签,且符号为#,默认配置下,模板引擎识别<#tag ></#tag>这样的类似html标签,并能调用相应的标签函数或者模板文件。也可以指定别的符号,如bg: 则识别<bg:
HTML_TAG_SUPPORT = true
HTML_TAG_FLAG = #

# 指定如果标签属性有var,则认为是需要绑定变量给模板的标签函数
HTML_TAG_BINDING_ATTRIBUTE = var

# 指定允许本地Class直接调用
NATIVE_CALL = TRUE

# 指定模板字符集是UTF-8
TEMPLATE_CHARSET = UTF-8

# 指定异常的解析类,默认是ConsoleErrorHandler,他将在render发生异常的时候在后台打印出错误信息(System.out)
ERROR_HANDLER = org.beetl.core.ConsoleErrorHandler

# 指定了本地Class调用的安全策略
NATIVE_SECUARTY_MANAGER= org.beetl.core.DefaultNativeSecurityManager

# 配置了是否进行严格MVC,通常情况下,此处设置为false
MVC_STRICT = FALSE

# 资源配置,resource后的属性只限于特定ResourceLoader。指定了默认使用的模板资源加载器,注意,在beetl与其他MVC框架集成的时候,模板加载器不一定根据这个配置,比如spring,他的RESOURCE_LOADER以spring的配置为准。
RESOURCE_LOADER=org.beetl.core.resource.ClasspathResourceLoader

# 配置了模板资源加载器的一些属性,如设置根路径为/,即Classpath的顶级路径,并且总是检测模板是否更改。
RESOURCE.root= /
# 是否检测文件变化,开发用true合适,但线上要改为false。
RESOURCE.autoCheck= true

# 自定义脚本方法文件的Root目录和后缀
RESOURCE.functionRoot = functions
RESOURCE.functionSuffix = html

# 自定义标签文件Root目录和后缀
RESOURCE.tagRoot = htmltag
RESOURCE.tagSuffix = tag

#########扩展##############
## 内置的方法
FN.date = org.beetl.ext.fn.DateFunction
......
##内置的功能包
FNP.strutil = org.beetl.ext.fn.StringUtil
......
##内置的默认格式化函数
FTC.java.util.Date = org.beetl.ext.format.DateFormat
.....
## 标签类
TAG.include= org.beetl.ext.tag.IncludeTag
TAG.html.include= org.beetl.ext.tag.html.IncludeResourceHtmlTag
TAG.html.foreach= org.beetl.ext.tag.html.ForeachHtmlTag

       模板开发者可以创建一个beetl.properties的配置文件,此时,该配置文件将覆盖默认的配置文件属性,比如,定界符考虑是<!--: 和 --> ,则在beetl.properties加入一行即可,并将此配置文件放入Classpath根目录下即可。Configuration.defaultConfiguration()总是先加载系统默认的,然后再加载Beetl.properties的配置属性,如果有重复,用后者代替前者的配置。

三、模板资源加载器

       资源加载器是根据String值获取Resource实例的工场类,同时资源加载器还要负责响应模板引擎询问模板是否变化的调用。

1、字符串模板加载器

       在创建GroupTemplate过程中,如果传入的是StringTemplateResourceLoader,则允许通过调用gt.getTemplate(String template)来获取模板实例对象

2、文件资源模板加载器

       更通常情况下,模板资源是以文件形式管理的,集中放在某一个文件目录下(如webapp的模板根目录就可能是WEB-INF/template里),因此,可以使用FileResourceLoader来加载模板实例,如下代码:

//文件资源模板加载器
String root = System.getProperty("user.dir") + File.separator + "template";  //指定模板根目录,即位于项目工程下的template目录
FileResourceLoader resourceLoader = new FileResourceLoader(root, "utf-8");  //构造资源加载器,并指定字符集为utf-8
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
Template t = gt.getTemplate("/hello.txt");  //通过模板的相对路径来加载模板
String str = t.render();
System.out.println(str);

3、Classpath资源模板加载器

       在springboot里,模板资源是打包到jar文件或者同Class放在一起,因此,可以使用ClasspathResourceLoader来加载模板实例,如下代码:

ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("org/beetl/sample/s01/");  //指定了模板根目录,即搜索模板的时候从根目录开始,字符集默认是utf-8
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
Template t = gt.getTemplate("/hello.txt");
String str = t.render();
System.out.println(str);

4、WebApp模板资源加载器

       WebAppResourceLoader 是用于Java EE web应用的资源模板加载器,默认根路径是WebRoot目录。也可以通过制定root属性来设置相对于WebRoot的的模板根路径,从安全角考虑,建议放到WEB-INF目录下如下是Jfinal集成初始化GroupTemplate的方法:

Configuration cfg = Configuration.defaultConfiguration();
WebAppResourceLoader resourceLoader = new WebAppResourceLoader();
groupTemplate = new GroupTemplate(resourceLoader, cfg);

       WebAppResourceLoader假定beetl.jar是位于WEB-INF/lib 目录下,因此,可以通过WebAppResourceLoader类的路径来推断出WebRoot路径从而指定模板根路径。如果环境不符合此假设,需要调用resourceLoader.setRoot()来指定模板更路径。

5、自定义资源模板加载器

       有时候模板可能来自文件系统不同目录,或者模板一部分来自某个文件系统,另外一部分来自数据库,还有的情况模板可能是加密混淆的模板,此时需要自定义资源加载,继承ResouceLoader才能实现模板功能。

四、定界符与占位符

       Beetl模板语言类似JS语言和习俗,只需要将Beetl语言放入定界符号里即可,如默认的是<% %>,定界符用于静态文本里嵌入占位符用于输出,如下:

<%
var a = 2;
var b = 3;
var result = a + b;
%>
hello 2 + 3 = ${result}

       千万不要在定界符里使用占位符号,因为占位符仅仅嵌在静态文本里,如下例子是错误例子:

<%
var a = "hi";
var c = ${a}+"beetl"; //应该是var c = a+"beetl"
%>

       如果表达式中的符号跟自己定义的定界符或者占位符有冲突,可以在表达式中使用“\”来进行转义。

五、注释

       Beetl语法类似js语法,所以注释上也同js一样:单行注释采用//,多行注视采用/**/。

六、变量定义

1、临时变量定义

       在模板中定义的变量成为临时变量,这类似js中采用var 定义的变量,模板里定义的临时变量只能在当前模板中使用,如下:

<%
var a = 3;
var b = 3,c = "abc",d=true,e=null;
var f = [1,2,3];
var g = {key1:a,key2:c};
var i = a+b;
%>

2、全局变量定义

       全局变量是通过template.binding传入的变量,这些变量能在模板的任何一个地方,包括子模板都能访问到。如java代码里:

template.binding("list",service.getUserList());

//在模板里
<%
for(user in list){
%>
hello,${user.name};
<% } %>

       自从2.8.0版本后,有一个特殊的变量成为root变量,当模板找不到变量的时候,会寻找root变量的属性来作为变量的值,这个root变量必须绑定为"_root"。

template.binding("_root",new User());

//在模板里
${name}
${wife.name}

七、共享变量

       共享变量指在所有模板中都可以引用的变量,可通过groupTemplate.setSharedVars(Map<String, Object> sharedVars)传入变量,这些变量能用在所有模板的任何一个地方。

GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
// 设置共享变量
Map<String,Object> shared = new HashMap<String,Object>();
shared.put("name", "beetl");
gt.setSharedVars(shared);
Template t = gt.getTemplate("/org/beetl/sample/s0208/t1.txt");
String str = t.render();
System.out.println(str);
t = gt.getTemplate("/org/beetl/sample/s0208/t2.txt");
str = t.render();
System.out.println(str);
//t1.txt
hi,${name}
//t2.txt
hello,${name}

八、模板变量

        模板变量是一种特殊的变量,即可以将模板中任何一段的输出赋值到该变量,并允许稍后在其他地方使用,如下:

<%
var content = {
        var c = "1234";
        print(c);
%>
//其他内容
<% }; %>

九、引用属性

       属性引用是模板中的重要一部分,Beetl支持属性同JavaScript的支持方式一样,如下:1、Beetl支持通过”.”号来访问对象的的属性。如果User对象有个getName()方法,那么在模板中,可以通过${xxx.name}来访问。2、如果模板变量是数组或者List类,这可以通过[]来访问,如${userList[0]}。3、如果模板变量是Map类,这可以通过[]来访问,如${map[“name”]},如果key值是字符串类型,也可以使用${map.name}。4、Beetl也支持Generic Get方式,即如果对象有一个public Object get(String key)方法,可以通过”.”号或者[]来访问,譬如 ${activityRecord.name}或者${activityRecord[“name”] }都将调用activityRecord的 get(String key)方法。如果对象既有具体属性,又有Generic get(这种模型设计方式是不值得鼓励),则以具体属性优先级高。5、Beetl也可以通过[]来引用属性,如${user[“name”]} 相当于${user.name}。6、Beetl还可以定义额外的对象属性,而无需更改java对象,这叫着虚拟属性,如:对于所有集合、数组、都有共同的虚拟属性size。虚拟属性是“.~”+虚拟属性名。

template.binding("list",service.getUserList());
template.binding("pageMap",service.getPage());

//在模板里
总共 ${list.~size}
<%
for(user in list){
%>
hello,${user.name};
<% } %>

当前页${pageMap['page']},总共${pageMap["total"]}

十、属性赋值

<%
var user = ....
user.name="joelli";
user.friends[0] = getNewUser();
user.map["name"] = "joelli";
%>

十一、表达式

1、算术表达式

       Beetl支持类似javascript的算术表达式和条件表达式,如+ - * / % 以及(),以及自增++,自减--。

<%
var a = 1;
var b = "hi";
var c = a++;
var d = a+100.232;
var e = (d+12)*a;
var f = 122228833330322.1112h
%>

       Beetl里定义的临时变量类型默认对应的java类型是Int型或者double类型,对于模板常用情况,已经够了。如果需要定义长精度类型(对应java的BigDecimal),则需要在数字末尾加上h以表示这是长精度BigDecimal,其后的计算和输出以及逻辑表达式都将按照长精度类型来考虑。

2、逻辑表达式

       Beetl支持类似Javascript,java的条件表达式 如>,<,==,!=,>= , <= 以及 !, 还有&&和 || ,还有三元表达式等,如下:

<%
var a = 1;
var b="good";
var c = null;

if(a!=1&&b=="good"&&c==null){
        ......
}
%>

       三元表达式如果只考虑true条件对应的值的话,可以做简化,如下俩行效果是一样的。

<%
 var  a = 1 ;
%>
${a==1?"ok":''}
${a==1?"ok"}

十二、循环语句

       Beetl支持丰富的循环方式,如for-in,for(exp;exp;exp),以及while循环,以及循环控制语句break;continue; 另外,如果没有进入for循环体,还可以执行elsefor指定的语句。

1、for-in

       for-in循环支持遍历集合对象,对于List和数组来说以及Iterator,对象就是集合对象,对于Map来说,对象就是Map.entry。如下:

<%
for(user in userList){
        print(userLP.index);
        print(user.name);
}
%>

       上例中的userLP是Beetl隐含定义的变量,是一个ILoopStatus实例,能在循环体内使用。其命名规范是item名称后加上LP,他提供了当前循环的信息,如:

*userLP.index *当前的索引,从1开始
userLP.dataIndex 索引,从0开始
*userLP.size *集合的长度
userLP.first 是否是第一个
userLP.last 是否是最后一个
userLP.even 索引是否是偶数
userLP.odd 索引是否是奇数

       下面是Map使用的例子:

<%
for(entry in map){
        var key = entry.key;
        var value = entry.value;
        print(value.name);
}
%>

2、for(exp;exp;exp)

       对于渲染逻辑更为常见的是经典的for循环语句,如下:

<%
var a = [1,2,3];
for(var i=0;i<a.~size;i++){
        print(a[i]);
}
%>

3、while

       对于渲染逻辑同样常见的有的while循环语句,如下:

<%
var i = 0;
while(i<5){
        print(i);
        i++;
}
%>

4、elsefor

       不同于通常程序语言,如果没有进入循环体,则不需额外的处理,模板渲染逻辑更常见情况是如果没有进入循环体,还需要做点什么,因此,对于for循环来说,还有elsefor 用来表达如果循环体没有进入,则执行elsefor 后的语句。

<%
var list = [];
for(item in list){

}elsefor{
        print("未有记录");
}
%>

十三、条件语句

1、if else

<%
var a =true;
var b = 1;
if(a&&b==1){

}else if(a){

}else{

}
%>

2、switch-case

<%
var b = 1;
switch(b){
        case 0:
                print("it's 0");
                break;
        case 1:
                print("it's 1");
                break;
        default:
                print("error");
}
%>

3、select-case

       select-case 是switch case的增强版。他允许case 里有逻辑表达式,同时,也不需要每个case都break一下,默认遇到合乎条件的case执行后就退出。

<%
var b = 1;
select(b){
        case 0,1:
                print("it's small int");
        case 2,3:
                print("it's big int");
        default:
                print("error");
}
%>

       select 后也不需要一个变量,这样case 后的逻辑表达式将决定执行哪个case。其格式是:

<%
select {
        case boolExp,orBoolExp2:
                doSomething();
}
%>
<%
var b = 1;
select{
        case b<1,b>10:
                print("it's out of range");
                break;
        case b==1:
                print("it's 1");
                break;
        default:
                print("error");
}
%>

十四、try-catch

       通常模板渲染逻辑很少用到try-catch 但考虑到渲染逻辑复杂性,以及模板也有不可控的地方,所以提供try catch,在渲染失败的时候仍然能保证输出正常。

<%
try{
        callOtherSystemView()
}catch(error){
        print("暂时无数据");
}
%>

       error代表了一个异常,你可以通过error.message 来获取可能的错误信息。也可以省略catch部分,这样出现异常,不做任何操作。

十五、虚拟属性

       虚拟属性也是对象的属性,是虚拟的,非模型对象的真实属性,这样的好处是当模板需要额外的用于显示属性的时候但又不想更改模型,便可以采用这种办法,如beetl内置的虚拟属性.~size 针对了数组以及集合类型。

十六、函数调用

       Beetl内置了少量实用函数,可以在Beetl任何地方调用。如下例子是调用date 函数,不传参数情况下,返回当前日期:

<%
var date = date();
var len = strutil.length("cbd");
println("len="+len);
%>

       注意函数名支持namespace方式,因此代码调用的函数是strutil.length。

       定义beetl的方法有三种方法:1、实现Function类的call方法,并添加到配置文件里,或者显示的通过代码注册registerFunction(name,yourFunction)。2、可以直接调用registerFunctionPackage(namespace,yourJavaObject),这时候yourJavaObject里的所有public方法都将注册为Beetl方法,方法名是namespace+"."+方法名。3、可以直接写模板文件并且以html作为后缀,放到root/functions目录下,这样此模板文件自动注册为一个函数,其函数名是该模板文件名。

       以下是Beetl常用的函数:

1、date 返回一个java.util.Date类型的变量,如 date() 返回一个当前时间(对应java的java.util.Date); ${date( "2011-1-1" , "yyyy-MM-dd" )} 返回指定日期,date(ms),指定一个毫秒数。相当于调用java.util.Date(ms)。
2、print 打印一个对象 print(user.name)。
3、println 打印一个对象以及回车换行符号,回车换号符号使用的是模板本身的,而不是本地系统的。如果仅仅打印一个换行符,则直接调用println() 即可。
4、nvl函数,如果对象为null,则返回第二个参数,否则,返回自己 nvl(user,"不存在")。
5、isEmpty 判断变量或者表达式是否为空,变量不存在,变量为null,变量是空字符串,变量是空集合,变量是空数组,此函数都将返回true
6、isNotEmpty 同上,判断对象是否不为空。
7、has 变量名为参数,判断是否存在此"全局变量",如 has(userList),类似于1.x版本的exist("userList"),但不需要输入引号了。注意,has和isEmpety 判断的是从java传到模板的全局变量,而不是临时变量。
8、hasAttrbiute 测试目标对象是否有此属性,hasAttribute(user,"name")。
9、assert 如果表达式为false,则抛出异常。
10、trim 截取数字或者日期,返回字符,如trim(12.456,2)返回"12.45",trim(date,'yyyy')返回"2017"。
11、trunc 截取数字,保留指定的小数位,如trunc(12.456,2) 输出是12.45.不推荐使用,因为处理float有问题,兼容原因保留了。
12、decode 一个简化的if else 结构,如 decode(a,1,"a=1",2,"a=2","不知道了"),如果a是1,这decode输出"a=1",如果a是2,则输出"a==2", 如果是其他值,则输出"不知道了"。
13、debug 在控制台输出debug指定的对象以及所在模板文件以及模板中的行数,如debug(1),则输出1 [在3行@/org/beetl/core/lab/hello.txt],也可以输出多个,如debug("hi",a),则输出hi,a=123,[在3行@/org/beetl/core/lab/hello.txt]。
14、parseInt 将数字或者字符解析为整形 如 parseInt("123")。
15、parseLong 将数字或者字符解析为长整形,parseInt(123.12)。
16、parseDouble 将数字或者字符解析为浮点类型 如parseDouble("1.23")
17、range 接收三个参数,初始值,结束值,还有步增(可以不需要,则默认为1),返回一个Iterator,常用于循环中,如for(var i in range(1,5)) {print(i)},将依次打印1234。
18、flush 强制io输出。
19、json,将对象转成json字符串,如 var data = json(userList) 可以跟一个序列化规则 如:var data = json(userList,"[*].id:i")。
20、pageCtx ,仅仅在web开发中,设置一个变量,然后可以在页面渲染过程中,调用此api获取,如pageCtx("title","用户添加页面"),在其后任何地方,可以pageCtx("title") 获取该变量。
21、type.new 创建一个对象实例,如 var user = type.new("com.xx.User"); 如果配置了IMPORT_PACKAGE,则可以省略包名,type.new("User")。
22、type.name 返回一个实例的名字,var userClassName = type.name(user),返回"User"。
23、global 返回一个全局变量值,参数是一个字符串,如 var user = global("user_"+i)。
24、cookie 返回指定的cookie对象 ,如var userCook = cookie("user"),allCookies = cookie()。

十七、安全输出

       在变量后加上!不仅仅可以应用于占位符输出(但主要是应用于占位符输出),也可以用于表达式中,如:

<%
var k = user.name!'N/A'+user.age!;
%>
<%
${k}
%>

       如果user为null,则k值将为N/A。

       在有些模板里,可能整个模板都需要安全输出,也可能模板的部分需要安全输出,这时不必为每一个表达式使用!,可以使用beetl的安全指示符号来完成安全输出 如:

<%
DIRECTIVE SAFE_OUTPUT_OPEN;
%>
${user.wife.name}
模板其他内容,均能安全输出……
<%
//关闭安全输出。
DIRECTIVE SAFE_OUTPUT_CLOSE;
%>

       Beetl不建议每一个页面都使用DIRECTIVE SAFE_OUTPUT_OPEN,这样,如果真有不期望的错误,不容易及时发现,其次,安全输出意味着beetl会有额外的代码检测值是否存在或者是否为null,性能会略差点。所以建议及时关闭安全输出。

       在for-in 循环中 ,也可以为集合变量增加安全输出指示符号,这样,如果集合变量为null,也可以不进入循环体,如:

<%
var list = null;
for(item in list!){

}elsefor{
        print("no data");
}
%>

1、变量是否存在

<%
if(has(flag)){
        print("flag变量存在,可以访问")
}
%>

       如果需要判断变量是否存在,如果存在,还有其他判断条件,通常都这么写:

<%
if(has(flag)&&flag==0){
        //code
}
%>

       如果flag存在,而且值是0,都将执行if语句,但是,有更为简便的方法是直接用安全输出,如:

<%
if(flag!0==0){
        //code
}
%>

       flag!0 取值是这样的,如果flag不存在,则为0,如果存在,则取值flag的值,类似三元表达式 if((has(flag)?flag:0)==0)

2、安全输出表达式

       安全输出表达式可以包括:1、字符串常量,如 ${user.count!"无结果"}。2、boolean常量 ${user.count!false}。3、数字常量,仅限于正数,因为如果是负数,则类似减号,容易误用,因此,如果需要表示负数,请用括号,如${user.count!(-1)}。4、class直接调用,如${[email protected]_NUM}。5、方法调用,如 ${user.count!getDefault() }。6、属性引用,如 ${user.count!user.maxCount }。7、任何表达式,需要用括号。

十八、格式化

       如下例子Beetl提供的内置日期格式:

<% var date = date(); %>
Today is ${date,dateFormat="yyyy-MM-dd"}.
Today is ${date,dateFormat}
salary is ${salary,numberFormat="##.##"}

       格式化函数只需要一个字符串作为参数放在=号后面,如果没有为格式化函数输入参数,则使用默认值,dateFormat格式化函数默认值是local。Beetl也允许为指定的java class设定格式化函数,譬如已经内置了对java.util.Date,java.sql.Date 设置了了格式化函数,因此上面的例子可以简化为:

${date,“yyyy-MM-dd”}

       Beetl针对日期和数字类型提供的默认的格式化函数,在org/beetl/core/beetl-default.properties里,注册了:

##内置的格式化函数
FT.dateFormat =  org.beetl.ext.format.DateFormat
FT.numberFormat =  org.beetl.ext.format.NumberFormat
##内置的默认格式化函数
FTC.java.util.Date = org.beetl.ext.format.DateFormat
FTC.java.sql.Date = org.beetl.ext.format.DateFormat
FTC.java.sql.Time = org.beetl.ext.format.DateFormat
FTC.java.sql.Timestamp = org.beetl.ext.format.DateFormat
FTC.java.lang.Short = org.beetl.ext.format.NumberFormat
FTC.java.lang.Long = org.beetl.ext.format.NumberFormat
FTC.java.lang.Integer = org.beetl.ext.format.NumberFormat
FTC.java.lang.Float = org.beetl.ext.format.NumberFormat
FTC.java.lang.Double = org.beetl.ext.format.NumberFormat
FTC.java.math.BigInteger = org.beetl.ext.format.NumberFormat
FTC.java.math.BigDecimal = org.beetl.ext.format.NumberFormat
FTC.java.util.concurrent.atomic.AtomicLong = org.beetl.ext.format.NumberFormat
FTC.java.util.concurrent.atomic.AtomicInteger = org.beetl.ext.format.NumberFormat

十九、标签函数

       标签函数即允许处理模板文件里的一块内容,功能等于同jsp tag。如Beetl内置的layout标签。

       index.html

<%
layout("/inc/layout.html",{title:'主题'}){
%>
Hello,this is main part
<% } %>

       layout.html

title is ${title}
body content ${layoutContent}
footer

       Beetl内置了另外一个标签是include,允许include另外一个模板文件:

<%
include("/inc/header.html"){}
%>

       在标签中,{} 内容将依据标签的实现而执行,layout标签将执行{}中的内容,而include标签则忽略标签体内容。

二十、HTML标签

       Beetl 也支持HTML tag形式的标签, 区分beetl的html tag 与 标准html tag。如设定HTML_TAG_FLAG=#,则如下html tag将被beetl解析。

<#footer style=”simple”/>
<#richeditor id=”rid” path="${ctxPath}/upload" name=”rname”  maxlength=”${maxlength}”> ${html} …其他模板内容   </#richdeitor>
<#html:input  id=’aaaa’ />

       对于标签footer,Beetl默认会寻找WebRoot/htmltag/footer.tag(可以通过配置文件修改路径和后缀) ,内容如下:

<% if(style==’simple’){ %>
 请联系我 ${session.user.name}
<% }else{ %>
请联系我 ${session.user.name},phone:${session.user.phone}
<% } %>

       如下还包含了自定义html标签一些规则:1、可以在自定义标签里引用标签体的内容,标签体可以是普通文本,beetl模板,以及嵌套的自定义标签等。如上<#richeditor 标签体里,可用“tagBody”来引用。2、HTML自定义标签的属性值均为字符串 如<#input value="123" />,在input.tag文件里变量value的类型是字符串。3、可以在属性标签里引用beetl变量,如<#input value="${user.age}" />,此时在input.tag里,value的类型取决于user.age。4、在属性里引用beetl变量,不支持格式化,如<#input value="${user.date,'yyyy-MM-dd'}"/>,如果需要格式化,需要在input.tag文件里自行格式化。5、在标签属性里传json变量需要谨慎,因为json包含了"}",容易与占位符混合导致解析出错,因此得使用"\"符号,如<#input value="${ {age:25\} }" />。6、html tag 属性名将作为 其对应模板的变量名。如果属性名包含“-”,则将转为驼峰命名的变量,如data-name,转为dataName。7、默认机制下,HTMLTagSupportWrapper2 实现了标签。8、标签属性带有"-“符号,会自动去掉,后面的字母大写,以符合变量命名规范。9、所有的标签属性都保存在"$cols" 变量里,这是一个map,key为属性转化后的变量名,value是属性名。

       如果采用模板来写html标签功能不够强大,beetl支持写标签函数来实现html标签,标签函数args[0]表示标签名,args[1] 则是标签的属性,参数是个map,key是html tag的属性,value是其属性值,如下用java完成的html标签用于输出属性值:

public class SimpleHtmlTag extends Tag{
        @Override
        public void render(){
                String tagName = (String) this.args[0];
                Map attrs = (Map) args[1];
                String value = (String) attrs.get("attr");
                                //Map allColsDefine = (map)attrs.get("$cols");
                try{
                        this.ctx.byteWriter.writeString(value);
                }catch (IOException e){

                }
        }
}

       如果注册gt.registerTag("simpleTag", SimpleHtmlTag.class); 则如下模板输出了attr属性值abc。

<#simpleTag attr="abc"></#simpleTag>

       Beetl默认标签并不包含父子关系,如果想在标签传递参数,可以使用pageCtx函数

<#form>
<#input name="user"></#input>

</#form>

       form标签实现如下:

<%
var a = pageCtx("formParas",{"user":"abc"});
%>
<form>
${tagBody}
</form>

      input标签可以获取formParas参数:

<%
var all = pageCtx("formParas");
var value = all[name];
%>
<input name="${name}" value=${value} />

二十一、绑定变量的HTML标签

       对于html标签,Beetl还支持将标签实现类里的对象作为临时变量,被标签体引用。此时需要实现GeneralVarTagBinding (此类是Tag的子类) 。该类提供另外几个方法:1、void binds(Object… array) 子类在render方法里调用此类以实现变量绑定,绑定顺序同在模板中声明的顺序。2、void bind(String name, Object value) 子类在render方法里调用此类以实现变量绑定,name是模板中声明的变量名,用此方法绑定不如binds更灵活。3、Object getAttributeValue 获得标签的属性。4、Map getAttributes 获得标签的所有属性。

public class TagSample extends GeneralVarTagBinding{
        @Override
        public void render(){
                int limit = Integer.parseInt((String) this.getAttributeValue("limit"));
                for (int i = 0; i < limit; i++){
                        this.binds(i)
                        this.doBodyRender();
                }
        }
}
//在某处注册一下标签TagSample
//gt.registerTag("tag", TagSample.class);

       如上例子,render方法将循环渲染标签体limit次,且每次都将value赋值为i。模板的写法如下:

<#tag limit="3";value>
        ${value}
</#tag>

       类似于常规html标签,需要在标签的最后的属性定义后面加上分号 ";" 此分号表示这个是一个需要在标签运行时需要绑定变量的标签。后跟上要绑定的变量列表,如上例只绑定了一个value变量,如果需要绑定多个变量,则用逗号分开,如var1,var2 上。如果后面没有变量列表,只有分号,则默认绑定到标签名同名的变量上. 如果标签有namesapce,则默认绑定订的变量名不包含namespace。注意,由于标签使用因为太长可能换行或者是文本格式化导致换行,目前beetl只允许在属性之间换行,否则,将报标签解析错误。默认情况下,如果标签属性出现了var,也认为是绑定变量的标签,如上面的例子也可以这么写。

<#tag limit="3" var="value">
        ${value}
</#tag>

       var属性的值可以是个以逗号分开的变量名列表,如var="total,customer,index"。通过var定义的变量只能在标签体中使用,如果想定义一个能在标签体外能使用的变量,需要使用export。

<#define limit="3" expor="value"/>
${value}

二十二、直接调用java方法和属性

       可以通过符号@来表明后面表达式调用是java风格,可以调用对象的方法,属性:

${@user.getMaxFriend(“lucy”)}
${@user.maxFriend[0].getName()}
${@com.xxxx.constants.Order.getMaxNum()}
${@com.xxxx.User$Gender.MAN}
<%
var max = @com.xxxx.constants.Order.MAX_NUM;
var c =1;
var d = @user.getAge(c);
%>

二十三、严格MVC控制

       如果在配置文件中设置了严格MVC,则以下语法将不在模板文件里允许,否则将报出STRICK_MVC错误:1、定义变量,为变量赋值,如var a = 12是非法的。2、算术表达式 如${user.age+12}是非法的。3、除了只允许布尔以外,不允许逻辑表达式和方法调用 如if(user.gender==1)是非法的。4、方法调用,如${subString(string,1)}是非法的。5、Class方法和属性调用,如${@user.getName()}是非法的。6、严格的MVC,非常有助于逻辑与视图的分离,特别当逻辑与视图是由俩个团队来完成的。如果你嗜好严格MVC,可以调用groupTemplate.enableStrict()。

发布了253 篇原创文章 · 获赞 1152 · 访问量 50万+

猜你喜欢

转载自blog.csdn.net/gdkyxy2013/article/details/101194538