1. beetl的安装

  • 使用maven:
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>2.9.3</version>
</dependency>
  • 非maven项目:https://gitee.com/xiandafu/beetl2.0/attach_files

2. beetl的基本使用

 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);

  先选择模板资源加载器和配置类;然后通过这两个创建GroupTemplate(建议使用单模式创建);通过GroupTemplate对象加载模板得到模板对象,就可以对模板进行一系列的操作

3. 模板资源加载器的种类

  • StringTemplateResourceLoader:字符串模板加载器,用于加载字符串模板
  • FileResourceLoader:文件模板加载器,需要一个根目录作为参数构造,传入getTemplate方法的String是模板文件相对于根目录的相对路径
  • ClasspathResourceLoader:文件模板加载器,模板文件位于Classpath里
  • WebAppResourceLoader:用于webapp集成,假定模板根目录就是WebRoot目录
  • MapResourceLoader : 可以动态存入模板
  • CompositeResourceLoader:混合使用多种加载方式
  • 自定义资源模板加载器:有时候模板可能来自文件系统不同目录,或者模板一部分来自某个文件系统,另外一部分来自数据库,还有的情况模板可能是加密混淆的模板,此时需要自定义资源加载,继承ResouceLoader才能实现模板功能

4. 模板基础配置
  Beetl建议通过配置文件配置GroupTemplate,主要考虑到IDE插件未来可能会支持Beetl模板,模板的属性,和函数等如果能通过配置文件获取,将有助于IDE插件识别。 配置GroupTemplate有俩种方法

  • 配置文件: 默认配置在/org/beetl/core/beetl-default.properties 里,Beetl首先加载此配置文件,然后再加载classpath里的beetl.properties,并用后者覆盖前者。配置文件通过Configuration类加载,因此加载完成后,也可以通过此类API来修改配置信息
  • 通过调用GroupTemplate提供的方法来注册函数,格式化函数,标签函数等

  配置文件分为三部分,第一部分是基本配置,第二部分是资源类配置,可以在指定资源加载类,以及资源加载器的属性(这个配置在spring框架里,通过spring或者springboot的配置机制实现覆盖,并未起作用)

5. 定界符:Beetl模板语言书写区间标识,类似于JSP的<% %>,可以在开始标识和结束标识之间书写模板语言代码;可以通过基本配置进行配置自己的定界符;如果代码中使用到定界符符号,可以使用转义字符"\";定界符内不能使用占位符,而是直接使用变量;模板语言类似于js语法。

6. 占位符:类似于JSP的<%= %>表达式;在模板中直接使用变量,不能在定界符内使用;可以通过基本配置进行配置自己的占位符。

7. 注释:定界符内的注释与js语法的单行多行注释一样,都是采用// 或 /* */

8. 临时变量定义:模板中定义的变量,只能在模板内访问;var 变量名 = 值

9. 全局变量定义:能在整个模板及子模板访问的变量;只能通过java代码使用模板对象的binding方法加入;2.8版本以后加入了一个默认的root变量,当找不到变量时,会去root中查找,加入root变量需要使用binding方法加入

key='_root'

10. 共享变量:所有模板中都可以引用的变量;需要在GroupTemplate对象中调用.setSharedVars(Map<String, Object> sharedVars)传入变量

11. 模板变量:与临时变量不同的是,定义包住了用到它的模板内容

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

12. 引用变量:

  • 对象:支持通过”.”号来访问对象的的属性,如果javascript一样。如果User对象有个getName()方法,那么在模板中,可以通过${xxx.name}来访问;也可以通过[]来引用属性,如${user[“name”]} 相当于${user.name},这跟javascript保持一致。但建议不这么做,因为容易让阅读模板的人误认为这是一个Map类型
  • 数组:如果模板变量是数组或者List类,这可以通过[] 来访问,如${userList[0]} map:如果模板变量是Map类,这可以通过[]来访问,如${map[“name”]},如果key值是字符串类型,也可以使用${map.name}.但不建议这么使用,因为会让模板阅读者误以为是一个Pojo对象
  • Generic Get方式:即如果对象有一个public Object get(String key)方法,可以通过”.”号或者[]来访问,譬如 ${activityRecord.name}或者${activityRecord[“name”] }都将调用activityRecord的 get(String key)方法。如果对象既有具体属性,又有Generic get(这种模型设计方式是不值得鼓励),则以具体属性优先级高.
  • 虚拟属性:还可以定义额外的对象属性,而无需更改java对象,这叫做虚拟属性,如,对于所有集合,数组,都有共同的虚拟属性size.虚拟属性是“.~”+虚拟属性名

