6 Star 72 Fork 28

JustryDeng / notebook

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
[11]Beetl模板引擎.md 18.62 KB
一键复制 编辑 原始数据 按行查看 历史
邓沙利文 提交于 2022-04-28 09:38 . Beetl模板引擎.md

Beetl模板引擎

简介

Beetl( 发音同Beetle )相对于其他java模板引擎,具有功能齐全,语法直观,性能超高,以及编写的模板容易维护等特点。使得开发和维护模板有很好的体验。同时,Beetl具备引擎可定制性,可以打造自己的模板引擎。总得来说,它的特性如下:

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

使用方式

第一步:引入相关依赖

<dependency>
  <groupId>com.ibeetl</groupId>
  <artifactId>beetl</artifactId>
  <version>3.10.0.RELEASE</version>
</dependency>

第二步:编写模板

提示:为方便管理,我们一般把模板内容放在一个文件里,使用时读取该文件即可

<% for(user in list){ %>
hello  ${user.name}
<% } %>

提示:Beetl对模板文件的后缀名没啥要求,只要保证读出来是正常的文本内容即可。即:我们创建出来(用来放置模板内容的)模板文件的后缀名自取即可,可以是.txt、.html、.js、.sh、.abc之类的都行。

第三步:加载模板并渲染(返回/输出)结果

Beetl的核心是GroupTemplate,是一个重量级对象,实际使用的时候建议使用单模式创建,创建GroupTemplate需要2个参数,一个是模板资源加载器,一个是配置类,模板资源加载器Beetl内置了6种。

  • 方式一:StringTemplateResourceLoader:字符串模板加载器,用于加载字符串模板

    //初始化代码
    StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
    Configuration cfg = Configuration.defaultConfiguration();
    GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
    //获取模板(参数即为模板内容)
    Template t = gt.getTemplate("hello,${name}");
    t.binding("name", "beetl");
    /*
     * 渲染结果
     * template.render() 返回渲染结果
     * template.renderTo(Writer) 渲染结果输出到Writer里,如果你的Writer是一个FilterWriter,则可把输出保存到文件里
     * template.renderTo(OutputStream) 渲染结果输出到OutputStream里
     */
    String str = t.render();
    System.out.println(str);
  • 方式二:FileResourceLoader:文件模板加载器,需要一个根目录作为参数构造,传入getTemplate方法的String是模板文件相对于Root目录的相对路径

    String root = System.getProperty("user.dir")+File.separator+"template";
    FileResourceLoader resourceLoader = new FileResourceLoader(root,"utf-8");
    Configuration cfg = Configuration.defaultConfiguration();
    GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
    // 从指定文件中加载模板
    Template t = gt.getTemplate("/s01/hello.txt");
    /*
     * 渲染结果
     * template.render() 返回渲染结果
     * template.renderTo(Writer) 渲染结果输出到Writer里,如果你的Writer是一个FilterWriter,则可把输出保存到文件里
     * template.renderTo(OutputStream) 渲染结果输出到OutputStream里
     */
    String str = t.render();
    System.out.println(str);
  • 方式三:ClasspathResourceLoader:现代web应用最常用的文件模板加载器,模板文件位于Classpath

    /*
     * new ClasspathResourceLoader("org/beetl/sample/s01/"):指定org/beetl/sample/s01/的为模板文件的根目录
     * new ClasspathResourceLoader("template/"):指定template/的为模板文件的根目录
     * new ClasspathResourceLoader():默认即classpath的根目录就为模板文件的根目录
     */
    ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("org/beetl/sample/s01/");
    Configuration cfg = Configuration.defaultConfiguration();
    GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
    // 从指定文件中加载模板
    Template t = gt.getTemplate("/hello.txt");
    /*
     * 渲染结果
     * template.render() 返回渲染结果
     * template.renderTo(Writer) 渲染结果输出到Writer里,如果你的Writer是一个FilterWriter,则可把输出保存到文件里
     * template.renderTo(OutputStream) 渲染结果输出到OutputStream里
     */
    String str = t.render();
    System.out.println(str);
  • 方式四:WebAppResourceLoader:用于webapp集成,假定模板根目录就是WebRoot目录。

    使用相对较少,这里不多作说明

  • 方式五:MapResourceLoader:可以动态存入模板

    使用相对较少,这里不多作说明

  • 方式六:CompositeResourceLoader:混合使用多种加载方式

    使用相对较少,这里不多作说明

Configuration配置说明

我们在构造GroupTemplate时,需要传入对应的配置,这里对配置进行简单说明

