在日常的开发过程中,我们常常要处理不同来源的数据。数据可能来自不可靠的外部系统、不可靠的用户输入和甚至设计有误的数据库表,因此,对数据有效性进行验证是必要的工作。

开源工具ABAP Data Validator是一个使用ABAP开发的数据验证工具,它可以简化开发者在这方面的工作。本文将介绍它的用法和一些设计思路。

本文链接:https://www.cnblogs.com/hhelibeb/p/12206648.html

原创内容,转载请注明

目的

具体而言,ABAP Data Validator将通过以下的思路简化数据有效性验证方面的工作:

  • 提供统一的检查接口,让开发者通过单次方法调用就可以实现对数据的检查。
  • 将验证逻辑集中实现,避免相似的检查代码分散在系统各处造成的逻辑不一致,从而降低相关程序的维护成本。
  • 避免检查过程中的潜在dump,减少开发者处理dump问题的精力花费。

为了实现以上目的,该工具实现了一些功能:

  • 内置常见的验证逻辑。
  • 可配置的检查规则。
  • 可扩展的检查程序。
  • 异常的统一处理。

支持的检查列表

ABAP Data Validator目前支持以下类型的检查(持续更新中):

  • 日期.
  • 时间.
  • 时间戳.
  • 邮件地址.
  • INT4.
  • 正则字符串.
  • URL.
  • JSON.
  • HEX.
  • IMEI.
  • GUID.
  • BASE64.
  • HTML (实验性的).

此外,它也支持对内表字段的必填检查、根据数据元素的类型进行检查等功能,下文会详细介绍。

使用

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)。

目前支持以下类型的数据元素:

  • 日期
  • 时间
  • 时间戳
  • INT4
  • GUID
  • HEX
  • DEC(P类型)

为了保持检查方法的简单性,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种方式可以实现检查功能的扩展。

  1. 通过rules-regex传入正则表达式。
  2. 创建新的检查类型:定义新的类型名,创建它的检查类,实现接口zif_adv_check,将自定义检查逻辑写在is_valid方法的实现中。接着,将类型名和类名传入zcl_adata_validator的构造方法constructor中。这样就可以使用新的检查类型了。

正则表达式示例:如果你不仅要检查一个字段的值是否为邮件地址,还要验证它是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位贡献者larshpFreHu,他们帮助修正了代码格式和readme方面的一些问题。

欢迎参与这个工具的开发!如果你发现程序有任何问题,也可以在github提交issue告知我。

Q & A

怎样定义有效性?

有效性的定义十分重要,如果有效的定义是模糊的,那检查也失去了意义。

对于ABAP Data Validator,如果一个检查类型存在对应的ABAP数据类型(比如日期,时间戳等),那么“有效”是指:

  • 值可以直接被赋值给相应类型的ABAP变量,不产生异常,也不产生无意义的值。

以时间戳为例,

  • 2021-12-21 00:00:00   "无效
  • 19000000235959        "无效
  • 20200101235959        "有效

2021-12-21 00:00:00’\可能在某些情境下是合理的时间戳值,但是对于ABAP Data Validator而言,它是无效的,因为将它赋值给时间戳类型的变量会导致dump。而'19000000235959'虽然可以被赋值给ABAP时间戳变量,但因为没有实际意义,它同样是无效值。

这种类型检查的逻辑主要由SAP提供的标准功能实现,时间戳的检查实际上由正则检查、标准函数DATE_CHECK_PLAUSIBILITY和TIME_CHECK_PLAUSIBILITY组成。

如果一个检查类型没有对应的ABAP数据类型,ABAP Data Validator的检查逻辑收集自一些相对权威的来源,这些检查逻辑通常会符合行业标准。来源包括,

ABAP Data Validator的检查结果可靠吗?

绝大部分检查逻辑是成熟的,且它们都包含单元测试。你可以在单元测试中加上自己的用例来验证它们的行为是否符合你的期望。