13. 属性赋值:与JS相同(对象、数组、map)

14. 表达式

  • 算术表达式:【+】【-】【*】【/】【%】【()】【++】【--】
  • 逻辑表达式:【<】【>】【==】【!=】【>=】【<=】【!】【&&】【||】【?:】(三元表达式如果只考虑true条件对应的值的话,可以省略:及后面的)

15. 循环语句

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

   在循环体内能使用隐含定义的变量;其命名规范是item名称后加上LP,如例子中的userLP;隐含的变量如下:

    • userLP.index 当前的索引,从1开始
    • 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(表达如果循环体没有进入,则执行elsefor 后的语句)
<%
var list = [];
for(item in list){ }elsefor{
print("未有记录");
}
%>

16. 条件语句

  • if-else(与JS一样)
  • switch-case(与JS一样,但switch变量可以支持任何类型)
  • 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();
}
%>

17. 异常捕获 try-catch(与JS一样,通过.message获得异常信息)

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

19. 函数调用:Beetl内置了少量实用函数,可以在Beetl任何地方调用;函数名支持namespace方式

  • 定义beetl的方法非常容易,有三种方法(详细看官网文档高级功能部分)

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

20. 安全输出

  • 说明

    • 如果要输出的模板变量为null,则beetl将不做输出
    • 模板中有两种情况会导致模板输出异常;
    • 有时候模板变量并不存在(譬如子模板里)
    • 模板变量为null,但输出的是此变量的一个属性,如${user.wife.name}
    • 可以在变量引用后加上!以提醒beetl这是一个安全输出的变量,如${user.wife.name! }
    • 可以在!后增加一个常量(字符串,数字类型等),或者另外一个变量,方法,本地调用,作为默认输出,${user.wife.name!”单身”}
    • 输出模板变量发生的任何异常,如变量内部抛出的一个异常,这需要使用格式${!(变量)},这样,在变量引用发生任何异常情况下,都不作输出;在变量后加上!不仅仅可以应用于占位符输出(但主要是应用于占位符输出),也可以用于表达式中
    • 在有些模板里,可能整个模板都需要安全输出,也可能模板的部分需要安全输出,使用者不必为每一个表达式使用!,可以使用beetl的安全指示符号来完成安全输出 如:
<%
DIRECTIVE SAFE_OUTPUT_OPEN;
%>
${user.wife.name}
模板其他内容,均能安全输出……
<%
//关闭安全输出。
DIRECTIVE SAFE_OUTPUT_CLOSE;
%>
  • 安全输出表达式

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

21.格式化

  • 格式化函数只需要一个字符串作为参数放在=号后面,如果没有为格式化函数输入参数,则使用默认值,dateFormat格式化函数默认值是local,如${date,dateFormat="yyyy-MM-dd"}、${salary,numberFormat="##.##"}
  • Beetl也允许为指定的java class设定格式化函数,譬如已经内置了对java.util.Date,java.sql.Date 设置了了格式化函数,因此上面的例子可以简化为${date,“yyyy-MM-dd”}
  • Beetl针对日期和数字类型提供的默认的格式化函数,在org/beetl/core/beetl-default.properties里注册了
  • 自定义格式化函数(详细看官网文档高级部分)

22. 标签函数(所谓标签函数,即允许处理模板文件里的一块内容,功能等于同jsp tag)

  • layout("/inc/layout.html",{title:'主题'}){}
  • include("/inc/header.html"){}

