-
Notifications
You must be signed in to change notification settings - Fork 113
/
asciidoc-beetl.txt
executable file
·4129 lines (2704 loc) · 134 KB
/
asciidoc-beetl.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Beetl2.7使用说明书20161024
===================
李家智 <[email protected]>
:toc:
:icons:
:numbered:
:website: http://ibeetl.com/
== 什么是Beetl
Beetl目前版本是2.7.0,相对于其他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也支持自定义占位符和控制语句起始符号也支持使用者完全可以打造适合自己的工具包.
.关于性能
**********************************************************************
通过与主流模板引擎Freemarker,Vecloity以及JSP对比,Beetl6倍于Freemarker,2倍于JSP。这是因为宏观上,通过了优化的渲染引擎,IO的二进制输出,字节码属性访问增强,微观上,通过一维数组保存上下文Context,静态文本合并处理,通过重复使用字节数组来防止java频繁的创建和销毁数组,还使用模板缓存,运行时优化等方法。详情参考附录
**********************************************************************
.独特功能
**********************************************************************
Beetl有些功能是发展了10多年的模板引擎所不具备的,这些功能非常利于模板的开发和维护,如下
1. 自定义占位符和控制语句起始符号,这有利于减小模板语法对模板的倾入性,比如在html模板中,如果定义控制语句符号是`<!--:和 -->`,那么,大部分模板文件都能通过浏览器打开。有的使用者仅仅采用了单个符号@ (或者单个符号“~”)以及回车换号作为控制语句起始符号,这又能提高开发效率
2. 可单独测试的模板。无需真正的控制层和模型层,Beetl的模板就可以单独开发和*测试*
3. 同时支持较为松散的MVC和严格的MVC,如果在模板语言里嵌入计算表达式,复杂条件表达式,以及函数调用有干涉业务逻辑嫌疑,你可以禁止使用这些语法。
4. 强大的安全输出,通过安全输出符号!,能在模板变量,变量属性引用,for循环,占位符输出,try-catch中等各个地方提供安全输出,保证渲染正常
5.模板变量:运行将模板的某一部分输出像js那样赋值给一个变量,稍后再处理。利用模板变量能完成非常复杂的页面布局(简单的布局可使用include,layout标签函数)
6. 类型推测,能在运行的时候推测模板变量类型,从而优化性能,也可以通过注解的方法显示的说明模板变量属性(这是非必须的,但有助于IDE自动提示功能)
7. 可插拔的设计,错误信息提示,模板引擎缓存机制,模板资源管理,本地调用的安全管理器,严格MVC限制,模板引擎本身都有默认的实现,但又完全可以自定义以适合特定需求
8. 增强的语法,如for-elsefor, select-case,安全输出符号!,省略的三元表达式 等,这些语法特别适合模板开发
9. 局部渲染技术,结合现在js的ajax技术。
10. 性能超高,具有最快的模板解释引擎,同时,又有较低的CPU消耗。5-6倍于国内使用的Freemaker。适合各类模板应用,如代码生成工具,CMS系统,普通网站,超高访问量的门户系统,和富客户端JS框架整合的后台管理应用
**********************************************************************
.小白如何开始
**********************************************************************
- 需要通读基本用法,大部分都是讲解语法,而语法跟js很接近,所以可以快速预览,但Beetl是针对模板设计,
所以像安全输出,标签和html标签,全局变量,临时变量和共享变量,布局技术,以及直接调用java代码等还需要认真读一遍。
- 如果从事web开发,还需要阅读web集成里的第一节“web提供的全局变量”,如果web里还使用ajax技术,可以阅读“整合ajax的局部渲染技术”。
- 包含有spring,jfinal,jodd,struts 等demo可以作为参考学习用 http://ibeetl.com/community/?/article/4
- 任何问题,都可以在ibeetl.com 社区上提问。目前答复率是100%,提问需要详细说明自己的期望,出错信息,附上代码或者图片
**********************************************************************
.联系作者
**********************************************************************
作者:闲.大赋 (李家智)等(参考附录查看代码贡献者)
QQ技术交流群:219324263
Beetl社区:ibeetl.com
源码主页:https://github.com/javamonkey/beetl2.0
在线体验和代码分享 http://ibeetl.com:8080/beetlonline/
**********************************************************************
== 基本用法
=== 安装
如果使用maven,使用如下坐标
[source,xml]
----------------------------
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>2.7.0</version>
</dependency>
----------------------------
如果非maven工程,直接下载 http://git.oschina.net/xiandafu/beetl2.0/attach_files
=== 从GroupTemplate开始
[source,java]
----------------------------
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提供了多种获得渲染输出的方法,如下
- tempalte.render() 返回渲染结果,如本例所示
- template.renderTo(Writer) 渲染结果输出到Writer里
- template.renderTo(OutputStream ) 渲染结果输出到OutputStream里
*************************************************
1. 关于如何使用模板资源加载器,请参考下一节
2. 如何对模板进行配置,请参考下一节
*************************************************
=== 模板基础配置
Beetl提供不但功能齐全,而且还有很多独特功能,通过简单的配置文件,就可以定义众多的功能,默认情况下,Configuration类总是会先加载默认的配置文件(位于/org/beetl/core/beetl-default.properties,作为新手,**通常只需要关注3,4,5,6行定界符的配置,以及12行模板字符集的配置就可以了**,其他配置会在后面章节陆续提到)下,其内容片断如下:
[source,text]
----------------------------
#默认配置
ENGINE=org.beetl.core.engine.FastRuntimeEngine
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= /
#是否检测文件变化
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
----------------------------
第2行配置引擎实现类,默认即可.
第3,4行指定了占位符号,默认是${ }.也可以指定为其他占位符。
第5,6行指定了语句的定界符号,默认是<% %>,也可以指定为其他定界符号
第7行指定IO输出模式,默认是FALSE,即通常的字符输出,在考虑高性能情况下,可以设置成true。详细请参考高级用法
第8,9行指定了支持HTML标签,且符号为#,默认配置下,模板引擎识别<#tag ></#tag>这样的类似html标签,并能调用相应的标签函数或者模板文件。你也可以指定别的符号,如bg: 则识别<bg:
第10行 指定如果标签属性有var,则认为是需要绑定变量给模板的标签函数
第11行指定允许本地Class直接调用
第12行指定模板字符集是UTF-8
第13行指定异常的解析类,默认是ConsoleErrorHandler,他将在render发生异常的时候在后台打印出错误信息(System.out)。
第14行指定了本地Class调用的安全策略
第15行配置了是否进行严格MVC,通常情况下,此处设置为false.
第18行指定了默认使用的模板资源加载器
第20到22行配置了模板资源加载器的一些属性,如设置根路径为/,即Classpath的顶级路径,并且总是检测模板是否更改
第23行配置了自定义的方法所在的目录以及文件名后缀。beetl既支持通过java类定义方法,也支持通过模板文件来定义方法
第26行配置了自定义的html标签所在的目录以及文件名后缀。beetl既支持通过java类定义标签,也支持通过模板文件来定义标签
第31行注册了一个date方法,其实现类是org.beetl.ext.fn.DateFunction
第34行注册了一个方法包strutil,其实现类org.beetl.ext.fn.StringUtil,此类的每个public方法都将注册为beetl的方法
第37行注册了一个日期格式化函数
第40行注册了一个include标签函数
*************************************************
模板开发者可以创建一个beetl.properties的配置文件,此时,该配置文件将覆盖默认的配置文件属性,比如,你的定界符考虑是<!--: 和 --> ,则在beetl.properties加入一行即可,并将此配置文件放入Classpath根目录下即可。 Configuration.defaultConfiguration()总是先加载系统默认的,然后再加载Beetl.properties的配置属性,如果有重复,用后者代替前者的配置
[source,text]
----------------------------
#自定义配置
DELIMITER_STATEMENT_START=<!--:
DELIMITER_STATEMENT_END=-->
----------------------------
*************************************************
*************************************************
2.4.0 新功能:beetl 支持通过模板本生来完成函数,即模板函数,或者通过模板来实现HTML标签(而不用写java代码),可以beetl.properties为这种应用设置的不同的语句定界符来跟常规模板做区分,如下
[source,text]
----------------------------
FUNCTION_TAG_LIMITER=<%;%>
----------------------------
分号分割开,如果配置文件没有FUNCTION_TAG_LIMITER=,则模板函数,html标签使用同DELIMITER_STATEMENT_START,DELIMITER_STATEMENT_END
*************************************************
=== 模板资源加载器
资源加载器是根据String值获取Resource实例的工场类,同时资源加载器还要负责响应模板引擎询问模板是否变化的调用。对于新手来说,无需考虑模板资源加载器如何实现,只需要根据自己场景选择系统提供的三类模板资源加载器即可
==== 字符串模板加载器
在创建GroupTemplate过程中,如果传入的是StringTemplateResourceLoader,则允许通过调用gt.getTemplate(String template)来获取模板实例对象,如2.1所示
==== 文件资源模板加载器
更通常情况下,模板资源是以文件形式管理的,集中放在某一个文件目录下(如webapp的模板根目录就可能是WEB-INF/template里),因此,可以使用FileResourceLoader来加载模板实例,如下代码:
[source,java]
----------------------------
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");
String str = t.render();
System.out.println(str);
----------------------------
第1行代码指定了模板根目录,即位于项目工程下的template目录
第2行构造了一个资源加载器,并指定字符集为UTF-8 (也可不指定,因为配置文件默认就是UTF-8);
第5行通过模板的相对路径/s01/hello.txt来加载模板
==== Classpath资源模板加载器 ====
还有种常情况下,模板资源是打包到jar文件或者同Class放在一起,因此,可以使用ClasspathResourceLoader来加载模板实例,如下代码:
[source,java]
----------------------------
ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("org/beetl/sample/s01/”);
Configuration cfg = Configuration.defaultConfiguration(“);
GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
Template t = gt.getTemplate("/hello.txt");
String str = t.render();
System.out.println(str);
----------------------------
第1行代码指定了模板根目录,即搜索模板的时候从根目录开始,如果new ClasspathResourceLoader("template/"),则表示搜索template下的模板。此处用空构造函数,表示搜索路径是根路径,且字符集默认字符集UTF-8.
第4行通过模板的相对路径org/beetl/sample/s01/hello.txt来加载模板
==== WebApp资源模板加载器 ====
WebAppResourceLoader 是用于web应用的资源模板加载器,默认根路径是WebRoot目录。也可以通过制定root属性来设置相对于WebRoot的的模板根路径,从安全角考虑,建议放到WEB-INF目录下
如下是Jfinal集成 里初始化GroupTemplate的方法
[source,java]
----------------------------
Configuration cfg = Configuration.defaultConfiguration();
WebAppResourceLoader resourceLoader = new WebAppResourceLoader();
groupTemplate = new GroupTemplate(resourceLoader, cfg);
----------------------------
*************************************************
WebAppResourceLoader 假定 beetl.jar 是位于 WEB-INF/lib 目录下,因此,可以通过WebAppResourceLoader类的路径来推断出WebRoot路径从而指定模板根路径。所有线上环境一般都是如此,如果是开发环境或者其他环境不符合此假设,你需要调用resourceLoader.setRoot() 来指定模板更路径
*************************************************
==== 自定义资源模板加载器 ====
有时候模板可能来自文件系统不同目录,或者模板一部分来自某个文件系统,另外一部分来自数据库,还有的情况模板可能是加密混淆的模板,此时需要自定义资源加载,继承ResouceLoader才能实现模板功能,这部分请参考高级部分
=== 定界符与占位符号 ===
Beetl模板语言类似JS语言和习俗,只需要将Beetl语言放入定界符号里即可,如默认的是<% %> ,占位符用于静态文本里嵌入占位符用于输出,如下是正确例子
[source,javascript]
----------------------------
<%
var a = 2;
var b = 3;
var result = a+b;
%>
hello 2+3=${result}
----------------------------
千万不要在定界符里使用占位符号,因为占位符仅仅嵌在静态文本里,如下例子是**错误**例子
[source,javascript]
----------------------------
<%
var a = "hi";
var c = ${a}+"beetl"; //应该是var c = a+"beetl"
%>
----------------------------
每次有人问我如上例子为啥不能运行的时候,我总是有点憎恶velocity 带来的这种非人性语法
定界符和占位符 通常还有别的选择,如下定界符
- @ 和回车换行 (此时,模板配置DELIMITER_STATEMENT_END= 或者 DELIMITER_STATEMENT_END=null 都可以)
- #: 和回车换行
- <!--: 和 -->
- <!--# 和 -->
- <? 和 ?>
占位符:
- ~ ~
- #{ }
- # #
你也可以与团队达成一致意见来选择团队喜爱择定界符号和占位符号。
定界符号里是表达式,如果表达式跟定界符或者占位符有冲突,可以在用 “\” 符号,如
[source,javascript]
----------------------------
@for(user in users){
email is ${user.name}\@163.com
@}
${[1,2,3]} //输出一个json列表
${ {key:1,value:2 \} } //输出一个json map,} 需要加上\
----------------------------
=== 注释 ===
Beetl语法类似js语法,所以注释上也同js一样:
单行注释采用//
多行注视采用/**/
[source,javascript]
----------------------------
<%
/*此处是一个定义变量*/
var a = 3; //定义一个变量.
/* 以下内容都将被注释
%>
<% */ %>
----------------------------
第2行是一个多行注释
第3行是一个单行注释
第5行到第8行采用的是多行注释,因此里面有内容也是注释,模板将不予处理
=== 临时变量定义 ===
在模板中定义的变量成为临时变量,这类似js中采用var 定义的变量,如下例子
[source,javascript]
----------------------------
<%
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;
%>
----------------------------
=== 全局变量定义 ===
全局变量是通过template.binding传入的变量,这些变量能在模板的任何一个地方,包括子模板都能访问到。如java代码里
[source,java]
----------------------------
template.binding("list",service.getUserList());
//在模板里
<%
for(user in list){
%>
hello,${user.name};
<%}%>
----------------------------
=== 共享变量 ===
共享变量指在所有模板中都可以引用的变量,可过groupTemplate.setSharedVars(Map<String, Object> sharedVars)传入的变量,这些变量能在 *所有模板* 的任何一个地方
[source,java]
----------------------------
.....
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);
----------------------------
[source,javascript]
----------------------------
//t1.txt
hi,${name}
//t2.txt
hello,${name}
----------------------------
=== 模板变量 ===
模板变量是一种特殊的变量,即可以将模板中任何一段的输出赋值到该变量,并允许稍后在其他地方使用,如下代码
[source,javascript]
----------------------------
<%
var content = {
var c = "1234";
print(c);
%>
模板其他内容:
<%}; %>
----------------------------
第2行定义了一个模板变量content = { ...} ; 此变量跟临时变量一样,可以在其他地方使用,最常见的用户是用于复杂的布局。请参考高级用法布局
=== 引用属性 ===
属性引用是模板中的重要一部分,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.虚拟属性是“.~”+虚拟1属性名
[source,java]
----------------------------
template.binding("list",service.getUserList());
template.binding("pageMap",service.getPage());
//在模板里
总共 ${list.~size}
<%
for(user in list){
%>
hello,${user.name};
<%}%>
当前页${pageMap['page']},总共${pageMap["total"]}
----------------------------
=== 属性赋值 ===
Beetl2.7.0 开始支持对象赋值,如
[source,javascript]
----------------------------
<%
var user = ....
user.name="joelli";
user.friends[0] = getNewUser();
user.map["name"] = "joelli";
%>
----------------------------
=== 算数表达式 ===
Beetl支持类似javascript的算术表达式和条件表达式,如+ - * / % 以及(),以及自增++,自减--
[source,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,其后的计算和输出以及逻辑表达式都将按照长精度类型来考虑。
=== 逻辑表达式 ===
Beetl支持类似Javascript,java的条件表达式 如>, <, == ,!=,>= , <= 以及 !, 还有&&和 || ,还有三元表达式等,如下例子
[source,javascript]
----------------------------
<%
var a = 1;
var b=="good";
var c = null;
if(a!=1&&b=="good"&&c==null){
......
}
%>
----------------------------
三元表达式如果只考虑true条件对应的值的话,可以做简化,如下俩行效果是一样的。
[source,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,如下俩个例子
[source,javascript]
----------------------------
<%
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 索引是否是奇数
*************************************************
如何记住后缀是LP,有俩个诀窍,英语棒的是Loop的缩写,拼音好的是老婆的拼音缩写,这可以让程序员每次写到这的时候都会想想老婆(不管有没有,哈哈)
*************************************************
如下是Map使用例子
[source,javascript]
----------------------------
<%
for(entry in map){
var key = entry.key;
var value = entry.value;
print(value.name);
}
%>
----------------------------
==== for(exp;exp;exp) ====
对于渲染逻辑更为常见的是经典的for循环语句,如下例子
[source,javascript]
----------------------------
<%
var a = [1,2,3];
for(var i=0;i<a.~size;i++){
print(a[i]);
}
%>
----------------------------
==== while ====
对于渲染逻辑同样常见的有的while循环语句,如下例子
[source,javascript]
----------------------------
<%
var i = 0;
while(i<5){
print(i);
i++;
}
%>
----------------------------
==== elsefor ====
不同于通常程序语言,如果没有进入循环体,则不需额外的处理,模板渲染逻辑更常见情况是如果没有进入循环体,还需要做点什么,因此,对于for循环来说,还有elsefor 用来表达如果循环体没有进入,则执行elsefor 后的语句
[source,javascript]
----------------------------
<%
var list = [];
for(item in list){
}elsefor{
print("未有记录");
}
%>
----------------------------
=== 条件语句 ===
==== if else ====
同js一样,支持if else,如下例子
[source,javascript]
----------------------------
<%
var a =true;
var b = 1;
if(a&&b==1){
}else if(a){
}else{
}
%>
----------------------------
==== switch-case ====
同js一样,支持switch-case,如下例子
[source,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执行后就退出。
[source,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.其格式是
[source,javascript]
----------------------------
select {
case boolExp,orBoolExp2:
doSomething();
}
%>
----------------------------
[source,javascript]
----------------------------
<%
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,在渲染失败的时候仍然能保证输出正常
[source,javascript]
----------------------------
<%
try{
callOtherSystemView()
}catch(error){
print("暂时无数据");
}
%>
----------------------------
error代表了一个异常,你可以通过error.message 来获取可能的错误信息
也可以省略catch部分,这样出现异常,不做任何操作
=== 虚拟属性 ===
虚拟属性也是对象的属性,但是虚拟的,非模型对象的真实属性,这样的好处是当模板需要额外的用于显示的属性的时候但又不想更改模型,便可以采用这种办法
如beetl内置的虚拟属性.~size 针对了数组以及集合类型。
[source,javascript]
----------------------------
${user.gender}
${user.~genderShowName}
----------------------------
~genderShowName 是虚拟属性,其内部实现根据boolean变量gender来显示性别
如何完成虚拟属性,请参考高级用法
=== 函数调用 ===
Beetl内置了少量实用函数,可以在Beetl任何地方调用。如下例子是调用date 函数,不传参数情况下,返回当前日期
[source,javascript]
----------------------------
<%
var date = date();
var len = strutil.length("cbd");
println("len="+len);
%>
----------------------------
注意函数名支持namespace方式,因此代码第3行调用的函数是strutil.length
*************************************************
定义beetl的方法非常容易,有三种方法
- 实现Function类的call方法,并添加到配置文件里,或者显示的通过代码注册registerFunction(name,yourFunction)
- 可以直接调用registerFunctionPackage(namespace,yourJavaObject),这时候yourJavaObject里的所有public方法都将注册为Beetl方法,方法名是namespace+"."+方法名
- 可以直接写模板文件并且以html作为后缀,放到root/functions目录下,这样此模板文件自动注册为一个函数,其函数名是该模板文件名。
详情请参考高级用法
*************************************************
Beetl内置函数请参考附录,以下列出了常用的函数
- 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,则抛出异常
- trunc 截取数字,保留指定的小数位,如trunc(12.456,2) 输出是12.45
- 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"
=== 安全输出 ===
安全输出是任何一个模板引擎必须重视的问题,否则,将极大困扰模板开发者。Beetl中,如果要输出的模板变量为null,则beetl将不做输出,这点不同于JSP,JSP输出null,也不同于Feemarker,如果没有用!,它会报错.
模板中还有俩种情况会导致模板输出异常
- 有时候模板变量并不存在(譬如子模板里)
- 模板变量为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,输出”单身”
譬如
${[email protected]}, 表示如果user为null,或者user. birthday为null,输出System.constants.DefaultBir
还有一种情况很少发生,但也有可能,输出模板变量发生的任何异常,如变量内部抛出的一个异常
这需要使用格式${!(变量)},这样,在变量引用发生任何异常情况下,都不作输出,譬如
${!(user.name)},,beetl将会调用user.getName()方法,如果发生异常,beetl将会忽略此异常,继续渲染
值得注意的是,在变量后加上!不仅仅可以应用于占位符输出(但主要是应用于占位符输出),也可以用于表达式中,如:
[source,javascript]
----------------------------
<%