1.基本用法
1.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; %>
1.2.引用属性
属性引用是模板中的重要一部分,beetl支持属性同javascript的支持方式一样,如下
- Beetl支持通过”.”号来访问对象的的属性,如果javascript一样。如果User对象有个getName()方法,那么在模板中,可以通过${xxx.name}来访问
- 如果模板变量是数组或者List类,这可以通过[] 来访问,如${userList[0]}
- 如果模板变量是Map类,这可以通过[]来访问,如${map[“name”]},如果key值是字符串类型,也可以使用${map.name}.但不建议这么使用,因为会让模板阅读者误以为是一个Pojo对象
- Beetl也支持Generic Get方式,即如果对象有一个public Object get(String key)方法,可以通过”.”号或者[]来访问,譬如 ${activityRecord.name}或者${activityRecord[“name”] }都将调用activityRecord的 get(String key)方法。如果对象既有具体属性,又有Generic get(这种模型设计方式是不值得鼓励),则以具体属性优先级高.
- Beetl也可以通过[]来引用属性,如${user[“name”]} 相当于${user.name}.这跟javascript保持一致。但建议不这么做,因为容易让阅读模板的人误认为这是一个Map类型
- 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"]}
1.3.算数表达式
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,其后的计算和输出以及逻辑表达式都将按照长精度类型来考虑。
1.4.逻辑表达式
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"}
1.5.循环语句
Beetl支持丰富的循环方式,如for-in,for(exp;exp;exp),以及while循环,以及循环控制语句break;continue; 另外,如果没有进入for循环体,还可以执行elsefor指定的语句。
1.5.1. for-in
for-in循环支持遍历集合对象,对于List和数组来说以及Iterator,对象就是集合对象,对于Map来说,对象就是Map.entry,如下俩个例子
<% for(user in userList){ print(userLP.index); print(user.name); } %>
第三行代码userLP是Beetl隐含定义的变量,能在循环体内使用。其命名规范是item名称后加上LP,他提供了当前循环的信息,如
- userLP.index 当前的索引,从1开始
- 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); } %>
1.5.2. for(exp;exp;exp)
对于渲染逻辑更为常见的是经典的for循环语句,如下例子
<% var a = [1,2,3]; for(var i=0;i<a.~size;i++){ print(a[i]); } %>
1.5.3. while
对于渲染逻辑同样常见的有的while循环语句,如下例子
<% var i = 0; while(i<5){ print(i); i++; } %>
1.5.4. elsefor
不同于通常程序语言,如果没有进入循环体,则不需额外的处理,模板渲染逻辑更常见情况是如果没有进入循环体,还需要做点什么,因此,对于for循环来说,还有elsefor 用来表达如果循环体没有进入,则执行elsefor 后的语句
<% var list = []; for(item in list){ }elsefor{ print("未有记录"); } %>
1.6.条件语句
1.6.1. if else
同js一样,支持if else,如下例子
<% var a =true; var b = 1; if(a&&b==1){ }else if(a){ }else{ } %>
1.6.2. switch-case
同js一样,支持switch-case,如下例子
<% var b = 1; switch(b){ case 0: print("it's 0"); break; case 1: print("it's 1"); break; default: print("error"); } %>
switch变量可以支持任何类型,而不像js那样只能是整形
1.6.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"); } %>
1.7.安全输出
安全输出是任何一个模板引擎必须重视的问题,否则,将极大困扰模板开发者。Beetl中,如果要输出的模板变量为null,则beetl将不做输出,这点不同于JSP,JSP输出null,也不同于Freemarker,如果没有用!(感叹号),它会报错.
模板中还有俩种情况会导致模板输出异常
- 有时候模板变量并不存在(譬如子模板里)
- 模板变量为null,但输出的是此变量的一个属性,如${user.wife.name}
针对前俩种种情况,可以在变量引用后加上!以提醒beetl这是一个安全输出的变量。
如${user.wife.name!},即使user不存在,或者user为null,或者user.wife为null,或者user.wife.name为null beetl都不将输出
可以在!后增加一个常量(字符串,数字类型等),或者另外一个变量,方法,本地调用,作为默认输出,譬如:
${user.wife.name!”单身”},如果user为null,或者user.wife为null,或者user.wife.name为null,输出”单身”
譬如
${user.birthday!@System.constants.DefaultBir}, 表示如果user为null,或者user. birthday为null,输出System.constants.DefaultBir
还有一种情况很少发生,但也有可能,输出模板变量发生的任何异常,如变量内部抛出的一个异常
这需要使用格式${!(变量)},这样,在变量引用发生任何异常情况下,都不作输出,譬如
${!(user.name)},,beetl将会调用user.getName()方法,如果发生异常,beetl将会忽略此异常,继续渲染
1.7.1. 安全输出表达式
安全输出表达式可以包括
- 字符串常量,如 ${user.count!"无结果"}
- boolean常量 ${user.count!false}
- 数字常量,仅限于正数,因为如果是负数,则类似减号,容易误用,因此,如果需要表示负数,请用括号,如${user.count!(-1)}
- class直接调用,如${user.count!@User.DEFAULT_NUM}
- 方法调用,如 ${user.count!getDefault() }
- 属性引用,如 ${user.count!user.maxCount }
- 任何表达式,需要用括号
1.8. 格式化
几乎所有的模板语言都支持格式化,Beetl也不列外,如下例子Beetl提供的内置日期格式
<% var date = date(); %> Today is ${date,dateFormat="yyyy-MM-dd"}. Today is ${date,dateFormat} salary is ${salary,numberFormat="##.##"}
格式化函数只需要一个字符串作为参数放在=号后面,如果没有为格式化函数输入参数,则使用默认值,dateFormat格式化函数默认值是local
2.内置方法
2.1.常用内置方法
- date 返回一个java.util.Date类型的变量,如 date() 返回一个当前时间(对应java的java.util.Date); ${date( "2011-1-1" , "yyyy-MM-dd" )} 返回指定日期
- print 打印一个对象 print(user.name);
- println 打印一个对象以及回车换行符号,回车换号符号使用的是模板本身的,而不是本地系统的.如果仅仅打印一个换行符,则直接调用println() 即可
- nvl 函数nvl,如果对象为null,则返回第二个参数,否则,返回自己 nvl(user,"不存在")
- isEmpty 判断变量或者表达式是否为空,变量不存在,变量为null,变量是空字符串,变量是空集合,变量是空数组,此函数都将返回true
- isNotEmpty 同上,判断对象是否不为空
- has 变量名为参数,判断是否存在此全局变量,如 has(userList),类似于1.x版本的exist("userList"),但不需要输入引号了
- assert 如果表达式为false,则抛出异常
- trim 截取数字或者日期,返回字符,如trim(12.456,2)返回"12.45",trim(date,'yyyyy')返回"2017"
- trunc 截取数字,保留指定的小数位,如trunc(12.456,2) 输出是12.45.不推荐使用,因为处理float有问题,兼容原因保留了
- decode 一个简化的if else 结构,如 decode(a,1,"a=1",2,"a=2","不知道了")},如果a是1,这decode输出"a=1",如果a是2,则输出"a==2", 如果是其他值,则输出"不知道了"
- 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]
- parseInt 将数字或者字符解析为整形 如 parseInt("123");
- parseLong 将数字或者字符解析为长整形,parseInt(123.12);
- parseDouble 将数字或者字符解析为浮点类型 如parseDouble("1.23")
- range 接收三个参数,初始值,结束值,还有步增(可以不需要,则默认为1),返回一个Iterator,常用于循环中,如for(var i in range(1,5)) {print(i)},将依次打印1234.
- flush 强制io输出。
- json ,将对象转成json字符串,如 var data = json(userList) 可以跟一个序列化规则 如,var data = json(userList,"[*].id:i"),具体参考 https://git.oschina.net/xiandafu/beetl-json
- pageCtx ,仅仅在web开发中,设置一个变量,然后可以在页面渲染过程中,调用此api获取,如pageCtx("title","用户添加页面"),在其后任何地方,可以pageCtx("title") 获取该变量
- type.new 创建一个对象实例,如 var user = type.new("com.xx.User"); 如果配置了IMPORT_PACKAGE,则可以省略包名,type.new("User")
- type.name 返回一个实例的名字,var userClassName = type.name(user),返回"User"
- global 返回一个全局变量值,参数是一个字符串,如 var user = global("user_"+i);
- cookie 返回指定的cookie对象 ,如var userCook = cookie("user"),allCookies = cookie();
2.2.字符串相关方法
strutil方法对参数均不做空指针检测,你可自定义方法来覆盖这些内置的方法
- strutil.startWith ${ strutil.startWith(“hello”,”he”) 输出是true
- strutil.endWith ${ strutil.endWith(“hello”,”o”) 输出是true
- strutil.length ${ strutil. length (“hello”),输出是5
- strutil.subString ${ strutil.subString (“hello”,1),输出是“ello”
- strutil.subStringTo ${ strutil.subStringTo (“hello”,1,2),输出是“e”
- strutil.split ${ strutil.split (“hello,joeli”,”,”),输出是数组,第一个是字符串,第二个是正则表达式。返回第一个是hello,第二个是joelli”
- strutil.contain ${ strutil.contain (“hello,”el”),输出是true
- strutil.toUpperCase ${ strutil.toUpperCase (“hello”),输出是HELLO
- strutil.toLowerCase ${ strutil.toLowerCase (“Hello”),输出是hello
- strutil.replace ${ strutil.replace (“Hello”,”lo”,”loooo”),输出是helloooo
- strutil.format ${ strutil.format (“hello,{0}, my age is {1}”,”joeli”,15),输出是hello,joelli, my age is 15. 具体请参考 http://docs.oracle.com/javase/6/docs/api/java/text/MessageFormat.html
- strutil.trim 去掉字符串的尾部空格
- strutil.formatDate var a = strutil.formatDate(user.bir,’yyyy-MM-dd’);
- strutil.index var index = strutil.index("abc","a");返回 索引0
- strutil.lastIndex var index = strutil.lastIndex("aba","a");返回索引2
2.3.数组相关方法
- array.range 返回数组或者Collection一部分,接受三个参数,第一个是数组或者Collection子类,第二,三个参数分别是起始位置
- array.remove 删除某个数组或者Collection的一个元素,并返回该数组或者Collection.第一个是数组或者Collection子类,第二个参数是元素
- array.add 向数组或者Collection添加一个元素,并返回该数组或者Collection。第一个是数组或者Collection子类,第二个参数是元素
- array.contain 判断数组或者元素是否包含元素,如果包含,返回true。否则false。第一个是数组或者Collection子类,第二个参数是元素
- array.toArray 转化成数组,如array.toArray(1,2,"a");
- array.collection2Array 将java集合转化为数组 array.collection2Array([1,2,''])
2.4.正则表达式相关方法
- reg.match(str,regex) str为需要处理的字符串,regex是表达式
- reg.replace(str,regex,replace) ,str为需要处理的字符串,regex是表达式,替换的字符串替换字符串
- reg.find(str,regex) 返回找到的符合表达式的第一个字符串,否则返回空字符串
- reg.findList(str,regex) 找到所有符合表达式的字符串,否则返回空列表
- reg.split(str,regex) ,对字符串进行切分,返回列表
- reg.split(str,regex,limit) 同上,limit是最多返回个数
2.5.内置标签函数
include include一个模板,如 :
<% include("/header.html"){} %>
如果想往子模板中传入参数,则可以后面跟一个json变量
<% include("/header.html",{'user':user,'id':user.id}){} %>
这样user,和id 可以在header.html被引用,并成为header.html的全局变量