一、簡介
1.1 介紹
oql4j 全稱 Object Query Language For Java,即java版本的物件查詢語言,支援使用編寫查詢語言快速的搜尋出符合條件的物件,簡化物件的過濾處理操作。
目前支援where條件的過濾和select的對映查詢,後續將支援update更新等操作。
二、使用指南
2.1 依賴說明
- 基於jdk8版本
- 依賴antlr4包(pom依賴自動引入)
- 依賴commons-beanutils包(pom依賴自動引入)
2.2 使用主程式碼
OqlClientBuilder oqlClientBuilder = new OqlClientBuilder();
OqlClient oqlClient = oqlClientBuilder.build();
然後就可以使用oqlClient物件,進行各種where條件的操作,select的對映查詢,例如操作oqlClient.doWhereFilter(...)、oqlClient.doSelect(...)
OqlClient介面的預設實現類是DefaultOqlClientImpl,此類是執行緒安全的,所以oqlClient物件可作為單例在整個專案中使用。
2.3 Where條件使用案例的demo
OqlClientBuilder oqlClientBuilder = new OqlClientBuilder();
OqlClient oqlClient = oqlClientBuilder.build();
// 原資料
Map<String, String> srcMap = new HashMap<>();
srcMap.put("name", "李明");
// 編寫oql語法
String whereOqlExp = " ${name} is not null ";
// name欄位不為空,判斷是否存在這樣的原資料。
boolean result = oqlClient.doWhereExists(whereOqlExp, srcMap);
// 列印的結果為true
System.out.println(result);
更多的使用demo,可參考程式碼的測試用例:com.cat.oqj4j.core.OqlClientlWhereTest
2.4 Select對映使用案例的demo
OqlClientBuilder oqlClientBuilder = new OqlClientBuilder();
OqlClient oqlClient = oqlClientBuilder.build();
// 原資料
PersonTest p01 = new PersonTest();
p01.setName("張三");
p01.setIsMan(true);
p01.setAge(36);
// 編寫oql語法
String selectOqlExp = " ${age} myAge, ${isMan} as knownGender, ${name} as myName, ${addr.province} as myAddr.province, ${addr.city} myAddr.city";
// 執行select對映,將對映結果賦值到MyPersonTest物件。
MyPersonTest result = oqlClient.doSelect(selectOqlExp, p01, MyPersonTest.class);
更多的使用demo,可參考程式碼的測試用例:com.cat.oqj4j.core.OqlClientlSelectTest
三、語法規則
3.1 語法基礎
3.1.1 基本型別說明:
型別 | 型別demo |
---|---|
字串 | 有單雙引號的內容都是屬於字串,例如 "name"、'name' 表示常量name |
數值 | 數字類的都屬於數值型別,包括整數和小數以及科學計數法,例如99、9993.66、-321、 1e3 |
布林 | 布林值型別,只有真和假,並且不區分大小寫,例如true、True、TRUE、false、False、FALSE |
null | null型別,並且不區分大小寫,例如null、Null、NULL |
3.1.2 語法概覽:
關鍵字 | 說明 | 語法demo | 詳細說明 |
---|---|---|---|
${} | 取值操作 | ${name} 表示取物件的name屬性 |
3.1.2.1 取值操作 |
F{} | 執行函式 | F{StrLen(${name})} 表示取出物件的name屬性值並且執行StrLen函式 |
3.1.2.2 執行函式 |
3.1.2.1 取值操作
- 使用
${}
來表示,例如${name}
表示取物件的name屬性值,支援巢狀取值,使用.來分割,
例如${addr.city}
表示取物件的addr屬性下的city屬性,即取出addr屬性後,再操作addr物件取出city屬性。
- 注意巢狀取值時,如果上層屬性必為null,則直接返回null值,例如巢狀取city屬性時,city的上層屬性addr為null,則取到的city屬性也為null。
- 取值操作是基本語法,支援在select對映語法、where條件語法中使用。
3.1.2.2 執行函式
-
用於執行預定義和自定義的函式,使用F{}關鍵字,關鍵字不區分大小寫, F{}、f{} 都能識別。
-
格式為
F{funName}、F{funName()}、F{funName(arg1,arg2...)}
均支援,預設都會傳操作集合的原物件和遍歷的當前物件這兩個引數,
有需要的可以額外追加引數,並且追加的引數可以為常量引數也可以為動態取值引數。
例如:F{StrLen(${name})}
表示取出物件的name屬性值作為引數,執行StrLen函式。
例如:F{CastInt(F{StrLen(${age})})} > 2
表示取出物件的age屬性值,取得字串長度,然後再轉換為int型別,並對函式結果進行大於2判斷。
-
取值操作是基本語法,支援在select對映語法、where條件語法中使用。
例如在select對映語法的使用:F{IfNull(${name}, '未知')}
例如在where條件語法的使用:F{StrLen(${name})} > 2
-
框架預定義的函式如下(支援自定義函式,具體可檢視 5.1 自定義函式):
函式名 功能 所需引數 詳細說明 StrLen 字串長度 StrLen(arg1),arg1:用於判斷字串長度的引數 將傳入的引數轉換為字串,統計並返回字串長度。如果引數為null,則返回長度為0。 If 三元表示式條件處理 If(arg1,arg2,arg3),arg1:用於判斷條件的真假,arg2:條件為真時的返回值,arg3:條件為假時的返回值 用於判斷arg1引數,如果為真則返回arg2引數,反之返回arg3。數值0和false字串都屬於假,1和true字串則屬於真(false和true字串不區分大小寫)。 IfNull null結果時取預設值 IfNull(arg1,arg2),arg1:主引數值,arg2:預設值 如果arg1引數不為null則返回此值,否則返回arg2引數。 CastStr 轉換為字串 CastStr(arg1),arg1:用於轉換為字串的引數 將傳入的引數轉換為字串,如果引數為null,則返回null。 CastBigDec 轉換為BigDecimal CastBigDec(arg1),arg1:用於轉換為BigDecimal的引數 將傳入的引數轉換為BigDecimal,如果引數為null,則返回null。 CastInt 轉換為Integer CastInt(arg1),arg1:用於轉換為Integer的引數 將傳入的引數轉換為Integer,如果引數為null,則返回null。 CastLong 轉換為Long CastLong(arg1),arg1:用於轉換為Long的引數 將傳入的引數轉換為Long,如果引數為null,則返回null。 CastByte 轉換為Byte CastByte(arg1),arg1:用於轉換為Byte的引數 將傳入的引數轉換為Byte,如果引數為null,則返回null。 CastFloat 轉換為Float CastFloat(arg1),arg1:用於轉換為Float的引數 將傳入的引數轉換為Float,如果引數為null,則返回null。 CastDouble 轉換為Double CastDouble(arg1),arg1:用於轉換為Double的引數 將傳入的引數轉換為Double,如果引數為null,則返回null。 CastChar 轉換為Character CastChar(arg1),arg1:用於轉換為Character的引數 將傳入的引數轉換為Character,如果引數為null或者為""字串,則返回null,長度大於1則轉換報錯。 CastBool 轉換為Boolean CastBool(arg1),arg1:用於轉換為Boolean的引數 將傳入的引數轉換為Boolean,如果引數為null,則返回null。數值0和false字串都屬於假,1和true字串則屬於真(false和true字串不區分大小寫)。 ClassSimpleName 獲取Class簡短名稱 ClassSimpleName(arg1),arg1:用於獲取Class位元組碼物件的簡短名稱的引數 將傳入的引數去除Class位元組碼物件並獲取簡短名稱,如果引數為null,則返回"null"字串。 NotExistNull 判斷全部引數都不為null NotExistNull(arg1,arg2,arg3...),需要判斷的引數,不限制引數數量 將傳入的引數逐一判斷,如果都不為null則返回true,反之false。如果沒有傳入任何引數,則返回true。 -
框架預定義的函式使用demo,可參考程式碼的測試用例:com.cat.oqj4j.core.OqlClientFunTest
3.2 Where條件語法
3.2.1 語法概覽:
關鍵字 | 說明 | 語法demo | 詳細說明 |
---|---|---|---|
and | 並且條件 | ${name} = '張三' and ${age} > 20 表示名稱為張三並年齡大於20 |
3.2.1.1 並且條件 |
or | 或者條件 | ${name} = '張三' or ${name} = '李四' 表示名稱為張三或者李四 |
3.2.1.2 或者條件 |
() | 括號運算 | (${name} = '張三' or ${name} = '李四') and ${age} > 20 表示先判斷名稱可為張三或者李四,然後再判斷年齡大於20歲 |
3.2.1.3 括號運算 |
in | 同時指定多個或者條件 | ${name} in ('張三','李四') 表示名稱為張三或者李四 |
3.2.1.4 同時指定多個或者條件 |
between | 範圍條件 | ${age} between 20 and 30 表示年齡在[20,30]範圍內 |
3.2.1.5 範圍條件 |
is null | 等於空 | ${name} is null 表示姓名為null 等價於 ${name} = null |
3.2.1.6 等於空 |
is not null | 不等於空 | ${name} is not null 表示姓名不為null 等價於 ${name} != null |
3.2.1.7 不等於空 |
3.2.1.1 並且條件
- 對多個條件進行交集處理,and關鍵字不區分大小寫,即and、And、AND 都能識別。
- 支援用 && 代替and關鍵字。例如:
${name} = '張三' and ${age} > 20
等價於${name} = '張三' && ${age} > 20
- and的優先順序比or要高。
3.2.1.2 或者條件
- 對多個條件進行並集處理,or關鍵字不區分大小寫,即or、Or、OR 都能識別。
- 支援用 || 代替or關鍵字。例如:
${name} = '張三' or ${age} > 20
等價於${name} = '張三' || ${age} > 20
- or的優先順序小於and。
3.2.1.3 括號運算
- 用於提升運算優先順序,使用()將表示式括起來,括號內的表示式將優先執行,常用於在and、or條件下進行配套使用。
- 括號表示式的運算優先順序比and、or都高
3.2.1.4 同時指定多個或者條件
- 當存在or引數時,可以使用in關鍵字來實現,關鍵字不區分大小寫,即in、In、IN都能識別。
- 格式為
keyName in (arg1,arg2,arg3,arg4...)
,arg引數可以是常量引數,也可以是動態取值引數,
例如${name} in ('李白', ${formerName})
表示判斷物件的name屬性值是否為 李白 或者為此物件的formerName屬性。 - in內的arg引數不限制數量,並且可以同時為各種型別資料,例如可以同時有字串型別、數值型別等。
3.2.1.5 範圍條件
- 當需要判斷範圍時,可以使用between關鍵字,關鍵字不區分大小寫,即between、Between、BETWEEN等都能識別。
- 格式為
keyName between arg1 and arg2、keyName between arg1 && arg2
, 大於等於arg1 並且小於等於 arg2,等價於 >=arg1 and <=arg2。
例如${age} between 20 and 30
表示年齡在[20,30]範圍內,20、21、29、30等均符合,用&&寫法則為${age} between 20 && 30
3.2.1.6 等於空
- 用於判斷值是否為null,使用 is null 關鍵字,關鍵字不區分大小寫, is、IS、null、Null、NULL等都能識別。
- 格式為
keyName is null
, 例如${name} is null
表示name屬性值為null的判斷,也等價於${name} = null
表示式。
3.2.1.7 不等於空
- 用於判斷值是否不為null,使用 is not null 關鍵字,關鍵字不區分大小寫, is、IS、not、Not、null、Null、NULL等都能識別。
- 格式為
keyName is not null
, 例如${name} is not null
表示name屬性值不為null的判斷,也等價於${name} != null
表示式。
3.2.2 其他說明:
- where條件支援使用比較符合,具體符合和比較規則,詳見 4.1 比較說明。
- 當使用單指作為條件時,必須是布林型別,或者是可以轉換為布林型別的數字或字串,否則語法執行將報錯。布林型別轉換詳見4.2 布林型別的轉換。
3.3 Select對映語法
3.3.1 使用格式:
- 直接寫需要對映的欄位,欄位間使用英文逗號分隔,例如: name1, name2, name3, name4 ...
3.3.1 指定對映別名:
- 預設不指定的情況下,則直接用原欄位名稱,例如: ${name1}, ${name2} 表示取原物件的name1和name2屬性,並對映賦值到目標物件的name1和name2屬性。
如果是使用${}動態取值,預設情況下對映到目標物件的名稱為取值欄位名,例如${name} 表示取原物件的name屬性,並對映賦值到目標物件的name屬性。
如果是F{}函式,預設情況下對映到目標物件的名稱為函式名,例如F{ClassSimpleName(${name})} 表示取原物件的name屬性,並執行ClassSimpleName函式後,將結果對映賦值到目標物件的ClassSimpleName屬性。
- 使用空格方式指定。例如:${name1} fatherName, ${name2} motherName 表示取原物件的name1和name2屬性,並對映賦值到目標物件的fatherName和motherName屬性。
- 使用AS關鍵字指定,並且as關鍵字不區分大小寫。例如:${name1} AS fatherName, ${name2} as motherName 表示取原物件的name1和name2屬性,並對映賦值到目標物件的fatherName和motherName屬性。
四、約定說明
4.1 比較說明
-
目前支援的比較符號如下
符號 含義 > 大於 < 小於 = 等於 >= 大於等於 <= 小於等於 != 不等於 <> 不等於 -
支援不同型別進行比較,規則如下:
- 判斷相等時:如果是相同型別,判斷相等時直接呼叫物件的equalse方法比較。
- 判斷相等時:如果比較物件有null,則要求另外個物件也必須為null才相等,否則均為不等。
- 判斷相等時:如果比較物件有個為布林型別,另外個物件為字串或數字時,則嘗試統一轉換為布林值進行比較。0和false字串都屬於假,1和true字串則屬於真(false和true字串不區分大小寫)。
- 判斷相等時:如果都是同屬於Number子類,則轉換為浮點型比較。
- 判斷相等時:如果都是屬於其中一種(java原始型別、字串型別、Number子類),統一獲取物件字串進行比較。
- 判斷大小時:如果存在有物件為null,屬於無法比較大小,均返回false。
- 判斷大小時:如果物件均為BigDecimal,轉為BigDecimal進行比較
- 判斷大小時:如果都是同屬於Number子類,則轉換為浮點型比較。
- 判斷大小時:如果存在有物件為布林值,屬於無法比較大小,均返回false。
- 判斷大小時:如果都是屬於其中一種(java原始型別、字串型別、Number子類),統一獲取物件字串進行比較(先比較長度,然後在比較asscii碼值)。
4.2 布林型別的轉換
- 支援原生的布林型別
- 如果是數字型別(Number子類),0屬於假可以轉換為false布林值,1屬於真可以轉換為true布林值。
- 如果是字串型別,"false"、'false'字串屬於假可以轉換為false布林值,"true"、'true'字串屬於真可以轉換為true布林值,並且字串不區分大小寫。
4.3 關鍵字大小寫
除特殊情況外,預設情況下,關鍵字是不區分大小寫的,均能識別,可根據需要自行選擇使用。例如 And、AND、and、As、AS、as 等關鍵字都能識別。
4.4 執行緒安全
凡是對應的介面或者類名上有com.cat.oqj4j.annotation.ThreadSafe註解的,均表示此介面實現類和指定類都是執行緒安全的,生成的物件可作為單例使用。
五、高階應用
5.1 自定義函式
- 除了使用框架預定義的函式以外,還支援自定義函式,方式如下:
- 實現com.cat.oqj4j.antlr.handler.FunHandler介面,或者繼承com.cat.oqj4j.antlr.handler.AbstractFunHandler類。注意實現類必須是執行緒安全的。
- 註冊函式,在OqlClientBuilder構造時註冊,然後在表示式中透過F{}即可使用。
- 實現com.cat.oqj4j.antlr.handler.FunHandler介面,或者繼承com.cat.oqj4j.antlr.handler.AbstractFunHandler類。注意實現類必須是執行緒安全的。
OqlClientBuilder oqlClientBuilder = new OqlClientBuilder();
// MyFunHandler是你自定義的函式類,根據需要更改類名。注意MyFunHandler是滿足執行緒安全的。
oqlClientBuilder.registerFunHandler(new MyFunHandler());
5.2 自定義bean操作
- 對bean的設值和賦值的操作,目前框架使用的是ApacheUtilsBeanHandler,此類是基於apache的commons-beanutils工具包的PropertyUtils類來實現,如果需要者可以自定義bean操作類,方式如下:
- 實現com.cat.oqj4j.support.BeanHandler介面。注意實現類必須是執行緒安全的。
- 設定bean操作器,在OqlClientBuilder構造時設定,後續對bean的操作都會自動用此操作器。
- 實現com.cat.oqj4j.support.BeanHandler介面。注意實現類必須是執行緒安全的。
OqlClientBuilder oqlClientBuilder = new OqlClientBuilder();
// MyBeanHandler是你實現的bean操作器,根據需要更改類名。注意MyBeanHandler是滿足執行緒安全的。
oqlClientBuilder.setBeanHandler(new MyBeanHandler());
附加
原始碼將釋出在github上進行管理,同時在gittee進行放開檢視。
- github地址(支援編輯): https://github.com/cat4416/oql4j
- gitee地址(僅能檢視):https://gitee.com/cat4416/oql4j
作者聯絡方式:
- 微訊號(wechat):cat4416
- 郵箱:565335545@qq.com