HTML检查是个例外,它是唯一一个需要调用外部API(https://validator.w3.org/)的检查,而且w3.org提供的API本身也只是实验性的。请只把它的检查结果当作参考。

目前,我已经在工作中部分地应用了ABAP Data Validator,看起来工作良好。

为什么是多个类,而不是一个类、多个方法?

一个很自然的问题是为什么不把这些检查功能放到一个类里面?毕竟,有时候为了几行代码的检查逻辑创建一个新类太过奢侈。
如果将所有检查放在同一个类里面,将会有一些好处,
  • 减少了全局类数量,方便记忆/不易产生命名冲突。
  • 方法定义更灵活,不需要接受接口ZIF_ADV_CHECK的限制。
但是也会带来一些损失,
  • 不同类型的检查之间的耦合度增加,部署单个方法的更新时,可能会导致更多的LOAD_ PROGRAM CLASS_ MISMATCH异常。
  • 不同开发者的ABAP服务器可能环境不同,如果个别方法不可用,问题将波及整个类,导致其它检查也不可用。
  • 失去了接口接口ZIF_ADV_CHECK的约束后,动态编程会变得复杂,也难以保持检查规则的简单性。

总之,经过一番权衡之后我选择了当前的设计,尽管它也存在某些缺点,如果你有更好的想法,请告诉我。

 

使用ABAP Data Validator验证数据有效性的更多相关文章

  1. jQuery.validator 验证规则详解

    前言:jQuery.validator是一款非常不错的表单验证插件,验证方式非常简单方便,它还对HTML5做了兼容处理,了解了验证规则,就基本掌握了它的使用,下面就让我一一道来 jQuery.vali ...

  2. Validator验证Ajax提交表单的方法

    Validator验证Ajax提交表单的方法 转自:http://hunanpengdake.iteye.com/blog/1671360 当我们在一些稍微复杂的业务时,可能会遇到需要多个表单form ...

  3. Laravel validate 500异常 添加手机验证,中文验证与Validator验证的“半个”生命周期

    今天来讲一下,Lumen的Validator函数 1 2 3 4 5 6 7 8 9 10 11 use Validator;   ...   Class .. {   public function ...

  4. vue学习记录:vue引入,validator验证,数据信息,vuex数据共享

    最近在学习vue,关于学习过程中所遇到的问题进行记录,包含vue引入,validator验证,数据信息,vuex数据共享,传值问题记录 1.vue 引入vue vue的大致形式如下: <temp ...

  5. Lumen开发:添加手机验证,中文验证与Validator验证的“半个”生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 添加手机验证方法可直接看这里:https://www.cnblogs.com/cxscode/p/9609828.html 今天来讲一下,Lume ...

  6. laravel拓展validator验证

    https://blog.csdn.net/zl20117/article/details/53536520 首先,扩展的收个问题是,我的扩展类应该放在哪儿才好呢? 直接在app目录下,建立一个目录: ...

  7. //解决validator验证插件多个name相同只验证第一的问题

    //解决validator验证插件多个name相同只验证第一的问题 var validatorName = function () { if ($.validator) { $.validator.p ...

  8. Validator验证框架

    Validator验证框架 系统分析 在设计Validator验证框架时,需要明确以下问题. (1)当用户没有输入数据时,弹出英文提示信息. (2)当用户输入的数据长度大于系统设置的数据长度,弹出英文 ...

  9. Converter(转换器)与Formatter(格式化) ,Validator(验证器)

    Converter(转换器)与Formatter(格式化)都可以用于将一种对象类型转换为另一种对象类型.Converter是通用元件,可以在应用程序的任意层中使用,而Fotermatter这是专门为W ...

随机推荐

  1. js基础——function类型

    1.函数声明方式 1)普通声明方式  function box(num1,num2){       return num1 + num2;  } 2)使用变量初始化函数 var box = funct ...

  2. SELECT command denied to user ''@'%' for column 'xxx_id' in table 'users_xxx' 权限问题

    问题的原因是:最主要是权限的问题. 大概说下 ,我导数据库时提示错误:SELECT command denied to user ''@'%' for column 'xxx_id' in table ...

  3. linux 使用 gdb

    gdb 对于看系统内部是非常有用. 在这个级别精通调试器的使用要求对 gdb 命令有信心, 需要理解目标平台的汇编代码, 以及对应源码和优化的汇编码的能力. 调试器必须把内核作为一个应用程序来调用. ...

  4. css3动画@keyframes示例

    .active { animation: chuiziza 0.5s ease 1 forwards; } .feijindan { display: block; animation: fei 2s ...

  5. ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(13)之会员登录注册

    源码下载地址:http://www.yealuo.com/Sccnn/Detail?KeyValue=c891ffae-7441-4afb-9a75-c5fe000e3d1c 会员中心,是我们与用户交 ...

  6. vue-learning:38 - router - 前端路由的发展

    前端路由的发展 参考博客 前端路由是什么东西? 什么是路由 在jQuery时代,我们使用<a href="https://www.example.com/example/home.ht ...

  7. vue中的时间修饰符stop,self

    stop阻止自身以外的冒泡 self只会阻止自身冒泡

  8. PowerShell 通过 WMI 获取系统服务

    本文告诉大家如何通过 WMI 获取系统服务 通过 Win32_Service 可以获取系统启动的服务 Get-WmiObject Win32_Service | Format-List Caption ...

  9. 洛谷——P1012拼数字符串操作(拼接排序)

    #include<bits/stdc++.h> using namespace std; bool cmp(const string &a,const string &b) ...

  10. 【20.51%】【codeforces 610D】Vika and Segments

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...