Java 模板引擎:webit-script
Java 模板引擎,基于java 5 開發,不依賴其他第三方庫,弱類型,語法類似于Javascript。
How to use(如何使用)
Maven
<repositories>
<repository>
<id>webit-script</id>
<name>Webit script</name>
<url>http://zqq90.github.io/maven/</url>
</repository>
</repositories>
<dependencies>
...
<dependency>
<groupId>com.github.zqq90.webit-script</groupId>
<artifactId>webit-script</artifactId>
<version>1.2.1</version>
</dependency>
...
</dependencies>
Or Add jars
webit-script-1.2.1.jar
Code in Java like this
// !! engine 并不會被緩存, 請根據需要自行實現 Engine的單例模式
Engine engine = Engine.createEngine("/webit-script-config.props", extraSettingsMap);
...
// template 已緩存, 線程安全, 并自動檢測模板源是否被更新
// 當然您也可以緩存 Template 實例,模板更新時更新實例內部AST, 其實例不會變化
Template template = engine.getTemplate("/your/template/path/filename.ext");
...
template.merge(parametersMap, outputStream);
//template.merge(parametersMap, writer);
Config(配置)
- 配置文件格式: Use Jodd-props, see:Jodd Props doc
Tips: Java-Properties also works
- 多文件支持 "/webit-script-config1.props,/webit-script-config2.props"
- 可選額外參數: extraSettingsMap 類型為Map, 支持props 宏
- 默認配置: webit-script-default.props
Grammar(語法)
Hello word
Hello Webit Script!
<%
var books;
{
for(book : books){
%>
${for.iter.index}.《${book.name}》 ¥${book.price}
<%
}
}
{
//this is a function
var func = function(a, b){
return a + b + arguments[3];
};
echo func("a", "b", "c");
echo '\n';
}
{
var map = {
1: 1,
"key2": "value2",
3: 2 + 1
};
map[5] = 2 + 3;
for(key, value : map){
echo key + ":" +value + "\n";
}
}
%>
更多實例可見:測試模板
結構
- 腳本必須都放在
<% %>
內.<% .code inside.. %> plain text outside
- 替換占位符
${}
只能允許帶返回值的單個表達式,只能在腳本塊<% %>
以外使用.${ .. expression .. }
- 轉義字符
\\
to\
,\<%
to<%
,\${
to${
- Node: 只有緊挨
<%
${
的\
才需要轉義 , - 轉義竅門: 偶數個
\
會 打印 一半數量的\
并進入代碼段, 奇數 會 打印 (count-1)/2 個\
然后打印被轉移的符號。
注釋
- 單行注釋
//
- 塊注釋
/* */
關鍵字
var super this
if else
switch case default
for do while break continue
function return
import include echo
native new @import
保留的關鍵字
static instanceof class const final
throw try catch finally
操作符
與Java 保持一致,順序按優先級從高到低
[] . () @
=>
! ~ ++ -- – (取負)
* / %
+ -
<< >> >>>
< <= > >=
^
|
&&
||
?:
..
= += -= *= /= %= ^= <<= >>= >>>=
語句
- 結尾分號不能省略
作用域(代碼段) { }
- 作用域引用上層變量
- 本層作用域變量不會影響上層
- 同一作用域不能重復聲明變量
- 模板傳入的變量僅在該作用域查找同名變量并賦值 1. 調用模板傳入的變量; 2.import 返回的變量
變量
變量聲明 var
var a;
var a, b, c=0, d="d";
變量名規則
- 先聲明 后使用,所有變量 必須全部聲明
- 可開啟 弱聲明模式,所有變量不需要 事先聲明,解析時自動聲明
- 對大小寫敏感
- 不能使用關鍵字
- 僅能包含 0-9a-zA-Z_$
- 特殊變量名: ++
super.
用于 取得指定上層且僅該層作用域的變量, 可嵌套super.super.a
++this.
用于 取得本層且僅本層作用域的變量, 可嵌套this.super.a
++for.iter
用于 最近一層for循環的 迭代狀態對象, 可使用super
this
限定作用域super.for.iter
數據結構
擁有動態類
var x // null
var x2 = 6; // 數字
var x3 = "Bill"; // 字符串
var x4 = 'a'; // 字符
var x5 = [1, "string"]; // 數組
var x6 = {}; // Map
字符串
- 轉義,
\\
\"
\'
\n
\r
\t
\f
\b
- 允許換行,行后轉義字符 可屏蔽該換行符
var string = "第一行 \
這還是在第一行
這是第二行\n第三行\n
這是第五行,第四行是空行";
數字
var x1=34; //Integer
var x2=34L; //Long
var x3=34.00; //Double
var x4=34.00D; //Double
var x5=34.00F; //Float
var x6 = 0b10101; //二進制
var x7 = 0123; //八進制
var x8 = 0x1A; //十六進制
布爾
var x = true;
var y = false;
數組
帶初始值的數組
var array = [1, "a string", book];
var item;
item = array[0];
item = array[1];
item = array[2];
array[0] = "a new value";
Native 方法聲明定長數組,
// 引入生成數組的 native 方法
var new_int_array = native int [];
var new_Object_array = native Object [];
var new_DateTime_array = native java.util.DateTime [];
//得到定長數組
var int_array = new_int_array(5); //長度為5 的int數組
var objects = new_Object_array(5);//長度為5 的Object數組
var a;
a = objects[4];
objects[4]=4; // 自動 裝箱為Integer 然后放入數組
var len = objects.length; //數組長度
len = objects.size; //數組長度
//不定長數組 可使用Java提供的List實現
var new_list = native new java.util.ArrayList();
var list_add = native java.util.List.add(Object);
var list = new_list();
list@list_add(0);
list@list_add(1);
var a = list[0];
list[0] = "zero";
list[1] = "a string";
Map
var map = {};
var map2 = {1:1,"2","2"};
map["key"] = "a string value";
var value = map[1];
value = map["2"];
value = map["key"];
Java對象
聲明
var new_list = native new java.util.ArrayList();
var list = new_list();
var list2 = new_list();
訪問屬性
var book;
var name = book.name; // book.getName();
book.name = "new name"; //book.setName("new name");
訪問方法
訪問方法必須事先native導入成本地函數
var list_add = native java.util.List.add(Object);
list@list_add(0);
list_add(list, 1);
訪問靜態方法
var now = native java.lang.System.currentTimeMillis();
echo now();
函數
聲明
- 格式同java
- 可變參數,
- 可通過 arguments 獲得所有傳入的參數, java類型為 Object[]
- 可訪問父層作用域
- 函數內部可嵌套函數
var outSideVar;
var a;
var myFunc = function(arg1, arg2){
var arg3 = arguments[3]; // 如果沒有將拋出異常,最好通過 arguments.size確認
outSideVar = "a new "; //可訪問
var a = 0; //內部變量
super.a ++ ; //訪問上層變量
var func = function(){ ... }; //內部嵌套函數
}; //不要忘了分號!!!
導入Java內的 方法
- 僅可導入公共類的公共方法, 包括靜態方法 和 成員方法
- 可使用
@import
導入類名 或者包名 用法同Java里的import
, 以簡化類名輸入 @import java.util.*;v1.2.0+ 不再支持導入包
@import java.lang.System; //實際上默認已經導入 java.lang.* 只是演示使用方法
@import java.util.List;
@import java.util.ArrayList;
var now = native java.lang.System.currentTimeMillis();
var list_add = native List.add(Object);
var new_list = native new ArrayList(); // 導入 構造函數
var new_list2 = native new ArrayList(int); // 導入 構造函數
調用
- 可變參數個數, 多余函數同樣會被傳入, 多余函數是否被使用 取決于函數本身
- 缺少的參數 自動 null 填充, 為了良好的設計 不建議使用缺少函數自動填充
- 可使用@ 將第一個參數 外置
func(arg1, arg2);
//等同于
arg1@func(arg2);
list_add(list, item);
//等同于
list@list_add(item);
重定向輸出符 =>
- 作用: 將指定 范圍 產生的輸出流 重定向到 指定變量
- 意義: 可以延后輸出
- 使用對象: 1. 代碼段; 2. 函數調用
- 數據格式: 使用OutputStream 時, 為 byte[] ; 使用 Writer 時, 為String.
var out;
var book;
//代碼段 輸出重定向
{
echo "a String";
>${book.name} <
} => out; //不要忘了分號!!!
// "a String" 以及 book.name 都將輸出到 out
var out;
// 函數 輸出重定向
func() => out;
//由于 `=>` 具有較高的優先級,也可以這么些
var a = arg1@func() => out +1;
//此時 a為 func()+1 , func() 本次執行的輸出內容賦值給out
import & include
- 區別: import 將把調用模板的 上層變量 推入調用層的當前已存在變量
- 共同點: 都會在調用位置產生 輸出
- 將使用默認的Loader 加載模板,可使用相對路徑或絕對路徑
- 可跟隨 一個 map 格式的傳參
- 模板名可以動態生成
- import 可支持指定需要導出的變量, 否則只導出本層作用域內的同名變量
//相對路徑
include "./book-head.wtl";
//等同于
include "book-head.wtl";
//絕對路徑
include "/copyright.wtl";
//動態模板名
var style = "";
import "book-list-"+ style +".wtl";
//可傳入參數 函數同樣也可以作為變量傳輸
var func = function(){};
var book;
import "book-head.wtl" {"book": book, "func":func};
//傳入Map 變量作為參數
var map = {"book": book, "func":func};
map["one"] = 1;
import "book-head.wtl" {map};
//導出指定變量
var a;
var b;
//導出 : a 到a ,c 到 b
import "book-head.wtl" {"param1":1} a,b=c;
關于條件判斷的三種情況
- 如果是boolean(Boolean)值 會原封返回
- 如果 ==null 返回 false
- **如果 是空集合 或者 空數組 (.size==0) 返回 false **
- 否則 返回 true
三元條件運算符 & 其簡寫
- 操作符按 自右向左 結合 [不是執行順序], 詳解看下面例子
- 簡寫時
?:
之間不能有空白
var a1 = isTrue ? "Yes" : "No";
//簡寫
var a2 = value ?: defaultValue; //取默認值
//自右向左 結合
var x = expr1 ? expr3 : expr2 ? expr4 : expr5;
//這個等同于
var x = expr1 ? expr3 : (expr2 ? expr4 : expr5);
// 如果 是 自左向右 就會變成這樣
var x = (expr1 ? expr3 : expr2) ? expr4 : expr5;
//簡寫 就按 從左向右 “執行”
var a4 = list1 ?: list2 ?: list3;
判斷語句
判斷表達式 ?:
判斷控制語句 if - else if - else
- 不能省略
{ }
if( ... ){
...;
}else if(...){
...;
}else{
...;
}
循環控制語句
- 支持 數組, java.util.Collection, java.util.Iterator, java.util.Enumeration, CharSequence, java.util.Map, 整型遞增/遞減
- 當集合為null 或者為空時將不會執行循環
- 支持 else , 可選, 當不符合執行循環體的條件時執行else體.
for-in
//集合 數組 等
for(item : list){
echo item;
//echo for.iter.index; // .isFirst .hasNext .isOdd .isEven
} else{
echo "list is empty";
}
//遞增
for(i: 3..6){
echo i;
}
//遞減
for(i: 6..3){
echo i;
//支持 for.iter.*
}
for-in Map version
for(key, value : map){
echo key + " = " value;
echo "\n";
//同樣支持 for.iter.*
}
while do-while
- 不支持 for.iter 特殊變量
//
var iter;
... ;
while(iter.hasNext){
var item = iter.next;
....;
}
//
do{
....;
}while( ... );
Switch-Case
- 支持普通 Object, 包括 String
- 使用 Object.equls() 判斷是否相等
- 需要 break, 否則無條件繼續執行下一個標簽的句柄
- 每個case 命名空間獨立
switch(a){
case 1:
....;
break;
case "c": //String
....;
break;
case 'c': //Char
....;
break;
default:
....;
}
break continue
- 支持 label, 直接操作該循環體 或 switch
//break continue
outter: for(i: 6..3){
echo i;
//支持 for.iter.*
inner: for(item : list){
if( ..... ){
break outter;
}
.....;
break; // break inner;
}
//
switch(a){
...;
case 'x':
break outter;
...;
}
}
正在完善。。。
其他
Performance(性能)
- 缺省開啟ASM構建Native 調用減少反射, 不同于將整個模板編譯成Java字節碼,該方法不會造成無限制的perm溢出;
- 解析之后的Template AST會放入緩存, 檢測到模板源文件改變時將重新加載資源并解析;
- 性能測試結果比較理想, 待比較權威的模版測試程序;
- 使用OutputStream 輸出時, 選擇 SimpleTextStatmentFactory 將會預先將純文本根據缺省編碼編碼成字節流.
- boilit/ebm 測試結果 by:boilit/ebm or see
Engine Time Size
BSL-2.0.0 559 68118050
webit-script-1.1.4 590 68318250
HTTL-1.0.11 958 68118050
BeeTL-1.25.01 958 68138070
Rythm-1.0.0-b10-SNAPSHOT 1624 48728680
Velocity-1.7 1834 75046912
FreeMarker-2.3.19 2369 68157440
JdkStringBuffer-1.7.0_40 606 67395584
JdkStringBuilder-1.7.0_40 735 67395584
SPI
- TextStatmentFactory 對模板純文本的存貯以及輸出形式進行管理
- Filter 輸出過濾
- CoderFactory 編碼/解碼
- Loader 模板資源加載(原ResourceLoader)
- Logger 日志
- GetResolver, SetResolver, OutResolver Bean屬性解釋器
- NativeSecurityManager Native調用安全管理器
項目主頁:http://www.baiduhome.net/lib/view/home/1385607413718
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!