DataQL
簡介
DataQL(Data Query Language)DataQL 是一種查詢語言。旨在通過提供直觀、靈活的語法來描述客戶端應(yīng)用程序的數(shù)據(jù)需求和交互。
數(shù)據(jù)的存儲(chǔ)根據(jù)其業(yè)務(wù)形式通常是較為簡單的,并不適合直接在頁面上進(jìn)行展示。因此開發(fā)頁面的前端工程師需要為此做大量的工作,這就是 DataQL 極力解決的問題。
請(qǐng)注意 DataQL 不是一門編程語言,它是查詢語言。它對(duì)邏輯的處理僅限于簡單場景。DataQL 的解決問題的重點(diǎn)集中在:數(shù)據(jù)的聚合和轉(zhuǎn)換以及過程中的簡單加工處理。
特性
語法手冊(cè)
詞法記號(hào)
-
注釋支持://、/*…*/
-
支持任意空格,提高可讀性,支持\t,\n,\r,\f
-
關(guān)鍵字:
關(guān)鍵字含義 if 條件語句的引導(dǎo)詞 else 用在條件語句中,表明當(dāng)條件不成立時(shí)的分支 return 三大退出指令之一,終止當(dāng)前過程的執(zhí)行并正常退出到上一個(gè)執(zhí)行過程中 throw 三大退出指令之一,終止所有后續(xù)指令的執(zhí)行并拋出異常 exit 三大退出指令之一,終止所有后續(xù)指令的執(zhí)行并正常退出 var 執(zhí)行一個(gè)查詢動(dòng)作,并把查詢結(jié)果保存到臨時(shí)變量中 run 僅僅執(zhí)行查詢動(dòng)作,不保留查詢的結(jié)果 hint 寫在 DataQL 查詢語句的最前面,用于設(shè)置一些執(zhí)行選項(xiàng)參數(shù) import 將另外一個(gè) DataQL 查詢導(dǎo)入并作為一個(gè) Udf 形式存在、或直接導(dǎo)入一個(gè) Udf 到當(dāng)前查詢中 as 與 import 關(guān)鍵字配合使用,用作將導(dǎo)入的 Udf 命名為一個(gè)本地變量名 true 基礎(chǔ)類型之一,表示 Boolean 的:真值 false 基礎(chǔ)類型之一,表示 Boolean 的:假值 null 基礎(chǔ)類型之一,表示 NULL 值 -
標(biāo)識(shí)符:表示查詢中的一些實(shí)體,如變量名參數(shù)名。必須滿足正則表達(dá)式:[_a-zA-Z][_0-9a-zA-Z]*,一些對(duì)象的key可能會(huì)超出范圍,可以用反引號(hào)`xxx`。
-
分隔符:()、{}、[]、,、:、;(非必須)
-
運(yùn)算符:
- 數(shù)學(xué)運(yùn)算:+,-,*,/,\(整除),%
- 位運(yùn)算:&,|,!,^(異或),<<(左位移),>>(有符號(hào)右位移),>>>(無符號(hào)右位移)
- 比較運(yùn)算:>,>=,<,<=,==,!=
類型系統(tǒng)
DataQL 是弱類型定義的查詢語言,在DataQL 中所有數(shù)據(jù)都會(huì)被歸結(jié)到有限的幾種類型上。無需定義數(shù)據(jù)類型結(jié)構(gòu),在弱類型系統(tǒng)中編寫查詢會(huì)非常方便,它去掉了繁雜的類型定義。
| 布爾 | true 或 false | 表示真假值 |
| 數(shù)值 | 負(fù)無窮大 或 0 或 正無窮大 | 浮點(diǎn)數(shù)、整數(shù)、科學(xué)計(jì)數(shù)法表示的數(shù) |
| 字符串 | ‘…’ 或 “…” | 字符串 或 單個(gè)字符 |
| 空值 | null 或 NULL | 空值 |
| 集合 | […] 數(shù)組 或 多維數(shù)組 | 帶有順序的多組數(shù)據(jù)的集合 |
| 對(duì)象 | {‘key’:…} 具有鍵值對(duì)的數(shù)據(jù)體 | DataQL 的對(duì)象不支持方法,但是可以具備 Udf 類型的屬性。 |
| UDF | lambda 函數(shù) 或 一個(gè)外部的 Udf | 一個(gè)外部的 net.hasor.dataql.Udf 接口函數(shù)定義。 |
| DataQL 中書寫的 lambda 函數(shù)也被稱作為 UDF。 | ||
| 一個(gè)擴(kuò)展代碼片段的定義,也屬于 UDF 的范疇。 |
-
數(shù)值類型
- 二進(jìn)制表示法:0b01010101100 或 0B01010101100
- 十進(jìn)制表示法:0o1234567 或 0O1234567
- 八進(jìn)制表示法:-0000234 或 123
- 十六進(jìn)制表示法:0x12345 或 0X12345
- 科學(xué)計(jì)數(shù)法:a * 10的n 次冪的形式,其中 1 < a < 10
- 關(guān)于負(fù)數(shù):目前只有十進(jìn)制表示法中提供了負(fù)數(shù)的表示能力。
-
UDF
- 外部Udf:外部的 Udf 被引入之后,通常以標(biāo)識(shí)符形式表示它。
- DataQL 中書寫的 lambda 表達(dá)方式為:var foo = () -> { /* 代碼塊 */ }
- 外部代碼片段:var a = @@xxx() <% /* 外部代碼塊 */ %>
-
JSON
- DataQL 可以直接表達(dá) Json 數(shù)據(jù)(Json 的 Key 必須通過雙引號(hào)或單引號(hào)形式包裹起來)
-
當(dāng)兩類型不匹配時(shí)能自動(dòng)類型提升。
數(shù)值
-
支持:byte、short、int、long、float、double、BigInt、Decimal
-
數(shù)值寬度默認(rèn)是int和double
-
浮點(diǎn)數(shù)計(jì)算時(shí)默認(rèn)保留20位小數(shù),多余的四舍五入。修改精度使用hint MAX_DECIMAL_DIGITS=20,更換舍入規(guī)則hint NUMBER_ROUNDING = 'HALF_EBEN'。
語句
-
import
- import “<函數(shù)類或函數(shù)包類>” as <別名>
- import @"<資源地址>" as <別名>
- 別名必須滿足 標(biāo)識(shí)符
- 必須放在整個(gè)查詢最開始的地方,被導(dǎo)入的資源會(huì)以var的方式定義。
-
var
- var <變量名> = <表達(dá)式 or 值對(duì)象 or 函數(shù)定義>
- 定義變量、執(zhí)行并存儲(chǔ)表達(dá)式的值
-
run
- run <表達(dá)式 or 值對(duì)象 or 函數(shù)定義>
-
return、throw、exit
- return <狀態(tài)碼>, <表達(dá)式 or 值對(duì)象 or 函數(shù)定義>
- 還可以不指定狀態(tài)碼
- return <表達(dá)式 or 值對(duì)象 or 函數(shù)定義>
- 三者除了行為不同,用法完全一樣。
-
if
-
令DataQL變得靈活的存在
- if` `(boolean_expression) {``/* 如果布爾表達(dá)式為真將執(zhí)行的語句 */ } ``else` `{``/* 如果布爾表達(dá)式為假將執(zhí)行的語句 */ }
-
-
hint
- hint <選項(xiàng)名稱> = <選項(xiàng)值>
- 作用是設(shè)置一些執(zhí)行查詢使用的選項(xiàng)參數(shù)。可以參考這里
表達(dá)式
- 一元運(yùn)算:!(對(duì)Boolean取反),-(對(duì)數(shù)值取相反數(shù))
- 二元運(yùn)算:主要是面向number,但是也支持字符串拼接。
- 三元運(yùn)算:testExpr ? expr1 : expr2
訪問符
-
取值域:
- $:值域符A
- #:值域符B
- @:值域符C
- 應(yīng)用場景:1. 獲取程序傳來的參數(shù)。2. 表達(dá)式中的訪問符。
-
獲取程序傳來的參數(shù):<訪問符>{<參數(shù)名>} ,如${abc}
-
表達(dá)式中的訪問符:$(環(huán)境棧根),#(環(huán)境棧頂),@(整個(gè)環(huán)境棧(數(shù)組形態(tài)))
-
DataQL 查詢過程中一般情況下環(huán)境棧始終是空的,當(dāng)遇到 => 操作時(shí)。
DataQL 會(huì)把 => 符左邊的表達(dá)式值放入環(huán)境棧,當(dāng)轉(zhuǎn)換結(jié)束時(shí) DataQL 會(huì)把表達(dá)式值從環(huán)境棧中刪掉。
如果在轉(zhuǎn)換過程中遇到第二次 => 操作,那么會(huì)在環(huán)境棧頂中放入新的數(shù)據(jù)。
-
取值與賦值
-
對(duì)象取值:return userInfo.username;
-
函數(shù)結(jié)果取值:return userByID({'id': 4}).username;
-
數(shù)組中取值:return userList()[0].username;
-
下標(biāo)取值:return userInfo['username'];
-
連續(xù)下標(biāo)取值:return userList[0]['username'];
-
數(shù)組下標(biāo)取值:
- 正向索引:list[3] = 3,
- 反向索引:list[-3] = 7,
- 索引溢出:三種處理方式:throw,null,near(默認(rèn))
-
下標(biāo)變量:使用變量代替下標(biāo)
// 定義一個(gè)變量,變量表示要取值的字段名。 var columnKey = 'username'; // 通過下標(biāo)變量方式來取值 return userInfo[columnKey]; -
賦值
- 在DataQL中數(shù)據(jù)是不可被修改的,只能重新生成數(shù)據(jù)集或者在結(jié)果轉(zhuǎn)換中對(duì)局部數(shù)據(jù)進(jìn)行修改。
- 重定義: 在任何時(shí)候都可以通過var來重新定義一個(gè)已經(jīng)存在的變量。
結(jié)果轉(zhuǎn)換
-
結(jié)果轉(zhuǎn)換是DataQL的核心能力,可以大體歸納為:組裝(憑空構(gòu)造)和變換。
-
組裝:
-
case1:
var userName = "馬三"; // 姓名 var userAge = 23; // 年齡// 返回一個(gè)對(duì)象數(shù)據(jù),將用戶名稱和年齡組裝到一個(gè)對(duì)象中 return {"name" : userName,"age" : userAge }; -
case2:
var data1 = 123; // 值1 var data2 = 456; // 值2// 返回2個(gè)元素的數(shù)組 return [data1, data2 ]; -
case3:
var data = [123, 456];//它組裝了兩個(gè)字段。但是兩個(gè)字段分別來自于同一個(gè)數(shù)組數(shù)據(jù)的不同元素 return {"element_0" : data[0], // 123"element_1" : data[1] // 456 };
-
-
數(shù)組的變換(是一個(gè)一個(gè)元素依次按照規(guī)則進(jìn)行轉(zhuǎn)換的)
//首先我們有一個(gè)對(duì)象數(shù)組 var data = [{"userID" : 1234567891,"age" : 31,"name" : "this is name1.","nick" : "my name is nick1.","sex" : "F","status" : true },{"userID" : 1234567892,"age" : 32,"name" : "this is name2.","nick" : "my name is nick2.","sex" : "F","status" : true },{"userID" : 1234567893,"age" : 33,"name" : "this is name3.","nick" : "my name is nick3.","sex" : "M","status" : true } ]-
case1:
//得到一個(gè)新的數(shù)據(jù)集,只包含name和age字段 return data => [{"name", "age"} ]; -
case2:
//只包含name和age字段,同時(shí)修改一下字段名 return data => [{"userName" : name, // 取 name 字段的值作為 userName 的值"userAge" : age} ]; -
case3:
//返回所有用戶名的列表,得到字符串?dāng)?shù)組 return data => [ name ]; -
case4:
//將 一組值類型 變換成 一組對(duì)象 var data = ["馬三", "馬四"]; return data => [{"name" : # // 符號(hào) "#" 表示在對(duì)每個(gè)元素進(jìn)行轉(zhuǎn)換的過程中的那個(gè)元素本身。} ]; //得到的就是 [ {"name":"馬三"}, {"name":"馬四"} ] -
case5:
//為二維數(shù)組的每個(gè)值都加上一個(gè)字符串前綴 var data = [[1,2,3],[4,5,6],[7,8,9] ] return data => [# => [ // 在結(jié)果轉(zhuǎn)換中對(duì)當(dāng)前元素進(jìn)行二次轉(zhuǎn)換"值:" + #] ] //查詢結(jié)果: [["值:1","值:2","值:3"],["值:4","值:5","值:6"],["值:7","值:8","值:9"] ]
-
-
對(duì)象的變換
//首先我們有一個(gè)對(duì)象 var data = {"userID" : 1234567890,"age" : 31,"name" : "this is name.","nick" : "my name is nick.","sex" : "F","status" : true }-
case1:
//通過變換而非組裝的方式將其轉(zhuǎn)換為一個(gè)數(shù)組,內(nèi)容是一個(gè)對(duì)象 return data => [ # ]; //---------結(jié)果--------- [{"userID": 1234567890,"age": 31,"name": "this is name.","nick": "my name is nick.","sex": "F","status": true} ] -
case2:
//對(duì)象的變換通常都是結(jié)構(gòu)上的變化。對(duì)象可以是數(shù)組形式的一個(gè)元素,數(shù)組中可以疊加對(duì)象的變換 return data => {"name","info" : {"age","sex"} } //查詢結(jié)果 {"name": "this is name.","info": {"age": 31,"sex": "F"} }
-
-
使用表達(dá)式
-
case1:
//對(duì)結(jié)果變換過程中通過表達(dá)式來對(duì)字段重新計(jì)算 return data => {"name","age" : age + "歲","old" : age, // 這是有效的,age能夠使用多次"old" : name, // 這是無效的,"old"只會(huì)顯示上面那個(gè)"sex" : (sex == 'F') ? '男' : '女' }
-
-
通過Lambda模擬for循環(huán)
import 'net.hasor.dataql.fx.basic.CollectionUdfSource' as collect;var map = {"a" : 123,"b" : 321 } var data = [{"name" : "馬三","type" : "a"},{"name" : "n2","type" : "b"} ]var appendData = (dat) -> {//這個(gè)dat是data中的一個(gè)對(duì)象。lambda表達(dá)式只用處理一個(gè)元素即可,具體的整個(gè)數(shù)組的調(diào)用邏輯在return的時(shí)候。var newMap = collect.newMap(dat);run newMap.put('type',map[dat.type])//給這個(gè)newMap中設(shè)置'type'屬性,值是這樣取出來的(從map取出(key是(dat.type的value)的鍵值對(duì))的值)。return newMap.data() };return data => [appendData(#) ] // 變量appendData定義為一個(gè)函數(shù),這個(gè)函數(shù)有一個(gè)參數(shù)。 // 對(duì)data進(jìn)行變換時(shí),變換規(guī)則是之前定義的函數(shù)appendData, // 在這個(gè)函數(shù)中參數(shù)為當(dāng)前data數(shù)組中的一個(gè)對(duì)象元素, // 所以在函數(shù)中是對(duì)一個(gè)對(duì)象進(jìn)行操作,不用考慮數(shù)組的問題。 // 數(shù)組是在return的時(shí)候?qū)erson進(jìn)行變換,對(duì)每個(gè)元素#調(diào)用定義的lambda函數(shù)appendData實(shí)現(xiàn)的。//執(zhí)行結(jié)果 [{"name": "馬三","type": 123},{"name": "n2","type": 321} ] -
Tips:
- 變換要出現(xiàn)數(shù)組,則以[]包裹,對(duì)象則{}包裹,只有[]沒有{}的是字符串?dāng)?shù)組。在變換中能自由改名并使用表達(dá)式組合結(jié)果,并且可以一個(gè)元素多次使用,但是同名屬性只以第一次出現(xiàn)為準(zhǔn)。
- 對(duì)數(shù)組的循環(huán)操作可以通過,在return中對(duì)數(shù)組取#實(shí)現(xiàn)對(duì)每個(gè)元素的更改。
函數(shù)
-
定義函數(shù):可以直接用DataQL語言定義一個(gè)函數(shù),然后在后續(xù)查詢中使用它。
var convertSex = (sex) -> {//定義一個(gè)函數(shù)return (sex == 'F') ? '男' : '女' };var data = {"userID" : 1234567890,"age" : 31,"name" : "this is name.","nick" : "my name is nick.","sex" : "F","status" : true };return data => {"name","age" : age + "歲","sex" : convertSex(sex)//使用函數(shù)得到值 } -
外部函數(shù):DataQL具有官方標(biāo)準(zhǔn)函數(shù)庫,可以通過import語句導(dǎo)入。
//通過時(shí)間函數(shù)庫獲取時(shí)間 import 'net.hasor.dataql.fx.basic.DateTimeUdfSource' as time;return time.now();//通過json函數(shù)庫來生成JSON數(shù)據(jù) import 'net.hasor.dataql.fx.basic.JsonUdfSource' as json;return json.toJson([0,1,2])// "[0,1,2]"- 開發(fā)者還可以自己編寫函數(shù)(編寫UDF)
-
Lambda寫法
import 'net.hasor.dataql.fx.basic.CollectionUdfSource' as collect; // 數(shù)據(jù) var dataList = [{"name" : "馬一" , "age" : 18 },{"name" : "馬二" , "age" : 28 },{"name" : "馬三" , "age" : 30 },{"name" : "馬四" , "age" : 25 } ]//只保留年齡大于20歲的數(shù)據(jù)// 使用非Lambda的寫法---------------- // 年齡過濾邏輯 var filterAge = (dat) -> {return return dat.age > 20; }; // 調(diào)用 filter 函數(shù) return collect.filter(dataList, filterAge);//使用Lambda的寫法----------------------省略了一個(gè)函數(shù)定義 var result = collect.filter(dataList, (dat) -> { // lambda 寫法return dat.age > 20;// 年齡過濾條件 });
混合其他語言
? 在DataQL中混合其他語言一起協(xié)同處理DataQL查詢,需要定義一個(gè)片段執(zhí)行器。
-
典型的場景是把SQL語句混合在DataQL中。
var dataSet = @@sql(item_code) <%select * from category where co_code = #{item_code} %>return dataSet() => [{ "id","name","code","body" } ] // @@sql 是 FunctionX 擴(kuò)展包中提供的一組片段執(zhí)行器,這個(gè)片段執(zhí)行器相當(dāng)于讓 DataQL 有能力執(zhí)行數(shù)據(jù)庫的 SQL 語句。 -
定義:定義一個(gè)片段執(zhí)行器需要,實(shí)現(xiàn) net.hasor.dataql.FragmentProcess 接口(更多信息請(qǐng)參考開發(fā)手冊(cè))并且將其注冊(cè)到 DataQL 環(huán)境中
// 方式一:通過Dataql接口 FragmentProcess process = ... AppContext = appContext = ...DataQL dataQL = appContext.getInstance(DataQL.class);//獲取 DataQL 接口 dataQL.addFragmentProcess("sql", process); //注冊(cè)片段執(zhí)行器// 方式二:通過QueryModule FragmentProcess process = ...public class MyQueryModule implements QueryModule {public void loadModule(QueryApiBinder apiBinder) {dataQL.addFragmentProcess("sql", process); //注冊(cè)片段執(zhí)行器} } -
使用:
定義一個(gè)片段執(zhí)行器需要使用 @@xxxx(arg1,arg2,arg3,…)<% … %> 語法,其中:
- xxxx 為片段執(zhí)行器注冊(cè)的名稱。
- (arg1,arg2,arg3,…) 為執(zhí)行這個(gè)代碼時(shí)傳入的參數(shù)列表。如果不需要定義任何參數(shù)可以是 ()
- 在 <% 和 %> 之間編寫的是 目標(biāo)語言的代碼片段。
數(shù)據(jù)模型
DataQL的數(shù)據(jù)模型是通過net.hasor.dataql.domain.DataModel接口表示的,共計(jì)4個(gè)實(shí)現(xiàn)類:ValueModel,ListModel,ObjectModel,UdfModel。
還有一個(gè)非常重要的unwrap方法,能解除DataModel形態(tài)的封裝,直接變成Map/List結(jié)構(gòu),注意UdfModel類型解開是Udf接口。
- ValueModel:用于表示String、Number、Boolean、Null四種基本數(shù)據(jù)類型。有isXxx()方法用于判斷類型,asXxx()方法用于獲取對(duì)應(yīng)值。
- ListModel:表示一個(gè)列表或集合的數(shù)據(jù),相比較 DataModel 多了一組根據(jù)元素位置判斷對(duì)應(yīng)類型的接口方法。
- ObjectModel:表示一個(gè)列表或集合的數(shù)據(jù),相比較 DataModel 多了一組根據(jù)元素 Key 判斷對(duì)應(yīng)類型的接口方法。
- UdfModel:當(dāng) DataQL 查詢返回一個(gè) Udf 函數(shù)或者 Lambda 函數(shù)時(shí),就會(huì)得到一個(gè) UdfModel。而它事實(shí)上就是一個(gè) Udf
開發(fā)手冊(cè)
執(zhí)行查詢
? 引入依賴
<dependency><groupId>net.hasor</groupId><artifactId>hasor-dataql</artifactId><version>4.2.1</version> </dependency>通過Hasor使用DataQL
//由于 AppContext 有自身的聲明周期特性,因此需要做一個(gè)單例模式來創(chuàng)建 DataQL 接口。 public class DataQueryContext {private static AppContext appContext = null;private static DataQL dataQL = null;public static DataQL getDataQL() {if (appContext == null) {appContext = Hasor.create().build();dataQL = appContext.getInstance(DataQL.class);}return dataQL;} }//然后在Test中執(zhí)行查詢 HashMap<String, Object> tempData = new HashMap<String, Object>() {{put("uid", "uid is 123");put("sid", "sid is 456"); }};DataQL dataQL = DataQueryContext.getDataQL(); Query dataQuery = dataQL.createQuery("return [${uid},${sid}]"); QueryResult queryResult = dataQuery.execute(tempData); DataModel dataModel = queryResult.getData(); List list = (List)dataModel.unwrap();for (Object o : list) {System.out.println(o);}通過JSR223使用DataQL:我這里略
基于底層接口使用DataQL
DataQL 的運(yùn)行基于三個(gè)步驟:
- 1.解析DataQL查詢:把 DataQL 查詢字符串通過解析器解碼為 AST(抽象語法樹)QueryModel queryModel = QueryHelper.queryParser(query1);
- 2.編譯查詢:將DataQL 的 AST(抽象語法樹) 編譯為 QIL 指令序列。QIL qil = QueryHelper.queryCompiler(queryModel, ``null``, Finder.DEFAULT);
- 3.執(zhí)行查詢:最后在根據(jù) QIL 創(chuàng)建對(duì)應(yīng)的 Query 接口即可。Query dataQuery = QueryHelper.createQuery(qil, Finder.DEFAULT);
查詢接口(Query)
無論使用何種方式查詢都會(huì)通過DataQL的查詢接口發(fā)出查詢指令。
查詢接口提供了三種不同參數(shù)類型的查詢重載,所有入?yún)?shù)最后都被轉(zhuǎn)換成為 Map 結(jié)構(gòu)然后統(tǒng)一變換成為 CustomizeScope 數(shù)據(jù)域形式。
查詢結(jié)果(QueryResult)
發(fā)出DataQL查詢后,如果順利執(zhí)行完查詢,結(jié)果會(huì)以QueryResult接口形式返回。
/** 執(zhí)行結(jié)果是否通過 EXIT 形式返回的 */ public boolean isExit();/** 獲得退出碼。如果未指定退出碼,則默認(rèn)值為 0 */ public int getCode();/** 獲得返回值 */ public DataModel getData();/** 獲得本次執(zhí)行耗時(shí) */ public long executionTime();DataQL 的所有返回值都會(huì)包裝成 DataModel 接口類型。如果想拿到 Map/List 結(jié)構(gòu)數(shù)據(jù),只需要調(diào)用 unwrap 方法即可。
全局變量
添加全局變量有兩種方式:
在QueryModule中初始化環(huán)節(jié)添加
AppContext appContext = Hasor.create().build((QueryModule) apiBinder -> {apiBinder.addShareVarInstance("global_var", "g1"); });通過DataQL接口添加
DataQL dataQL = appContext.getInstance(DataQL.class); dataQL.addShareVarInstance("global_var", "g2");獲取全局變量
return global_var;函數(shù)
-
開發(fā)Udf
一個(gè)Udf必須是實(shí)現(xiàn)了net.hasor.dataql.Udf接口,注冊(cè)Udf的方式和添加全局變量相同。
public class UserByIdUdf implements Udf {private UserManager userManager;public Object call(Hints readOnly, Object[] params) {return userManager.findById(params[0]);} } -
參數(shù)中的Udf
DataQL 允許在執(zhí)行查詢時(shí)通過參數(shù)形式提供 Udf ,這種方式傳入的 Udf 在調(diào)用時(shí)也需要使用 ${…} 來獲取
HashMap<String, Object> tempData = new HashMap<String, Object>() {{put("findUserById", new UserByIdUdf()); }};AppContext appContext = Hasor.create().build(); DataQL dataQL = appContext.getInstance(DataQL.class);//得到 DataQL接口 Query dataQuery = dataQL.createQuery("return ${findUserById}(1) => { 'name','sex' }"); // 創(chuàng)建查詢 QueryResult queryResult = dataQuery.execute(tempData); DataModel dataModel = queryResult.getData(); -
函數(shù)包(UdfSource)
UdfSource 是一個(gè)函數(shù)包接口,接口中只有一個(gè) getUdfResource 方法,用于返回函數(shù)包中的所有 Udf(Map形式返回)但是一般情況下更推薦使用 UdfSourceAssembly 接口。
使用函數(shù)包的好處是可以像平常開發(fā)一樣編寫 Udf,無需考慮 Udf 接口的細(xì)節(jié)。裝配器會(huì)自動(dòng)幫助進(jìn)行參數(shù)和結(jié)果的轉(zhuǎn)換。
public class DateTimeUdfSource implements UdfSourceAssembly {/** 返回當(dāng)前時(shí)間戳 long 格式 */public long now() { ... }/** 返回當(dāng)前系統(tǒng)時(shí)區(qū)的:年 */public int year(long time) { ... }/** 返回當(dāng)前系統(tǒng)時(shí)區(qū)的:月 */public int month(long time) { ... }/** 返回當(dāng)前系統(tǒng)時(shí)區(qū)的:日 */public int day(long time) { ... }... } // 最后在查詢中通過 <函數(shù)包名>.<函數(shù)> 的形式調(diào)用函數(shù)包。 -
inport導(dǎo)入(函數(shù)/函數(shù)包)
如果 Classpath 中已經(jīng)存在某個(gè) Udf 類,還可以通過 import 語句導(dǎo)入使用。
import 'net.xxxx.foo.udfs.UserByIdUdf' as findUserById; return findUserById(1) => { 'name','sex' };函數(shù)包的導(dǎo)入語句相同,只是在調(diào)用函數(shù)包中函數(shù)的時(shí)需要指明函數(shù)包
import 'net.xxxx.foo.udfs.DateTimeUdfSource' as timeUtil; return timeUtil.now(); -
使用注解批量注冊(cè)
通過 @DimUdf 注解可以快速的聲明函數(shù)
@DimUdf("findUserById") public class UserByIdUdf implements Udf {private UserManager userManager;public Object call(Hints readOnly, Object[] params) {return userManager.findById(params[0]);} }通過 @DimUdfSource 注解可以快速的聲明函數(shù)包:
@DimUdfSource("time_util") public class DateTimeUdfSource implements UdfSourceAssembly {... }然后在初始化時(shí)掃描加載它們
AppContext appContext = Hasor.create().build(apiBinder -> {QueryApiBinder queryBinder = apiBinder.tryCast(QueryApiBinder.class);queryBinder.loadUdf(queryBinder.findClass(DimUdf.class));queryBinder.loadUdfSource(queryBinder.findClass(DimUdfSource.class)); });
外部代碼片段
-
外部代碼執(zhí)行器
外部代碼片段是 DataQL 特有能力,它允許在 DataQL 查詢中混合其它語言的腳本。并將引入的外部語言腳本轉(zhuǎn)換為 Udf 形式進(jìn)行調(diào)用。使用這一特性時(shí)需要擴(kuò)展 FragmentProcess 接口,并注冊(cè)對(duì)應(yīng)的外部代碼執(zhí)行器。
//外部代碼執(zhí)行器,接收<% %>包裹的代碼,然后調(diào)用jdbcTemplate的query方法執(zhí)行具體的SQL查詢 @DimFragment("sql") public class SqlQueryFragment implements FragmentProcess {@Injectprivate JdbcTemplate jdbcTemplate;public Object runFragment(Hints hint, Map<String, Object> paramMap, String fragmentString) throws Throwable {return this.jdbcTemplate.queryForList(fragmentString, paramMap);} }//在初始化階段注冊(cè)這個(gè)代碼執(zhí)行器,就可以在查詢時(shí)使用了這個(gè)外部代碼片段了 public class MyFragment implements QueryModule {public void loadModule(QueryApiBinder apiBinder) {//掃描所有標(biāo)記了@DimFragment注解的類并加載它apiBinder.loadFragment(queryBinder.findClass(DimFragment.class));} }//DataQL語句,通過@@指令開啟了一段外部代碼的定義,執(zhí)行器的名字是sql var dataSet = @@sql(item_code) <%select * from category where co_code = #{item_code} %>return dataSet() => [{ "id","name","code","body" } ] -
資源加載器(Finder)
資源加載器是net.hasor.dataql.FInder,其主要負(fù)責(zé)import語句導(dǎo)入資源/對(duì)象的加載。通常不會(huì)接觸到它。
import ``'userBean'` `as ub;``//userBean 是 Bean 的名字 return` `ub().name;
SQL執(zhí)行器
SQL 執(zhí)行器是 DataQL 的一個(gè) FragmentProcess 擴(kuò)展,其作用是讓 DataQL 可以執(zhí)行 SQL。執(zhí)行器的實(shí)現(xiàn)是 FunctionX 擴(kuò)展包提供的。使用執(zhí)行器需要引入擴(kuò)展包。
<dependency><groupId>net.hasor</groupId><artifactId>hasor-dataql-fx</artifactId><version>4.2.1</version> </dependency>功能與特性
- 支持兩種模式:簡單模式、分頁模式
- 簡單模式下,使用原生SQL。100% 兼容所有數(shù)據(jù)庫
- 分頁模式下,自動(dòng)改寫分頁SQL。并兼容多種數(shù)據(jù)庫
- 支持參數(shù)化 SQL,更安全
- 支持 SQL 注入,更靈活
- 支持批量 CURD
配置和方言
-
配置數(shù)據(jù)源
//普通方式配置數(shù)據(jù)源,在Hasor中初始化數(shù)據(jù)源即可 public class ExampleModule implements Module {public void loadModule(ApiBinder apiBinder) throws Throwable {// .創(chuàng)建數(shù)據(jù)源DataSource dataSource = null;// .初始化Hasor Jdbc 模塊,并配置數(shù)據(jù)源apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));} } -
方言
配置方言使用 hint HASOR_DATAQL_FX_PAGE_DIALECT = mysql,即可設(shè)置方言。支持Mysql,Oracle,SqlServer2012,PostgreSQL,DB2,Infomix。
執(zhí)行SQL
-
執(zhí)行SQL
// 聲明一個(gè) SQL var dataSet = @@sql() <%select * from category limit 10; %>// 執(zhí)行這個(gè) SQL,并返回結(jié)果 return dataSet(); -
SQL參數(shù)化
// 聲明一個(gè) SQL var dataSet = @@sql(itemCode) <%select * from category where co_code = #{itemCode} limit 10; %>// 執(zhí)行這個(gè) SQL,并返回結(jié)果 return dataSet(${itemCode}); -
SQL注入
//SQL注入是為了一些特殊場景需要拼接SQL而準(zhǔn)備的,如:動(dòng)態(tài)排序字段和排序規(guī)則 // 使用 DataQL 拼接字符串 var orderBy = ${orderField} + " " + ${orderType};// 聲明一個(gè)可以注入的 SQL var dataSet = @@sql(itemCode,orderString) <%select * from category where co_code = #{itemCode} order by ${orderString} limit 10; %>// 執(zhí)行這個(gè) SQL,并返回結(jié)果 return dataSet(${itemCode}, orderBy); -
Ognl表達(dá)式
//同Mybatis一樣,SQL執(zhí)行器可以將一個(gè)對(duì)象作為參數(shù)傳入 // 例子數(shù)據(jù) var testData = {"name" : "馬三","age" : 26,"status" : 0 }// insert語句模版 var insertSQL = @@sql(userInfo) <%insert into user_info (name,age,status,create_time) values (#{userInfo.name},#{userInfo.age},#{userInfo.status},now()) %>// 插入數(shù)據(jù) return insertSQL(testData); -
批量操作
DataQL 的 SQL 執(zhí)行器支持批量 Insert\Update\Delete\Select 操作,最常見的場景是批量插入數(shù)據(jù)。批量操作必須滿足下列幾點(diǎn)要求:
- 入?yún)⒈仨毷?List
- 如果有多個(gè)入?yún)ⅰK袇?shù)都必須是 List 并且長度必須一致。
- @@sql()<% … %> 寫法升級(jí)為批量寫法 @@sql[]()<% … %>
- 如果批量操作的 SQL 中存在 SQL注入,那么批量操作會(huì)自動(dòng)退化為:循環(huán)遍歷模式
- 由于批量操作底層執(zhí)行SQL使用java.sql.Statement.executeBatch方法,因此insertSQL的返回值是int數(shù)組。
-
執(zhí)行結(jié)果拆包
拆包是指將只返回一行一列的數(shù)據(jù)如count(*),拆解為int類型。
有三種模式,默認(rèn)為column:
- off:不拆包,嚴(yán)格返回一個(gè)對(duì)象數(shù)組。
- row:最小粒度到行,多條記錄時(shí)正常返回,返回0或1條記錄時(shí),返回一個(gè)Object。
- column:最小粒度到列,當(dāng)返回結(jié)果只有一行一列時(shí),返回具體值。
-
結(jié)果列名拼寫轉(zhuǎn)換
是指從數(shù)據(jù)庫查詢返回的列名信息,按照某一規(guī)則統(tǒng)一處理,如所有key轉(zhuǎn)為駝峰。可以使返回的列信息具有很高的可讀性。
hint FRAGMENT_SQL_COLUMN_CASE = "hump"
幾個(gè)可供配置的值:
- default:保持原樣,這是個(gè)默認(rèn)設(shè)置
- upper:全部轉(zhuǎn)大寫
- lower:全部轉(zhuǎn)小寫
- hump:轉(zhuǎn)換成駝峰
-
分頁查詢
默認(rèn)關(guān)閉,通過hint FRAGMENT_SQL_QUERY_BY_PAGE = true打開。
打開分頁后經(jīng)過3個(gè)步驟:
- 定義分頁SQL
- 創(chuàng)建分頁查詢對(duì)象
- 設(shè)置分頁信息
- 執(zhí)行分頁查詢
由于大部分前端是以1為第一頁,而默認(rèn)情況下SQL執(zhí)行器是以0為第一頁的,所以需要-1,如果是GET方式發(fā)布的話,還需要使用轉(zhuǎn)換函數(shù)。
import 'net.hasor.dataql.fx.basic.ConvertUdfSource' as convert; hint FRAGMENT_SQL_QUERY_BY_PAGE = true ... run queryPage.setPageInfo({"pageSize" : 5, // 頁大小"currentPage" : (convert.toInt(${pageNumber}) -1) });還有第二種方式,DataQL在4.1.8版本中加入FRAGMENT_SQL_QUERY_BY_PAGE_NUMBER_OFFSETHint,可以設(shè)置讓SQL執(zhí)行器以1作為開始。
-
數(shù)據(jù)庫事務(wù)
SQL執(zhí)行器本身并不支持事務(wù),需要借助事務(wù)函數(shù)來實(shí)現(xiàn)。
事務(wù)函數(shù)還可以嵌套使用。
import 'net.hasor.dataql.fx.db.TransactionUdfSource' as tran; //引入事務(wù)函數(shù) ... return tran.required(() -> {... // 事務(wù)return ... }); ...支持完整的7個(gè)傳播屬性:
類型說明用法 REQUIRED 加入已有事務(wù) tran.required(() -> { … }); REQUIRES_NEW 獨(dú)立事務(wù) tran.requiresNew(() -> { … }); NESTED 嵌套事務(wù) tran.nested(() -> { … }); SUPPORTS 跟隨環(huán)境 tran.supports(() -> { … }); NOT_SUPPORTED 非事務(wù)方式 tran.notSupported(() -> { … }); NEVER 排除事務(wù) tran.never(() -> { … }); MANDATORY 要求環(huán)境中存在事務(wù) tran.tranMandatory(() -> { … }); -
多數(shù)據(jù)源
SQL執(zhí)行器在4.1.4版本之后提供了通過hint來切換數(shù)據(jù)源的能力
public class MyModule implements Module {public void loadModule(ApiBinder apiBinder) throws Throwable {DataSource defaultDs = ...;DataSource dsA = ...;DataSource dsB = ...;apiBinder.installModule(new JdbcModule(Level.Full, defaultDs)); // 默認(rèn)數(shù)據(jù)源apiBinder.installModule(new JdbcModule(Level.Full, "ds_A", dsA)); // 數(shù)據(jù)源AapiBinder.installModule(new JdbcModule(Level.Full, "ds_B", dsB)); // 數(shù)據(jù)源B} } // 如果不設(shè)置 FRAGMENT_SQL_DATA_SOURCE 使用的是 defaultDs 數(shù)據(jù)源。 // - 設(shè)置值為 "ds_A" ,使用的是 dsA 數(shù)據(jù)源。 // - 設(shè)置值為 "ds_B" ,使用的是 dsB 數(shù)據(jù)源。 hint FRAGMENT_SQL_DATA_SOURCE = "ds_A"// 聲明一個(gè) SQL var dataSet = @@sql() <% select * from category limit 10; %> // 使用 特定數(shù)據(jù)源來執(zhí)行SQL。 return dataSet(); -
多條查詢
是指一次SQL執(zhí)行的過程中,包含了一個(gè)以上的SQL語句。
var dataSet = @@sql() <%set character_set_connection = 'utf8';select * from my_option; %>return dataSet(); // 默認(rèn)返回最后一個(gè)SQL語句的結(jié)果。 // 可以通過 FRAGMENT_SQL_MUTIPLE_QUERIES hint來控制,例如:保留每一條結(jié)果。
拆包模式可以通過hint改變,hint FRAGMENT_SQL_OPEN_PACKAGE = 'row'
//hint FRAGMENT_SQL_OPEN_PACKAGE = "off" var dataSet = @@sql() <% select count(*) as cnt from category; %> var result = dataSet(); // 不指定 hint 的情況下,會(huì)返回 category 表的總記錄數(shù),返回值為:10。 // 拆包模式變更為 row ,返回值為: { "cnt" : 10 } // 關(guān)閉拆包,返回值為標(biāo)準(zhǔn)的 List/Map: [ { "cnt" : 10 } ]Mybatis執(zhí)行器
在4.1.8版本后加入了@@Mybatis執(zhí)行器,這是對(duì)@@sql執(zhí)行器的擴(kuò)展,繼承了@@sql的能力,并提供了Mybatis的配置方式,提供了動(dòng)態(tài)SQL的能力。
-
對(duì)比@@sql的優(yōu)勢
- 繼承 @@sql 全部能力
- 提供動(dòng)態(tài)SQL能力,提供 SQL 層面的 if 和 for
- 類似 mybatis 的工作方式,比起 DataQL 拼接字符串注入更加安全可靠。
-
提供的標(biāo)簽
-
select
-
update
-
insert
-
delete
-
foreach:循環(huán)拼接SQL
- collection:集合,必填
- item:item,必填
- open:起始,選填
- close:結(jié)束,選填
- separator:分隔符,選填
-
if:判斷條件,成立時(shí)拼接標(biāo)簽內(nèi)內(nèi)容
- test:判斷條件,必填
-
FunctionX庫函數(shù)
依賴:
<dependency><groupId>net.hasor</groupId><artifactId>hasor-dataql-fx</artifactId><version>4.2.1</version> </dependency>轉(zhuǎn)換函數(shù)庫
引入轉(zhuǎn)換函數(shù)庫:import 'net.hasor.dataql.fx.basic.ConvertUdfSource' as convert;
- toInt(target):將Object轉(zhuǎn)換為Number,0x12->18,""->0,“abc”->throw error
- toString(target):將Object轉(zhuǎn)換為String,null->“null”,[1,2,3,4]->"[1, 2, 3, 4]",{“test”:123}->"{test=123}"
- toBoolean(target):將Object轉(zhuǎn)換為Boolean,支持on,off
- byteToHex(target):將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為十六進(jìn)制字符串,將List<Byte>轉(zhuǎn)換為String。
- hexToByte(target):將十六進(jìn)制字符串轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),將String轉(zhuǎn)換為List<Byte>
- stringToByte(target, charset):將字符串轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),將String轉(zhuǎn)換為List<Byte>,charset是String類型的字符集名稱,如’utf-8’
- ByteToString(target, charset):將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為字符串
集合函數(shù)庫
引入集合函數(shù)庫:import 'net.hasor.dataql.fx.basic.CollectionUdfSource' as collect;
-
isEmpty:注意:collect.isEmpty(null) = false// 不支持的基本類型會(huì)返回 false
-
size
-
merge:返回 List
-
mergeMap
-
filter(dataList, filterUDF):根據(jù)一個(gè)規(guī)則來對(duì)集合進(jìn)行過濾。filterUDF類型:Udf/Lambda
var result = collect.filter(dataList, (dat) -> {return dat.age > 20; }); -
filterMap(dataMap, keyFilterUDF)
-
limit(dataList, start, limit):截取List的一部分,返回一個(gè)List
-
newList
-
newMap(target):將一個(gè)map創(chuàng)建為帶狀態(tài)的Map,具有put(),putAll(),data(),size()方法
-
mapJoin(data_1,data_2,joinMapping):將兩個(gè)Map/List進(jìn)行左連接,joinMaping是Map類型,表示兩表的join關(guān)系。
import 'net.hasor.dataql.fx.basic.CollectionUdfSource' as collect;var year2019 = [{ "pt":2019, "item_code":"code_1", "sum_price":2234 },{ "pt":2019, "item_code":"code_2", "sum_price":234 },{ "pt":2019, "item_code":"code_3", "sum_price":12340 },{ "pt":2019, "item_code":"code_4", "sum_price":2344 } ]; var year2018 = [{ "pt":2018, "item_code":"code_1", "sum_price":1234.0 },{ "pt":2018, "item_code":"code_2", "sum_price":1234.0 },{ "pt":2018, "item_code":"code_3", "sum_price":1234.0 },{ "pt":2018, "item_code":"code_4", "sum_price":1234.0 } ];var result = collect.mapJoin(year2019,year2018, { "item_code":"item_code" }) => [{"商品Code": data1.item_code,"去年同期": data2.sum_price,"今年總額": data1.sum_price,"環(huán)比去年增長": ((data1.sum_price - data2.sum_price) / data2.sum_price * 100) + "%"} ] return result; -
mapKeyToLowerCase:將Map的Key全部轉(zhuǎn)為小寫,如果Key沖突會(huì)產(chǎn)生覆蓋
-
mapKeyToUpperCase:將Map的Key全部轉(zhuǎn)為大寫,如果Key沖突會(huì)產(chǎn)生覆蓋
-
mapKeyToHumpCase:將Map的Key中下劃線轉(zhuǎn)為駝峰,如果Key沖突會(huì)產(chǎn)生覆蓋
-
mapKeys:提取Map的Key,返回List
-
mapValues:提取Map的Values,返回List
-
mapKeyReplace(dataMap, replaceKey):循環(huán)遍歷每一個(gè)Map元素,并對(duì)Map的Key進(jìn)行替換,replaceKey是用于生成新key的函數(shù)。
var data = {"key1":1, "key2":2, "key3":3 }; var result = collect.mapKeyReplace(data, (oldKey,value) -> {return "new_" + oldKey }); // result = {"new_key1":1, "new_key2":2, "new_key3":3 } -
mapValueReplace:同上,不過是對(duì)值的處理
-
list2map(listData, dataKey, convertUDF):將List轉(zhuǎn)為Map,dataKey是鍵的名字,可以用字符串,也可以直接獲取,convertUDF是轉(zhuǎn)換的函數(shù),可以不寫。
//通過字符串指明Key字段 var yearData = [{ "pt":2018, "item_code":"code_1", "sum_price":12.0 },{ "pt":2018, "item_code":"code_2", "sum_price":23.0 },{ "pt":2018, "item_code":"code_3", "sum_price":34.0 },{ "pt":2018, "item_code":"code_4", "sum_price":45.0 } ];var result = collect.list2map(yearData, "item_code"); // result = { // "code_1": { "pt":2018, "item_code":"code_1", "sum_price":12.0 }, // "code_2": { "pt":2018, "item_code":"code_2", "sum_price":23.0 }, // "code_3": { "pt":2018, "item_code":"code_3", "sum_price":34.0 }, // "code_4": { "pt":2018, "item_code":"code_4", "sum_price":45.0 } // };//使用提取出來的值作為key var yearData = [ 1,2,3,4,5]; var result = collect.list2map(yearData, (idx,dat)-> {// Key 提取函數(shù),直接把數(shù)組的數(shù)字元素內(nèi)容作為 key 返回return dat; },(idx,dat) -> {// 構(gòu)造 valuereturn { "index": idx, "value": dat }; });// result = { // "1": { "index": 0, "value": 1 }, // "2": { "index": 1, "value": 2 }, // "3": { "index": 2, "value": 3 }, // "4": { "index": 3, "value": 4 }, // "5": { "index": 4, "value": 5 } // } -
map2list(dataMap, convert):將List轉(zhuǎn)換為Map,convert是轉(zhuǎn)換函數(shù)。
// 不指定轉(zhuǎn)換函數(shù) var data = {"key1":1, "key2":2, "key3":3 }; var result = collect.map2list(data); // result = [ // { "key": "key1", "value": 1}, // { "key": "key2", "value": 2}, // { "key": "key3", "value": 3} // ]// 指定轉(zhuǎn)換函數(shù) var data = {"key1":1, "key2":2, "key3":3 }; var result = collect.map2list(data, (key,value) -> {return { "k" : key, "v" : value }; }); // result = [ // { "k": "key1", "v": 1}, // { "k": "key2", "v": 2}, // { "k": "key3", "v": 3} // ] -
map2string(dataMap, joinStr, convert):將Map轉(zhuǎn)換成字符串,通常在生成Url參數(shù)時(shí)用到,joinStr表示連接符。
var data = {"key1":1, "key2":2, "key3":3 }; var result = collect.map2string(data,"&",(key,value) -> {return key + "=" + value; }); // result = "key1=1&key2=2&key 3=3" -
mapSort(dataMap, sortUdf):DataQL中的Map是有序的,因此可以排序。
-
listSort(dataList, sortUdf):對(duì)List進(jìn)行排序
-
groupBy(dataList, groupByKey):根據(jù)公共字段對(duì)數(shù)據(jù)進(jìn)行分組。groupByKey是String是要分組的字段名。數(shù)據(jù)集中需要有一個(gè)公共字段。
-
uniqueBy(dataList, uniqueByKey):根據(jù)公共字段去重,只返回第一次出現(xiàn)的。數(shù)據(jù)集中需要有一個(gè)公共字段。
時(shí)間日歷函數(shù)庫
引入函數(shù)庫:import 'net.hasor.dataql.fx.basic.DateTimeUdfSource' as time;
- now:返回當(dāng)前時(shí)間戳
- year(time):返回時(shí)間戳中的年份,獲取當(dāng)前年份:time.year(time.now())
- month(time):返回時(shí)間戳中的月份。
- day、dayOfMonth:返回時(shí)間戳中的日期是這個(gè)月的第幾天。
- hour
- minute
- second
- dayOfYear(time):返回時(shí)間戳中的日期是全年的第幾天。
- dayOfWeek(time):返回時(shí)間戳中的日期是這周的第幾天,SUNDAY=1。
- format(time, pattern):對(duì)時(shí)間戳進(jìn)行時(shí)間日期格式化,底層使用的是java.text.SimpleDateFormat
- parser(time, pattern):對(duì)時(shí)間按照格式進(jìn)行解析,解析為時(shí)間戳。
Json函數(shù)庫
引入函數(shù)庫:import 'net.hasor.dataql.fx.basic.JsonUdfSource' as json;
- toJson(target):返回String,把對(duì)象JSON序列化。
- toFmtJson(target):返回String,把對(duì)象JSON序列化(帶格式)。
- fromJson(jsonString):把JSON格式的字符串解析成對(duì)象。
字符串函數(shù)庫
引入函數(shù)庫:import 'net.hasor.dataql.fx.basic.StringUdfSource' as string;
- startsWith(str, prifix):是否以xxx開頭
- startsWithIgnoreCase
- endsWith(str, prifix):是否以xxx結(jié)尾
- endsWithIgnoreCase
- lineToHump(str):下劃線轉(zhuǎn)駝峰
- humpToLine
- firstCharToUpperCase(str):首字母大寫
- firstCharToLowerCase
- toUpperCase
- toLowerCase
- indexOf(str, searchStr):查找第一次出現(xiàn)的位置
- indexOfWithStart(str, searchStr, startPos):從某一位置開始,查找之后第一次出現(xiàn)的位置
- indexOfIgnoreCase
- indexOfIgnoreCaseWithStart
- lastIndexOf
- lastIndexOfWithStart
- lastIndexOfIgnoreCase
- lastIndexOfIgnoreCaseWithStart
- contains(str, searchStr):是否包含字符串。
- containsIgnoreCase
- containsAny(str, searchStrArray):是否包含,指定List中的值。
- containsAnyIgnoreCase
- trim
- sub(str, start, end):獲取指定位置的子串。
- left(str, len):獲取最左邊的指定長度的串。
- right
- alignRight:右對(duì)齊,不足的向右填充
- alignLeft
- alignCenter
- compareString:比較兩個(gè)字符串大小
- compareStringIgnoreCase
- split
- join(array, separator):用separator將array拼裝成字符串
- isEmpty
- equalsIgnoreCase
狀態(tài)函數(shù)庫
引入函數(shù)庫:import 'net.hasor.dataql.fx.basic.StateUdfSource' as state;
- decNumber(initValue):返回一個(gè) Udf,每次調(diào)用這個(gè) UDF,都會(huì)返回一個(gè) Number。Number 值較上一次會(huì)自增 1。
- incNumber(initValue):返回一個(gè) Udf,每次調(diào)用這個(gè) UDF,都會(huì)返回一個(gè) Number。Number 值較上一次會(huì)自減 1。
- uuid():返回一個(gè)完整格式的UUID字符串
- uuidToShort():返回一個(gè)不含’-'的UUID字符串
Web函數(shù)庫
引入函數(shù)庫:import 'net.hasor.dataql.fx.web.WebUdfSource' as webData;
- cookieMap
- cookieArrayMap
- getCookie
- getCookieArray
- tempCookie
- tempCookieAll
- storeCookie
- removeCookie
- headerMap
- headerArrayMap
- getHeader
- getHeaderArray
- setHeaderAll
- addHeader
- addHeaderAll
- sessionKeys
- getSession
- setSession
- removeSession
- cleanSession
- sessionInvalidate
- sessionId
- sessionLastAccessedTime
簽名/編碼函數(shù)庫
引入函數(shù)庫:import 'net.hasor.dataql.fx.encryt.CodecUdfSource' as codec;
- encodeString
- decodeString
- encodeBytes
- decodeBytes
- urlEncode
- urlEncodeBy
- urlDecode
- urlDecodeBy
- digestBytes
- digestString
- hmacBytes
- hmacString
總結(jié)
- 上一篇: QT运行时的Debug、Release、
- 下一篇: gpu浮点计算能力floaps_认识GP