http://ibeetl.com/guide/
1. 什么是Beetl
Beetl目前版本是2.8.1,相对于其他java模板引擎,具有功能齐全,语法直观,性能超高,以及编写的模板容易维护等特点。使得开发和维护模板有很好的体验。是新一代的模板引擎。总得来说,它的特性如下:
功能完备:作为主流模板引擎,Beetl具有相当多的功能和其他模板引擎不具备的功能。适用于各种应用场景,从对响应速度有很高要求的大网站到功能繁多的CMS管理系统都适合。Beetl本身还具有很多独特功能来完成模板编写和维护,这是其他模板引擎所不具有的。
非常简单:类似Javascript语法和习俗,只要半小时就能通过半学半猜完全掌握用法。拒绝其他模板引擎那种非人性化的语法和习俗。同时也能支持html 标签,使得开发CMS系统比较容易
超高的性能:Beetl 远超过主流java模板引擎性能(引擎性能5-6倍与freemaker,2倍于JSP。参考附录),而且消耗较低的CPU。
易于整合:Beetl能很容易的与各种web框架整合,如Spring MVC,JFinal,Struts,Nutz,Jodd,Servlet等。
支持模板单独开发和测试,即在MVC架构中,即使没有M和C部分,也能开发和测试模板。
扩展和个性化:Beetl支持自定义方法,格式化函数,虚拟属性,标签,和HTML标签. 同时Beetl也支持自定义占位符和控制语句起始符号也支持使用者完全可以打造适合自己的工具包。
可以扩展为脚本引擎,规则引擎,能定制引擎从而实现高级功能。
关于性能
在使用FastRuntimeEngine情况下,通过与主流模板引擎Freemarker,Vecloity以及JSP对比,Beetl6倍于Freemarker,2倍于JSP。这是因为宏观上,通过了优化的渲染引擎,IO的二进制输出,字节码属性访问增强,微观上,通过一维数组保存上下文Context,静态文本合并处理,通过重复使用字节数组来防止java频繁的创建和销毁数组,还使用模板缓存,运行时优化等方法。详情参考附录
独特功能
Beetl有些功能是发展了10多年的模板引擎所不具备的,这些功能非常利于模板的开发和维护,如下
自定义占位符和控制语句起始符号,这有利于减小模板语法对模板的倾入性,比如在html模板中,如果定义控制语句符号是<!--:和-->,那么,大部分模板文件都能通过浏览器打开。有的使用者仅仅采用了单个符号@ (或者单个符号“~”)以及回车换号作为控制语句起始符号,这又能提高开发效率
可单独测试的模板。无需真正的控制层和模型层,Beetl的模板就可以单独开发和测试
同时支持较为松散的MVC和严格的MVC,如果在模板语言里嵌入计算表达式,复杂条件表达式,以及函数调用有干涉业务逻辑嫌疑,你可以禁止使用这些语法。
强大的安全输出,通过安全输出符号!,能在模板变量,变量属性引用,for循环,占位符输出,try-catch中等各个地方提供安全输出,保证渲染正常。
模板变量:运行将模板的某一部分输出像js那样赋值给一个变量,稍后再处理。利用模板变量能完成非常复杂的页面布局(简单的布局可使用include,layout标签函数)
类型推测,能在运行的时候推测模板变量类型,从而优化性能,也可以通过注解的方法显示的说明模板变量属性(这是非必须的,但有助于IDE自动提示功能)
可插拔的设计,错误信息提示,模板引擎缓存机制,模板资源管理,本地调用的安全管理器,严格MVC限制,模板引擎本身都有默认的实现,但又完全可以自定义以适合特定需求
增强的语法,如for-elsefor, select-case,安全输出符号!,省略的三元表达式 等,这些语法特别适合模板开发
局部渲染技术,结合现在js的ajax技术。
性能超高,具有最快的模板解释引擎,同时,又有较低的CPU消耗。5-6倍于国内使用的Freemaker。适合各类模板应用,如代码生成工具,CMS系统,普通网站,超高访问量的门户系统,和富客户端JS框架整合的后台管理应用
小白如何开始
需要通读基本用法,大部分都是讲解语法,而语法跟js很接近,所以可以快速预览,但Beetl是针对模板设计, 所以像安全输出,标签和html标签,全局变量,临时变量和共享变量,布局技术,以及直接调用java代码等还需要认真读一遍。
如果从事web开发,还需要阅读web集成里的第一节“web提供的全局变量”,如果web里还使用ajax技术,可以阅读“整合ajax的局部渲染技术”。
包含有spring,jfinal,jodd,struts 等demo可以作为参考学习用https://git.oschina.net/xiandafu 任何问题,都可以在ibeetl.com 社区上提问。目前答复率是100%,提问需要详细说明自己的期望,出错信息,附上代码或者图片
联系作者
作者:闲.大赋 (李家智)等(参考附录查看代码贡献者)
QQ技术交流群:219324263(满) 636321496
邮件:xiandafu@126.com
Beetl社区:bbs.ibeetl.com
源码主页:https://github.com/javamonkey/beetl2.0
在线体验和代码分享 http://ibeetl.com/beetlonline/
如果使用maven,请使用如下坐标
com.ibeetl
beetl
2.8.1
如果非maven工程,直接下载http://git.oschina.net/xiandafu/beetl2.0/attach_files
2.2. 从GroupTemplate开始
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);
Beetl的核心是GroupTemplate,创建GroupTemplate需要俩个参数,一个是模板资源加载器,一个是配置类,模板资源加载器Beetl内置了6种,分别是
StringTemplateResourceLoader:字符串模板加载器,用于加载字符串模板,如本例所示
FileResourceLoader:文件模板加载器,需要一个根目录作为参数构造,传入getTemplate方法的String是模板文件相对于Root目录的相对路径
ClasspathResourceLoader:文件模板加载器,模板文件位于Classpath里
WebAppResourceLoader:用于webapp集成,假定模板根目录就是WebRoot目录,参考web集成章
MapResourceLoader : 可以动态存入模板
CompositeResourceLoader 混合使用多种加载方式
代码第5行将变量name传入模板里,其值是“Beetl”。 代码第6行是渲染模板,得到输出,template提供了多种获得渲染输出的方法,如下
template.render() 返回渲染结果,如本例所示
template.renderTo(Writer) 渲染结果输出到Writer里
template.renderTo(OutputStream ) 渲染结果输出到OutputStream里
关于如何使用模板资源加载器,请参考下一节
如何对模板进行配置,请参考下一节
如果不想写代码直接体验Beetl,可以使用http://ibeetl.com/beetlonline/
2.3. 模板基础配置
Beetl提供不但功能齐全,而且还有很多独特功能,通过简单的配置文件,就可以定义众多的功能,默认情况下,Configuration类总是会先加载默认的配置文件(位于/org/beetl/core/beetl-default.properties,作为新手,通常只需要关注3,4,5,6行定界符的配置,以及12行模板字符集的配置就可以了,其他配置会在后面章节陆续提到,同时,对于Spring等框架,有些配置将会被这些框架的配置覆盖,需要参考后面章节)下,其内容片断如下:
#默认配置 ENGINE=org.beetl.core.engine.DefaultTemplateEngine DELIMITER_PLACEHOLDER_START=${ DELIMITER_PLACEHOLDER_END=} DELIMITER_STATEMENT_START= #资源配置,resource后的属性只限于特定ResourceLoader 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 这配置文件整体说明了Beetl提供的功能 第2行配置引擎实现类,默认即可. 第3,4行指定了占位符号,默认是${ },也可以指定为其他占位符。 第5,6行指定了语句的定界符号,默认是 ##内置的格式化函数 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 2.22. 标签函数 所谓标签函数,即允许处理模板文件里的一块内容,功能等于同jsp tag。如Beetl内置的layout标签 index.html #资源配置,resource后的属性只限于特定ResourceLoader #classpath 根路径 RESOURCE.root= / #是否检测文件变化 RESOURCE.autouCheck= true 第1行指定了模板加载器类,在beetl与其他框架集成的时候,模板加载器不一定根据这个配置,比如spring,它的RESOURCE_LOADER以spring的配置为准 第4行指定了模板根目录的路径,此处/ 表示位于classpath 根路径下,同loader一样,依赖使用的框架 第6行是否自动检测模板变化,默认为true,开发环境下自动检测模板是否更改。关于如何自定义ResouceLoader,请参考下一章 配置文件第三部分是扩展部分,如方法,格式化函数等 ##### 扩展 ############## ## 内置的方法 FN.date = org.beetl.ext.fn.DateFunction FN.nvl = org.beetl.ext.fn.NVLFunction …………….. ##内置的功能包 FNP.strutil = org.beetl.ext.fn.StringUtil ##内置的格式化函数 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 ## 标签类 TAG.include= org.beetl.ext.tag.IncludeTag TAG.includeFileTemplate= org.beetl.ext.tag.IncludeTag TAG.layout= org.beetl.ext.tag.LayoutTag TAG.htmltag= org.beetl.ext.tag.HTMLTagSupportWrapper FN前缀表示Function,FNP前缀表示FunctionPackage,FT表示format函数,FTC表示类的默认Format函数,TAG表示标签类。Beetl强烈建议通过配置文件加载扩展。以便随后IDE插件能识别这些注册函数 3.2. 自定义方法 3.2.1. 实现Function public class Print implements Function{ public String call(Object[] paras, Context ctx){ Object o = paras[0]; if (o != null){ try{ ctx.byteWriter.write(o.toString()); }catch (IOException e){ throw new RuntimeException(e); } } return “”; } } call方法有俩个参数,第一个是数组,这是由模板传入的,对应着模板的参数,第二个是Context,包含了模板的上下文,主要提供了如下属性 byteWriter 输出流 template 模板本身 gt GroupTemplate globalVar 该模板对应的全局变量 byteOutputMode 模板的输出模式,是字节还是字符 safeOutput 模板当前是否处于安全输出模式 其他属性建议不熟悉的开发人员不要乱动 call方法要求返回一个Object,如果无返回,返回null即可 为了便于类型判断,call方法最好返回一个具体的类,如date函数返回的就是java.util.Date call方法里的任何异常应该抛出成Runtime异常 3.2.2. 使用普通的java类 尽管实现Function对于模板引擎来说,是效率最高的方式,但考虑到很多系统只有util类,这些类里的方法仍然可以注册为模板函数。其规则很简单,就是该类的所有public方法。如果还需要Context 变量,则需要在方法最后一个参数加上Context即可,如 public class util{ public String print(Object a, Context ctx){ //balabala… } } 注意 从beetl效率角度来讲,采用普通类效率不如实现Function调用 采用的普通java类尽量少同名方法。这样效率更低。beetl调用到第一个适合的同名方法。而不像java那样找到最匹配的 方法名支持可变数组作为参数 方法名最后一个参数如果是Context,则beetl会传入这个参数。 3.2.3. 使用模板文件作为方法 可以不用写java代码,模板文件也能作为一个方法。默认情况下,需要将模板文件放到Root的functions目录下,且扩展名为.html(可以配置文件属性来修改这俩个默认值) 方法参数分别是para0,para1….. 如下root/functions/page.fn #ajax userTable: { %>id | 姓名 |
4.13. 在页面输出错误提示信息
2.2.3版本以后,新增加org.beetl.ext.web.WebErrorHandler,可以在web开发的时候在页面输出提示信息,在产品模式下在后台输出提示信息(通过配置属性ESOURCE.autoCheck= true来认为是开发模式),仅仅需要配置如下:
ERROR_HANDLER = org.beetl.ext.web.WebErrorHandler
附录
5.1. 内置方法
5.1.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();
5.1.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
5.1.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,''])
5.1.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是最多返回个数
5.1.5. Spring 相关函数
Spring函数并没有内置,需要注册,如下
spel(spelString, rootObject) SpEL方法传入一个Spring SpEL表达式以获取表达式结果,方法建议以函数的方式定义在BeetlGroupUtilConfiguration的functions中
spelString: SpEL表达式字符串,必传(否则返回null) rootObject: 作为spel的根对象(对应#root),可以是一个Map或Bean对象,默认取空Map。由于Beetl运行上下文无法直接获取模版局部变量的变量名,建议局部变量采用自定义Map的方式传入
列表筛选(以自定义Map为根对象传入局部变量)
<% var intArray = [12, 1, 2, 3]; %>
${spel('#root.intArray.?[#this>10]', {intArray: intArray})}
以Bean对象为根对象
<% var now = date(); %>
${spel('#root.year + 1900', now)}
直接new对象
${spel('(new java.util.Date()).year + 1900')}
直接引用Spring Bean
${spel('@testBean')}
默认变量
#root 表示SpEL的根对象, 由spel函数第二参数传入,默认是一个空map
#context 表示Beetl执行上下文
#global 表示Beetl的共享变量Map,由于Beetl上下文无法获取临时变量名,临时变量建议使用根对象的方式传入
#ctxPath 表示Servlet Context Path(由Beetl WebRender提供)
#servlet 可以从中获取到Servlet request,response,session原生实例(由Beetl WebRender提供)
#parameter 表示请求参数Map(由Beetl WebRender提供)
#request 表示请求对象(由Beetl WebRender提供)
#session 表示会话域属性Map(由Beetl WebRender提供)
sputil 提供了spring内置的一些功能,如
// 测试source中是否包含了candidates的某个成员(相当于交集非空)
sputil.containsAny(Collection