前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Beetl 基础知识

Beetl 基础知识

作者头像
Remember_Ray
发布2020-01-21 17:11:13
1.5K0
发布2020-01-21 17:11:13
举报
文章被收录于专栏:Ray学习笔记Ray学习笔记

引用属性

属性引用是模板中的重要一部分,beetl支持属性同javascript的支持方式一样,如下:

  1. Beetl支持通过”.”号来访问对象的的属性,如果javascript一样。如果User对象有个getName()方法,那么在模板中,可以通过${xxx.name}来访问
  2. 如果模板变量是数组或者List类,这可以通过[] 来访问,如${userList[0]}
  3. 如果模板变量是Map类,这可以通过[]来访问,如${map[“name”]},如果key值是字符串类型,也可以使用${map.name}.但不建议这么使用,因为会让模板阅读者误以为是一个Pojo对象
  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}.这跟javascript保持一致。但建议不这么做,因为容易让阅读模板的人误认为这是一个Map类型
  6. Beetl 还可以定义额外的对象属性,而无需更改java对象,这叫着虚拟属性,如,对于所有集合,数组,都有共同的虚拟属性size.虚拟属性是“.~”+虚拟属性名
代码语言:javascript
复制
template.binding("list",service.getUserList());
template.binding("pageMap",service.getPage());

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

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

逻辑表达式

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

代码语言:javascript
复制
<%
var a = 1;
var b="good";
var c = null;

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

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

代码语言:javascript
复制
<%
 var  a = 1 ;
%>
${a==1?"ok":''}
${a==1?"ok"}

循环语句

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

for-in

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

代码语言:javascript
复制
<%
for(user in userList){
        print(userLP.index);
        print(user.name);
}
%>

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

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

如何记住后缀是LP,有俩个诀窍,英语棒的是Loop的缩写,拼音好的是老婆的拼音缩写,这可以让程序员每次写到这的时候都会想想老婆(不管有没有,哈哈)

如下是Map使用例子

代码语言:javascript
复制
<%
for(entry in map){
        var key = entry.key;
        var value = entry.value;
        print(value.name);
}
%>

for(exp;exp;exp)

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

代码语言:javascript
复制
<%
var a = [1,2,3];
for(var i=0;i<a.~size;i++){
        print(a[i]);
}
%>

while

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

代码语言:javascript
复制
<%
var i = 0;
while(i<5){
        print(i);
        i++;
}
%>

elsefor

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

代码语言:javascript
复制
<%
var list = [];
for(item in list){

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

条件语句

if else

同js一样,支持if else,如下例子

代码语言:javascript
复制
<%
var a =true;
var b = 1;
if(a&&b==1){

}else if(a){

}else{

}
%>

switch-case

同js一样,支持switch-case,如下例子

代码语言:javascript
复制
<%
var b = 1;
switch(b){
        case 0:
                print("it's 0");
                break;
        case 1:
                print("it's 1");
                break;
        default:
                print("error");
}
%>

switch变量可以支持任何类型,而不像js那样只能是整形

select-case

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

代码语言:javascript
复制
<%
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.其格式是

代码语言:javascript
复制
<%
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,在渲染失败的时候仍然能保证输出正常

代码语言:javascript
复制
<%
try{
        callOtherSystemView()
}catch(error){
        print("暂时无数据");
}
%>

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

函数调用

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

代码语言:javascript
复制
<%
var date = date();
var len = strutil.length("cbd");
println("len="+len);
%>

定义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 函数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”),具体参考 https://git.oschina.net/xiandafu/beetl-json
  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();

安全输出

安全输出是任何一个模板引擎必须重视的问题,否则,将极大困扰模板开发者。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将会忽略此异常,继续渲染

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

代码语言:javascript
复制
<%
var k = user.name!'N/A'+user.age!;
%>
<%
${k}
%>

如果user为null,则k值将为N/A 在有些模板里,可能整个模板都需要安全输出,也可能模板的部分需要安全输出,使用者不必为每一个表达式使用!,可以使用beetl的安全指示符号来完成安全输出 如:

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

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

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

代码语言:javascript
复制
<%
var list = null;
for(item in list!){

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

变量是否存在

代码语言:javascript
复制
<%
if(has(flag)){
        print("flag变量存在,可以访问")
}
%>

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

代码语言:javascript
复制
<%
if(has(flag)&&flag==0){
        //code
}
%>

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

代码语言:javascript
复制
<%
if(flag!0==0){
        //code
}
%>

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

安全输出表达式

安全输出表达式可以包括

  • 字符串常量,如 ${user.count!”无结果”}
  • boolean常量 ${user.count!false}
  • 数字常量,仅限于正数,因为如果是负数,则类似减号,容易误用,因此,如果需要表示负数,请用括号,如${user.count!(-1)}
  • class直接调用,如${user.count!@User.DEFAULT_NUM}
  • 方法调用,如 ${user.count!getDefault() }
  • 属性引用,如 ${user.count!user.maxCount }
  • 任何表达式,需要用括号

格式化

几乎所有的模板语言都支持格式化,Beetl也不列外,如下例子Beetl提供的内置日期格式

代码语言:javascript
复制
<% 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 设置了了格式化函数,因此上面的例子可以简化为

代码语言:javascript
复制
${date,“yyyy-MM-dd”}

直接调用java方法和属性

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

代码语言:javascript
复制
${@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);
%>

可以调用instance的public方法和属性,也可以调用静态类的属性和方法 ,需要加一个 @指示此调用是直接调用class,其后的表达式是java风格的。

  • GroupTemplate可以配置为不允许直接调用Class,具体请参考配置文件.
  • 也可以通过安全管理器配置到底哪些类Beetl不允许调用,具体请参考高级用法。默认情况,java.lang.Runtime,和 java.lang.Process不允许在模板里调用。你自己的安全管理器也可以配置为不能直接访问DAO类(避免了以前jsp可以访问任意代码带来的危害)
  • 重要:请按照java规范写类名和方法名,属性名。这样便于beetl识别到底调用的是哪个类,哪个方法。否则会抛出错误
  • 可以省略包名,只用类名。beetl将搜索包路径找到合适的类(需要设置配置“IMPORT_PACKAGE=包名.;包名.”,包名后需要跟一个“.”, 或者调用Configuration.addPkg)方法具体请参考附件配置文件说明
  • 内部类(包括枚举)访问同java一样,如User类有个内部枚举类Gender,访问是User$Gender
  • 表达式是java风格,但参数仍然是beetl表达式,比如 @user.sayHello(user.name).这里user.sayHello是java调用,user.name 仍然是beetl表达式
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 逻辑表达式
  • 循环语句
    • for-in
      • for(exp;exp;exp)
        • while
          • elsefor
          • 条件语句
            • if else
              • switch-case
                • select-case
                  • try-catch
                  • 函数调用
                    • 常用的函数
                    • 安全输出
                    • 变量是否存在
                      • 安全输出表达式
                      • 格式化
                      • 直接调用java方法和属性
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档