23. HTML标签

  • 自定义html标签规则

    • 可以在自定义标签里引用标签体的内容,标签体可以是普通文本,beetl模板,以及嵌套的自定义标签等
    • 可以在属性标签里引用beetl变量,如<#input value="${user.age}" />
    • 在属性里引用beetl变量,不支持格式化,如<#input value="${user.date,'yyyy-MM-dd'}"/>,如果需要格式化,需要在input.tag文件里自行格式化
    • 在标签属性里传json变量需要谨慎,因为json包含了"}",容易与占位符混合导致解析出错,因此得使用"\"符号,如<#input value="${ {age:25\} }" />
    • html tag 属性名将作为 其对应模板的变量名。如果属性名包含“-”,则将转为驼峰命名的变量,如data-name,转为dataName
    • 默认机制下,HTMLTagSupportWrapper2 实现了标签(2.8.x以前使用HTMLTagSupportWrapper)

24. 绑定变量的HTML标签

25. 直接调用java方法和属性

  • 可以通过符号@来表明后面表达式调用是java风格,可以调用对象的方法,属性
  • GroupTemplate可以配置为不允许直接调用Class
  • 可以通过安全管理器配置到底哪些类Beetl不允许调用;默认情况,java.lang.Runtime,和 java.lang.Process不允许在模板里调用
  • 请按照java规范写类名和方法名,属性名。这样便于beetl识别到底调用的是哪个类,哪个方法。否则会抛出错误
  • 可以省略包名,只用类名。beetl将搜索包路径找到合适的类(需要设置配置“IMPORT_PACKAGE=包名.;包名.”,包名后需要跟一个“.”, 或者调用Configuration.addPkg)方法
  • 内部类(包括枚举)访问同java一样,如User类有个内部枚举类Gender,访问是User$Gender
  • 表达式是java风格,但参数仍然是beetl表达式,比如 @user.sayHello(user.name).这里user.sayHello是java调用,user.name 仍然是beetl表达式

26. 严格MVC控制:如果在配置文件中设置了严格MVC,则以下语法将不在模板文件里允许,否则将报出STRICK_MVC 错误
定义变量,为变量赋值,如var a = 12是非法的

  • 算术表达式 如${user.age+12}是非法的
  • 除了只允许布尔以外,不允许逻辑表达式和方法调用 如if(user.gender==1)是非法的
  • 方法调用,如${subString(string,1)}是非法的
  • Class方法和属性调用,如${@user.getName()}是非法的
  • 严格的MVC,非常有助于逻辑与视图的分离,特别当逻辑与视图是由俩个团队来完成的。如果你嗜好严格MVC,可以调用groupTemplate.enableStrict()
  • 通过重载AntlrProgramBuilder,可以按照自己的方法控制到底哪些语法是不允许在模板引擎中出现的

27. 指令

  • 指令格式为: DIRECTIVE 指令名 指令参数(可选) Beetl目前支持安全输出指令,分别是

    • DIRECTIVE SAFE_OUTPUT_OPEN ; 打开安全输出功能,此指令后的所有表达式都具有安全输出功能,
    • DIRECTIVE SAFE_OUTPUT_CLOSE ; 关闭安全输出功能。
    • DIRECTIVE DYNAMIC varName1,varName2 …指示后面的变量是动态类型,Beetl应该考虑为Object. 也可以省略后面的变量名,则表示模板里所有变量都是Object

28. 类型声明

  • Beetl 本质上还是强类型的模板引擎,即模板每个变量类型是特定的,在模板运行过程中,beetl 会根据全局变量自动推测出模板中各种变量和表达式类型。 也可以通过类型申明来说明beetl全局变量的类型
  • 类型申明必须放到多行注释里,格式是@type( … ),里面的申明类似java方法的参数申明。正如你看到的类型申明是在注释里,也就表明了这在Beetl模板引擎中不是必须的,或者你只需要申明一部分即可
