做过的增强不多,之前做过一次用户登陆增强而已,增强点都是找好的,基本上就是照着文档一步步实现。早就看过很多增强的相关文档,每次都是零零星星的看看,再加上增强的需求做得少,导致很多东西仅仅停在知道的层面,打算明年年初换项目,最近也在忙着面试,增强又是面试问的比较多的知识点,于是打算系统的总结下!
注:本文参考sap师太博客,在此感谢师太的博客,知识在于分享!
开发人员所说的增强主要是标准系统事先预留好的接口,根据不同业务需求来进行开发,称为增强,又叫出口(EXIT)。随着SAP ABAP的迭代,一共推出了四代增强(ABAP貌似好多年没更新迭代了)。
- 第一代:基于源代码的增强
- 第二代:基于出口函数的增强
- 第三代:基于类的增强
- 第四代:基于增强点的增强
第一代增强基于源代码,是SAP系统提供一个空代码的子过程(subroutine:From)。在这个子过程中用户可以添加自己的代码,控制自己的需求。这类增强都需要修改SAP标准代码,它们发布时都是空的,集中在一些文件名倒数第二个字符为Z的包含程序中。由于是在标准程序中,所以所有程序的全局数据都可以使用,但同时系统升级时会被新版本覆盖。
这种源代码增强和屏幕增强的说明可以从事务码SPRO后台配置中相关模块的路径中找到:一般是以UserExit_开头的子模块,可形象的称其为用户出口
Form源代码增强事先要到 service marketplace 申请对象键(ACCESS KEY),然后才能修改这些子程序,不过可以隐藏增强来实现,这样就不需要直接修改源代码了
第二代增强(基于函数模块的增强)用事务SAP增强管理(事务代码:SMOD)和增强编译器(事务代码:CMOD)维护。在SAP发布的版本中(如VA01对应的程序SAPMV45A的源代码中),使用Call Customer-Function ‘XXX’ 调用函数模块,所以可以通过在程序中搜索Customer-Function来查找第二代增强,第二代增强函数名构成为Exit_程序名_xxx_ (3 digital number)。它们在发布的版本中只有一句代码 include “zxxxxxx”.
针对数据表的增强出口是 “CI_ ”打头的结构,这些结构将.INCLUDE 结构的形式包含到时相应的数据表中,用户可以通过向这些结构中添加字段从而达到对数据表字段的增加
第二代增强只能使用接口中传递进来的参数,不能像第一代增强一样随便使用全局数据。
由于带有关键字Customer,故被称为Customer Exits(客户出口)
T. Include structure (表结构增强): 用于表结构的增强
其中函数增强最常用,在SAP上线很多年后都会使用,如:销售单VA02中,对PO长度限制在10-15位之间,且不能为中文与其他特殊字符,还有如对PO采购日期不能晚于交货日期的检验等,这些都会用来函数增强;
屏幕增强不常用,一般在上线初才会使用,上线后不常用;屏幕增强调用使用CALL CUSTOMER-SUBSCREEN
MODSAP:表中重要的字段增强名(Name)、组件类型(TYPE:ECST)、组件功能模块名(Member)里记录了所有Enhancement的增强
TFDIR:所有的函数表、重要字段FuncName(函数名)、功能模块激活状态MAND如果是C,代表此函数模块激活)
TSDIR:动态程序区 CALL CUSTOMER SUBSCREEN(屏幕增强)
CUATEXTS:修改GUI界面,菜单文本被客户改变(GUI才单文本增强)
MODSAPA:SAP扩展的属性
TADIR:资源库对象的目录
TFTIT:函数功能的短文本
代码查找增强
利用系统函数查找增强
常与出口相关的函数有:
MODX_SUBSCREEN_ACTIVE_CHECK(屏幕增强)
可以在函数最后设置断点,然后通过运行对应的增强程序就会调用这样的函数,这样就可以在调试模式下找到对应的增强
eg:去se80,在function-Module中搜索MODX_FUNCTION_ACTIVE_CHECK,在程序中打断点,如图:
然后运行需要增强的事务码,如果有增强会自动跳转到debug界面,双击查看l_funcname变量可以看到需要的增强出口函数
然后根据这个出口函数去MODSAP表中查询增强对象
找到出口增强对象
接着去SMOD输入增强对象后单击测试(F8)查看有哪些增强
从上面图中可以看到增强MM06E005包含功能出口、屏幕出口、表出口三种增强。在SMOD界面双击后面对应的增强名可以进行增强功能的实现。
SMOD包含具体的增强,而CMOD是包含一组SMOD编写的增强.
思路:确定增强出口函数,找到对应的增强对象,CMOD/SMOD
基于类的增强。主要技术是基于ABAP对象来实现增强。BADI维护是通过SE18、SE19事务来来维护的。SE18用于创建及维护BADI对象;SE19用于维护BADI的实例,即实现.SAP的BADI不但可以实现对标准系统的增强,也可以直接在自定义程序中进行调用
BADI与BTE。
BADI是基于ABAP的面向对象技术,可以被插入到SAP系统中,以适应用户由于行业的不同需要不同的功能以满足具体要求。
基于面对对象概念的增强BADI(Business Add-in),源代码的发布是通过接口的方法调用来实现使用的。用户增强实际上是实现一个或多个基于这个接口的实现类,因为接口类实际上是一个抽象类,所以对同一个增强会出现不同的源代码,这些不同的源代码是通过过滤器(Adapter)来区别用于不同的业务场景,这种增强通过SE18和SE19来实现。
SAP预定义了一些接口(Interface),客户可以自行定义实现Interface的类(Class),在标准程序中会使用调用客户自定义类(Class)的实例(Instance),获取实例的过程使用了工厂模式,因此获取过程对用户是未知的。不过BADI也有一些局限性,就是有一些Interface是固定的,有时候会发现需要Mix客户化代码的时候找不到Interface
业务交易事件(BTE, Business Transaction Events)是SAP的一种增强方式,技术上讲介于第二代增强和BADIS之间的产物,BTE为会计模块独有的增强,这种增强用于财务会计模块(Open FI)、总账会计(FI-GL)、应收账款和应付账款(FI-AR/FI-AP)及销售和分销(SD)的组件
BADI的查找方法:
BADI对象的信息存储在SXS_INTER,SXC_EXIT,SXC_CLASS和SXC_ATTR这四个表中。
主程序都会调用cl_exithandler=>get_instance来判断对象是否存在,并返回实例。我们可以打开类编辑器se24中,输入类CL_EXITHANDLER,并进入get_instance方法,设置断点,运行一个tcode,看一下exit_name的值,这就是要找的BADI。
se37 查看SXV_GET_CLIF_BY_NAME,设置断点,查看name的值。
它的调用方式是call method(instance), 可以通过exit_handler关键词来查找。
BADI使用方法:
BADI Definition是通过SE18->Utilities->Create Classic BAdi,实现BAdi是通过SE19;
在属性界面勾选多次使用(Multiple Use)只显示两个标签页,不勾选有四个标签页
一个badi包含着enhancement components,其主要包含下面几种components:
- Program enhancements:program enhancements是通过interface methods来实现的,SAP程序来调取生成的badi class的interface methods。对应界面标签页(interface)
- Menu enhancements:同customer exit一样,可以在badi中维护function code。这些menu entry在GUI definition中已经定义就可以在implemented badi看见。对应功能码标签页(Fcode)
- Screen enhancements:同customer exit一样你可以在badi中维护screen enhancements。对应子屏幕标签页(SUBSCREEN)
双击创建接口,并添加方法和参数
创建实现 Implementation->Create
在程序中调用badi,直接使用cl_exithandler=>get_instance
eg:
DATA: out TYPE string.
DATA: l_badi_instance TYPE REF TO zif_ex__badidef_baditest2.“zif_ex__badidef_baditest2是BAdi Definition的Interface name
CALL METHOD cl_exithandler=>get_instance
CHANGING
instance = l_badi_instance.
IF l_badi_instance IS NOT INITIAL.
CALL METHOD l_badi_instance->test
EXPORTING
in = 'hello'
CHANGING
out = out.
WRITE: / out.
ENDIF.
其实是第三代的加强switch Framework;
当sap进入newweaver 7.0以后推出的新增强体系,将BADI进行了改进,叫新BADI了。还新增Enhancement Spot 和 Enhancement Section 以及隐式增强点的概念,基本可以在面向对象的程序里实现处处皆可增强的最高境界。
BADI使用方法(新式):
1. SE18创建一个自定义的BADI增强点(Enhancement Spot)对象
确定后进入 Enhancement Implementation 页面
双击实施类进行编辑
双击方法创建实施
使用GET BADI语句
parameters: filter(2) type c.
DATA: handle TYPE REF TO z_badi_calc_vat,"z_badi_calc_vat为BADI定义,不是接口也不是类
sum TYPE p,
vat TYPE p,
percent TYPE p.
sum = 50.
GET BADI handle
FILTERS"SE18中定义的过滤器名作为这里的参数名
filter1 = 'C'.
CALL BADI handle->get_vat
EXPORTING
im_amount = sum
IMPORTING
ex_amount_vat = vat
ex_percent_vat = percent.
当BADI的某个实现版本有多个实现类时,这时在调用时如果想要调用指定的类,则需添加过滤器参数,该参数实质上由其代理类来使用,在运行时代理类会去实例化所对应的类。
加上该选项后,接口与实现类中的所有方法都会自动的加上一个必输参数:FLT_VAL
DATA: out TYPE string.
DATA: l_badi_instance TYPE REF TO zif_ex__badidef_baditest2.
CALL METHOD cl_exithandler=>get_instance
CHANGING
instance = l_badi_instance.
IF l_badi_instance IS NOT INITIAL.
CALL METHOD l_badi_instance->test
EXPORTING
"flt_val参数是由l_badi_instance实例来使用的,从这里可以推断
"l_badi_instance应该属于代理对象,由它在运行时根据过滤器值
"来选择性的调用相应实现类的方法
flt_val = '800'
in = 'hello'
CHANGING
out = out.
WRITE: / out.
ENDIF.
Filter type扩展性局限于以下几个方面:
- Filter type参考的domain必须符合下面的几个条件:
- Domain要指向cross client value table。这个value table只有一个使用的data element的domain是这个domain的key field。
- Domain有一个两个key field的text table,一个key field使用的是这个domain本身,另一个key field是language field。其必须还得有一个text field,这个text field的类型为TEXT或TXT。在ABAP DICTIONARY中必须给text field指定一个value table。
- 这两个table的delivery class必须是E或S
如果badi被激活,当调用程序执行时,相应的implementation methods也会被执行。一旦diactivate这个implementation,相应的方法就不会被调用。然而应用程序中的相关调用仍然会被执行。不同的是adapter class的instance不会找到激活的implementations。并不像CALL CUSTOMER-FUNCTION,CALL METHOD CL_EXITHANDLER=>GET_INSTANCE即使没用implementations,仍然会被调用。只有在original system(开发系统)中才可以activate或deactivate implementations,而subsequent systems则只能transport。如果badi只能有一个implementation,那么系统中仍然可以存在这个badi的多个implementation,只不过只能有一个激活版本。
同customer exit一样badi中也有menu enhancements。但是必须满足以下两个条件:1,必须预留了menu enhancement。2,必须在Badi的implementation中实现。Menu enhancements的function codes必须以+开始。如果相应的enhancement的badi implementation被激活,那么menu就会显示出来。你只能为single use badi创建function code,而且badi不能是filter dependent。这样就保证了一个或多个的badi不出现矛盾。如果用户在程序中选择了相应的以+开始的function code,那么系统就会调用相应的method。Method call和Menu enhancement是不可分离的,它们只能属于同一个badi。
通过badi builder SE18来创建badi。Badi有两个重要的属性,Reusable和filter-dependent。如果想让你的badi支持多个激活的implementation那么就要选择reusable。不过implementations的执行顺序不能被定义。即使badi本身不支持mulitiple use也可以同时存在多个implementations,只不过只能有一个激活的implementation。Badi如果filter dependent的,这样就可以设置调用的条件。Filter type必须是data element或者ABAP dictionary structure。Data element使用的domain的value table包含了implementation所需要的valid values。如果filter type使用的是structure,那么这适用于structure的每个字段。当调用enhancement method时,filter value必须传给interface。Badi中可以包含function code,需要输入program name,function code以及short description。局限性是不能够创建只包含function code的badi,menu enhancement既不能filter dependent也不能reusable。
系统提供了badi的interface和生成class的name。理论上可以将这些name改成任何你喜欢的name,但是保留系统推荐的name会使badi更加容易理解。生成的class的name遵循以下规则:namespace prefix(Z/Y) + CL_ + EX_(代表 exit) + badi name。双击interface name就会进入class builder,就可以定义interface method。一个badi indterface可以有多个interface method。Class bulder的所有功能都可以使用,如定义interface method,定义method的interface parameters以及声明interface的attributes等。如果badi是filter dependent的,必须给他的每个method定义一个import parameter flt_val(具体怎么做请参着这里)。一旦完成了interface的定义就要激活它。一旦修改了interface,badi class也会重新生成。也可以在badi维护事务中通过utilities->Regenerate来重新生成adapter class。Badi在程序中的调用过程:首先声明一个badi interface的reference variable。调用service class CL_EXITHANDLER的static method GET_INSTANCE。这个method返回required object的instance。这里属于narrow cast(窄化),所以通过这个variable只能调用interface methods。然后你就可以调用badi的方法了