在平常的開發過程當中,咱們經常要處理不一樣來源的數據。數據可能來自不可靠的外部系統、不可靠的用戶輸入和甚至設計有誤的數據庫表,所以,對數據有效性進行驗證是必要的工做。html
開源工具ABAP Data Validator是一個使用ABAP開發的數據驗證工具,它能夠簡化開發者在這方面的工做。本文將介紹它的用法和一些設計思路。git
本文連接:http://www.javashuo.com/article/p-xyujegzf-ha.htmlgithub
原創內容,轉載請註明web
具體而言,ABAP Data Validator將經過如下的思路簡化數據有效性驗證方面的工做:正則表達式
爲了實現以上目的,該工具實現了一些功能:數據庫
ABAP Data Validator目前支持如下類型的檢查(持續更新中):編程
此外,它也支持對內表字段的必填檢查、根據數據元素的類型進行檢查等功能,下文會詳細介紹。服務器
ABAP Data Validator支持多種檢查方式,下面會由簡單到複雜進行逐一介紹。函數
對於每種數據類型,ABAP Data Validator會有一個專門的檢查類,能夠用這些檢查類的is_valid方法來檢查變量的值是否有效,就像使用abap的內置函數那樣。好比,要檢查一個字符串是不是有效的郵箱地址,能夠用以下代碼實現,工具
IF zcl_adv_email_check=>is_valid( 'example@github.com' ). "do something ENDIF.
全部的檢查類都實現了接口zif_adv_check,所以它們都擁有靜態方法is_valid,以下圖(爲了方便閱讀,圖中沒有包含所有的實現類),
對於類方法而言,is_valid是個別名,也能夠不使用別名來調用接口方法:
IF zcl_adv_email_check=>zif_adv_check~is_valid( 'example@github.com' ). "do something ENDIF.
固然並不推薦這種方式,由於會讓代碼變長。
檢查類的命名規則是ZCL_ADV_類型名_CHECK。
爲了便於使用,方法is_valid的定義十分簡單,只有一個輸入參數、一個返回值,不包含任何異常,這使得它沒法勝任數量、金額等類型(通常而言是P類型,包含長度和小數位定義)字段的檢查。爲了解決這一問題,ABAP Data Validator提供了參考數據元素進行檢查的用法。可使用類zcl_adata_validator的方法validate_by_element使用該功能,示例以下,
DATA(result) = NEW zcl_adata_validator( )->->validate_by_element( data = data element = 'MENGE_D' "數量 ).
result是一個結構,包含兩個字段valid和type,若是data的值沒法轉換爲數字、或者轉換後溢出的話,result-valid將被賦值爲abap_false(即空);若是data是一個有效值,那麼rresult-valid將被賦值爲abap_true(即'X')。
正常狀況下,result-type總會被賦值爲數據元素的類型,對P類型,則爲固定值’PACKED‘(c_type_packed)。但若是輸入的數據元素無效的話,type則會被賦值爲固定值’Invalid Type‘(c_type_invalid)。
目前支持如下類型的數據元素:
爲了保持檢查方法的簡單性,validate_by_element方法的定義一樣不包含異常。任何異常都會在方法內部被處理。出現異常時,result-valid會被賦值爲abap_false,type會被賦值爲’Invalid Type‘。
ABAP Data Validator能夠根據指定的規則對內表進行檢查,以下所示,將規則my_rules和內表uploaded_data傳入類zcl_adata_validator的方法validate,能夠獲得檢查結果內表results,
TRY. DATA(results) = NEW zcl_adata_validator( )->validate( rules = my_rules data = uploaded_data ). CATCH zcx_adv_exception INTO DATA(ex). DATA(msg) = ex->get_text( ). ENDTRY.
檢查規則rules用於設定檢查邏輯。
rules的類型定義以下,
TYPES: BEGIN OF ty_rule, fname TYPE name_komp, "字段名 required TYPE abap_bool, "必填 initial_or_empty TYPE abap_bool, "必須爲空或初始值 user_type TYPE ty_spec_type,"檢查類型(參考類zcl_adata_validator的常量列表) regex TYPE string, "自定義正則表達式 regex_msg TYPE string, "自定義正則表達式檢查失敗消息 ref_element TYPE rollname, "參考數據元素 END OF ty_rule. TYPES: ty_rules_t TYPE HASHED TABLE OF ty_rule WITH UNIQUE KEY fname.
簡單的示例以下,
DATA: rules TYPE zcl_adata_validator=>ty_rules_t. *字段1爲必填字段,類型是日期,字段2非必填,類型爲郵件地址 rules = VALUE #( ( fname = 'FIELD1' required = abap_true user_type = zcl_adata_validator=>c_type_date ) ( fname = 'FIELD2' user_type = zcl_adata_validator=>c_type_email ) ).
使用ABAP Data Validator自帶的檢查邏輯能夠知足不少場景下的基本檢查須要,可是你也許還有更多的檢查邏輯。有2種方式能夠實現檢查功能的擴展。
正則表達式示例:若是你不只要檢查一個字段的值是否爲郵件地址,還要驗證它是gmail郵箱,那麼能夠把正則表達式’gmail\.com$‘複製給rules-regex,
DATA: rules TYPE zcl_adata_validator=>ty_rules_t. DATA: cases TYPE ty_case_t. cases = VALUE #( ( field3 = 'ZZZ2@gmail.com') "正確,是gmail郵箱 ( field3 = 'ZZZ2@qq.com') "不正確,非gmail郵箱 ). rules = VALUE #( ( fname = 'FIELD2' user_type = zcl_adata_validator=>c_type_email regex = 'gmail\.com$' regex_msg = 'Only gmail supported') ).
或者建立一個新類型和它的檢查類,而且把它的檢查類配置傳入constructor,
DATA: check_class_config TYPE zcl_adata_validator=>ty_check_config_t. check_class_config = VALUE #( ( type = zcl_adata_validator=>c_type_new class = 'ZCL_NEW_VALIDATOR' ) ). TRY. DATA(result) = NEW zcl_adata_validator( check_class_conifg = check_class_config )->validate( rules = rules data = cases ). CATCH zcx_adv_exception INTO DATA(ex). DATA(msg) = ex->get_text( ). ENDTRY.
注意:constructor中已經包含了默認的檢查類配置和檢查消息配置,它們是Hard coding,一旦傳入自定義配置,它們就會被覆蓋。
能夠按需對方法進行重定義、或者傳入本身的配置。好比,從數據庫或其它來源讀取配置,這樣能夠在不修改既有代碼的狀況下擴展程序的功能。
DATA: check_class_config TYPE zcl_adata_validator=>ty_check_config_t. SELECT * FROM my_config_table INTO TABLE @check_class_config. TRY. DATA(result) = NEW zcl_adata_validator( check_class_conifg = check_class_config )->validate( rules = rules data = cases ). CATCH zcx_adv_exception INTO DATA(ex). DATA(msg) = ex->get_text( ). ENDTRY.
https://github.com/hhelibeb/abap-data-validator
我提交了絕大部分代碼,此外還有2位貢獻者larshp和FreHu,他們幫助修正了代碼格式和readme方面的一些問題。
歡迎參與這個工具的開發!若是你發現程序有任何問題,也能夠在github提交issue告知我。
有效性的定義十分重要,若是有效的定義是模糊的,那檢查也失去了意義。
對於ABAP Data Validator,若是一個檢查類型存在對應的ABAP數據類型(好比日期,時間戳等),那麼「有效」是指:
以時間戳爲例,
2021-12-21 00:00:00’\可能在某些情境下是合理的時間戳值,可是對於ABAP Data Validator而言,它是無效的,由於將它賦值給時間戳類型的變量會致使dump。而'19000000235959'雖然能夠被賦值給ABAP時間戳變量,但由於沒有實際意義,它一樣是無效值。
這種類型檢查的邏輯主要由SAP提供的標準功能實現,時間戳的檢查實際上由正則檢查、標準函數DATE_CHECK_PLAUSIBILITY和TIME_CHECK_PLAUSIBILITY組成。
若是一個檢查類型沒有對應的ABAP數據類型,ABAP Data Validator的檢查邏輯收集自一些相對權威的來源,這些檢查邏輯一般會符合行業標準。來源包括,
絕大部分檢查邏輯是成熟的,且它們都包含單元測試。你能夠在單元測試中加上本身的用例來驗證它們的行爲是否符合你的指望。
HTML檢查是個例外,它是惟一一個須要調用外部API(https://validator.w3.org/)的檢查,並且w3.org提供的API自己也只是實驗性的。請只把它的檢查結果看成參考。
目前,我已經在工做中部分地應用了ABAP Data Validator,看起來工做良好。