<%
/**
*@type (List<User> idList,User user)
*/
for(value in idList) .....
  • 之所以提供可选的类型说明,是因为

    • 提高一点性能
    • 最重要的是,提高了模板的可维护性。可以让模板维护者知道变量类型,也可以让未来的ide插件根据类型声明来提供属性提示,重构等高级功能
  • 要注意的是,如果在类型声明里提供的是类名,而不是类全路径,这样必须在配置文件里申明类的搜索路径((需要设置配置IMPORT_PACKAGE=包名.;包名.,或者调用Configuration.addPkg)),默认的搜索路径有java.util. 和
  • java.lang.

29. 错误处理

  • Beetl能较为详细的显示错误原因,包括错误行数,错误符号,错误内容附近的模板内容,以及错误原因,如果有异常,还包括异常和异常信息。 默认情况下,仅仅在控制台显示
  • 默认的错误处理器仅仅像后台打印错误,并没有抛出异常,如果需要在render错误时候抛出异常到控制层,则可以使用org.beetl.core.ReThrowConsoleErrorHandler。不仅打印异常,还抛出BeetlException
  • 可以自定义异常处理器,比如把错误输出到 作为渲染结果一部分输出,或者输出更美观的html内容等
  • 可以在配置文件不设置异常,这样Beetl引擎将不处理异常,用户可以在外部来处理(可以在外部调用ErrorHandler子类来显示异常)

30. Beetl小工具

  • BeetlKit 提供了一些便利的方法让你立刻能使用Beetl模板引擎

    • public static String render(String template, Map<String, Object> paras) 渲染模板,使用paras参数,渲染结果作为字符串返回
    • public static void renderTo(String template, Writer writer, Map<String, Object> paras) 渲染模板,使用paras参数
    • public static void execute(String script, Map<String, Object> paras) 执行某个脚本
    • public static Map execute(String script, Map<String, Object> paras, String[] locals) 执行某个脚本,将locals指定的变量名和模板执行后相应值放入到返回的Map里
    • public static Map executeAndReturnRootScopeVars(String script) 执行某个脚本,返回所有顶级scope的所有变量和值
    • public static String testTemplate(String template, String initValue) 渲染模板template,其变量来源于intValue脚本运行的结果,其所有顶级Scope的变量都将作为template的变量
  • BeetlKit 不要用于线上系统。仅仅作为体验Beetl功能而提供的

31. 琐碎功能

  • 对齐:我发现别的模板语言要是做到对齐,非常困难,使用Beetl你完全不用担心,比如velocty,stringtemlate,freemarker例子都出现了不对齐的情况,影响了美观,Beetl完全无需担心输出对齐
  • Escape:可以使用\ 做escape 符号,如\$monkey\$ 将作为一个普通的文本,输出为$monkey$.再如为了在后加上美元符号(占位符恰好又是美元符号)可以用这俩种方式hello,it’s $money$\$, 或者Hello,it’s $money+"\$"$。如果要输出\符号本身,则需要用俩个\,这点与javascript,java 语义一致.

32. Web集成