#默认配置
# 模板引擎
ENGINE=org.beetl.core.engine.FastRutimeEngine
# 占位符 开始、结束标志
DELIMITER_PLACEHOLDER_START=${
DELIMITER_PLACEHOLDER_END=}
# 语句块 开始、结束标志
DELIMITER_STATEMENT_START=<%
DELIMITER_STATEMENT_END=%>
# 渲染结果直接输出为字节
DIRECT_BYTE_OUTPUT = FALSE
HTML_TAG_SUPPORT = true
HTML_TAG_FLAG = #
HTML_TAG_BINDING_ATTRIBUTE = var
NATIVE_CALL = TRUE
# 模板字符集
TEMPLATE_CHARSET = UTF-8
ERROR_HANDLER = org.beetl.core.ConsoleErrorHandler
NATIVE_SECUARTY_MANAGER= org.beetl.core.DefaultNativeSecurityManager
MVC_STRICT = FALSE

#资源配置,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
TAG.html.include= org.beetl.ext.tag.html.IncludeResourceHtmlTag
TAG.html.foreach= org.beetl.ext.tag.html.ForeachHtmlTag

注:Configuration.defaultConfiguration();方法加载的是位于/org/beetl/core/beetl-default.properties里的默认配置;一般的,我们使用默认配置即可。

常用模板语法

定界符与占位符

  • **定界符:**圈定一个范围,在这个范围内可以编写多个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中采用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;
    %>
  • **全局变量: ** 全局变量是通过在java代码里调用template.binding传入的变量,这些变量能在模板的任何一个地方,包括子模板都能访问到

    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);
  • 模板变量: 模板变量是一种特殊的变量,即可以将模板中任何一段的输出赋值到该变量,并允许稍后在其他地方使用

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

    注:模板变量是局部变量的一种拓展,类似于java中的共用方法逻辑抽取。

属性引用与赋值

  • 属性引用(示例说明)

    • 对象的访问:${name}
    • 对象属性的访问:${user.name}
    • 数组或List的访问:${userList[0]}
    • Map的访问:${map["name"]}
    • 数组/集合的长度访问:${userList.~size}~加上虚拟属性名,size是Beetl 对数组/集合默认内置的虚拟属性
  • 属性赋值(示例说明)

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

算数表达式

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支持类似JavaScriptJava的条件表达式,如 ><==!=>= , <= 以及 !, 还有 &&|| ,还有三元表达式

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

    if(a!=1 && b=="good" && c==null){
      ......
    }
%>
<%
 var  a = 1 ;
%>
${a==1 ? "ok" : ''}
${a==1 ? "ok"}

循环语句

  • for-in

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

    注:对于集合本身的属性,可通过后缀LP来获得:

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

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

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

    <%
    var list = [];
    for(item in list){
    
    }elsefor{
      print("未有记录");
    }
    %>

条件语句

  • if-else

    <%
    var a =true;
    var b = 1;
    if(a && b==1){
    
    }else if(a){
    
    }else{
    
    }
    %>
  • switch-case

    <%
    var b = 1;
    switch(b){
            case 0:
                    print("it's 0");
                    break;
            case 1:
                    print("it's 1");
                    break;
            default:
                    print("error");
    }
    %>
  • 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{
    callOtherSystemView()
  }catch(error){
    print("暂时无数据");
  }
%>

输出格式化

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

Beetl内置函数

  • date - 返回一个java.util.Date类型的变量,如date() 返回一个当前时间(对应java的java.util.Date); ${date( "2011-1-1" , "yyyy-MM-dd" )} 返回指定日期,date(ms),指定一个毫秒数。相当于调用java.util.Date(ms)
  • print - 打印一个对象 print(user.name);
  • println - 打印一个对象以及回车换行符号,回车换号符号使用的是模板本身的,而不是本地系统的.如果仅仅打印一个换行符,则直接调用println() 即可
  • nvl - 函数nvl,如果对象为null,则返回第二个参数,否则,返回自己 nvl(user,"不存在")
  • isEmpty - 判断变量或者表达式是否为空,变量不存在,变量为null,变量是空字符串,变量是空集合,变量是空数组,此函数都将返回true
  • isNotEmpty - 同上,判断对象是否不为空
  • has - 变量名为参数,判断是否存在此"全局变量",如 has(userList),类似于1.x版本的exist("userList"),但不需要输入引号了.注意,has和isEmpety 判断的是从java传到模板的全局变量,而不是临时变量
  • hasAttrbiute - 测试目标对象是否有此属性,hasAttribute(user,"name")
  • assert - 如果表达式为false,则抛出异常
  • trim - 截取数字或者日期,返回字符,如trim(12.456,2)返回"12.45",trim(date,'yyyy')返回"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();

更多功能

声明,本笔记只记录了最简单、最基本的功能的部分常用使用方式,更多使用方式、更多功能,详见官方文档或文末链接。

image-20220427235805277

相关资料

1
https://gitee.com/JustryDeng/notebook.git
git@gitee.com:JustryDeng/notebook.git
JustryDeng
notebook
notebook
master

搜索帮助