2019-04-18 Beetl模板学习的更多相关文章

  1. 2019.04.18 第六次训练 【2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage】

    题目链接: https://codeforces.com/gym/101911 又补了set的一个知识点,erase(it)之后it这个地址就不存在了,再引用的话就会RE A: ✅ B:  ✅ C: ...

  2. 2019.04.18 读书笔记 深入string

    整个.net中,最特殊的就是string类型了,它有着引用类型的特性,又有着值类型的操作方式,最特殊的是,它还有字符串池,一个字符串只会有一个实例(等下就推翻!). 鉴于之前的<==与Equal ...

  3. 2019 年起如何开始学习 ABP 框架系列文章-开篇有益

    2019 年起如何开始学习 ABP 框架系列文章-开篇有益 [[TOC]] 本系列文章推荐阅读地址为:52ABP 开发文档 https://www.52abp.com/Wiki/52abp/lates ...

  4. PowerBI更新2019/04 - 解决方案架构 - PowerBI Solution Architecture(一图胜万字!)

    Power BI 架构图 (2019/04) 1) Power BI Desktop 是一个免费的工具.它可以用来准备和管理数据模型:包括链接各种数据:做数据清洗:定义关系:定义度量值和层级关系:应用 ...

  5. 每日一练ACM 2019.04.13

    2019.04.13 第1002题:A+B Proble Ⅱ Problem DescriptionI have a very simple problem for you. Given two in ...

  6. 2019.3.18考试&2019.3.19考试&2019.3.21考试

    2019.3.18 C O D E T1 树上直接贪心,环上for一遍贪心 哇说的简单,码了将近一下午终于码出来了 感觉自己码力/写题策略太糟糕了,先是搞了一个细节太多的写法最后不得不弃疗了,然后第二 ...

  7. Wed Jul 04 18:01:38 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended

    Wed Jul 04 18:01:38 CST 2018 WARN: Establishing SSL connection without server's identity verificatio ...

  8. Beetl模板引擎入门教程

    最近项目中有个邮件发送的需求,不过要求发送的HTML格式的邮件.由于Beetl对java语言的良好支持和很好的性能,我们决定使用Beetl作为我们的模板引擎. Beetl官网已经有了很详细的教程,所以 ...

  9. “全栈2019”22篇Java异常学习资料及总结

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"22篇Ja ...

随机推荐

  1. 初探Parcel

    昨天趁有点时间看了前不久很火的构建工具Parcel,这里说下初步使用的感受,尤其是将其放到实际项目中和Webpack进行比较. 一.前言 首先说下笔者目前的技术栈.最近的前端项目主要以管理后台为主,技 ...

  2. Vue全家桶(Vue-cli、Vue-route、vuex)

    摘要 学习本篇之前要具备一定的vue基础知识,可以先看一下Vue基础(环境配置.内部指令.全局API.选项.内置组件) 1.Vue-cli Vue-cli是vue官方出品的快速构建单页应用的脚手架,这 ...

  3. ado.net的简单数据库操作(二)之封装SqlHelperl类

    今天我书接上回,接着昨天的ado.net的数据库操作的相关知识来讲哈! 从上篇文章给出的实例来看,你一定会发现,操作数据库其实还挺麻烦的,就连一个最简单的数据库操作语句都要包括 定义数据库连接字符串. ...

  4. .NET Core和.NET Standard有什么不同

        近日,微软发布了.NET Core 2.0,但是开发人员中间仍然存在一些疑惑,就是.NET Core..NET Standard.Xamarin和.NET Framework有什么不同. .N ...

  5. c#实战开发:以太坊钱包快速同步区块和钱包卡死解决方案 (三)

    首先以太坊默认的快速同步模式 我们需要先设置当前同步模式内存大小512-2048范围 在服务器配置情况下最大化内存 输入以下命令 geth --fast --cache=2048 最快同步模式也是 保 ...

  6. OGNL详解

    A.什么是OGNL? 全称叫ObjectGraphic Navigation Language(对象图导航语言),它是struts2框架里面的第三方语言(即可以再别的地方用,struts2只是拿过来了 ...

  7. TrieTree

    学习链接:https://blog.csdn.net/lisonglisonglisong/article/details/45584721 前缀树解决字符串前缀匹配问题,查找单词是否存在,统计以如“ ...

  8. JavaScript常用代码书写规范

    javascript 代码规范 代码规范我们应该遵循古老的原则:“能做并不意味着应该做”. 全局命名空间污染 总是将代码包裹在一个立即的函数表达式里面,形成一个独立的模块. 不推荐 , y = ; c ...

  9. Apache2配置多域名站点及支持https

    0x00 预备条件 申请SSL证书 建立对应站点目录 开放443端口 0x01 配置sites-available文件 执行 vi /etc/apache2/sites-available/zecoc ...

  10. Android为TV端助力 电影栏目移动到底部或者顶部时抖动动画

    1 移动到底部上下抖动ObjectAnimator animatorX = ObjectAnimator.ofFloat(holder.itemView,"translationX" ...