【BAdI】Definition&Using SAP New BAdI
1, T-CODE:SE18,进入如下界面,选中 ’ Enhancement Spot’ 并输入所决定的名称.
2, 点击上图中的 ’Create’ 按钮进入下一屏.在下面这个屏幕中输入Short Text,然后选择绿勾按钮.
3,在上一屏,选择绿勾按钮后,出现下面这个屏幕,输入合适的package,可以使用本地对象这个package,然后点左下角的保存按钮.
4,在上一屏保存之后出现下面的界面.选择 ‘Enh. Spot Element Definitions’ 这个页签(这个是进入后的默认页签),点击该页签左上角的 ‘Create BAdI’ 按钮,进入下一屏.
5,在如下屏幕中输入 BAdI Definition的name和Short Description. 然后选择绿勾按钮
选择multiple use,这样对同一个接口可以存在多份实现。
6,在上一屏选择绿勾后,在界面左边部分,找到Z_BADI_SAY字样,然后点开,双击Interface,然后在屏幕右边部分找到Interface字段,并填上自己决定的名称.最后点击保存.
7, 在上一屏中点击保存后出现如下对话框,选择Yes创建object.
8,创建object时,同样需要选择合适的package,这里仍然选择本地package.如下图所示.
9,在上一屏选择保存按钮之后,出现下面这个对话框,选择yes按钮表示保存.
10,在上一屏选择yes按钮保存之后,系统会跳到如下界面,要求我们给这个BADI定义method方法.这里定义了一个方法,名为say, level选择Instance Method(当然这里也可以选择Static,顾名思义可以不用创建类对象之间调用), 然后在后面的description里面填写上你所需要的描述.根据实际情况,决定是否需要参数. 这里需要一个输入参数,以便测试.所以点击下面这个屏幕的左上中部分的那个Parameters按钮.进入下一屏.
11,在面的参数定义table control中,输入一个参数,名为forsay, 类型type为:importing.选中Pass Value,在Associated type中输入C,表示字符型. 点屏幕左上中部分的Methods按钮返回到方法设置界面.点击屏幕最上方的保存按钮,然后点击激活按钮.
12,在上一屏点击激活按钮后,出现下面的对话框,本次需要激活的对象都已默认选择,直接选择左下角的绿勾按钮确认.
13,到此为止,一个BADI的definition部分就算做完了.直接在上面一步绿勾激活后停留的界面上,在命令区域输入/NSE18, 或者/OSE18打开一个新的对话进程.我们将implementing这个BADI, 维护BADI Implementation.
在如下界面中,选择菜单->Enhancement Implementation->Create.
或者点击两个小人按扭
14, 在上一步选择create之后,出现下面这个对话框,填写上面两个必输field之后,选择绿勾按钮确认.
15,在上一步选择绿勾按钮确认后,出现下面的对话框,选择合适的package以便保存.
16, 在上一步选择保存之后,出现如下对话框, 需要在BAdI Implementation这个列中,填写上我们第14中填写的Enhancement Implementation中值,即z_badi_say_impl. 填写完成后,选择左下角的绿勾按钮确认.
17,在上一步如果正确填写了BAdI Implementation列值后,将会进入如下界面.在这个界面中,选择Enh. Implementation Elements页签,在该页签的左边部分找到并点开Z_BADI_SAY_IMPL,然后双击出现的Implementing Class,直到该页签右边部分出现需要填写的Implementing Class字段,在该字段上填写上名称.
18, 在上一步操作完成后,点击上一屏上的保存按钮,出现下面对话框,选择Y确认创建该object.
19, 在创建时又会出现选择package的对话框,请选择合适的package.这里可以选择本地package.
20, 在上一步进行保存之后,如果一切都正确,则会出现下面的界面.将会出现我们在BADI Definition部分创建的method,在此即z_badi_say_interface~say. 双击该method.
21, 双击方法method时,出现下面这个确认对话框,选择Yes进行创建create.
22,在上一步选择Yes进行创建后,将会进入下面这个屏幕.如果不是在编辑状况,请点击左上角的Display<->Change按钮,切换到编辑状态.
23, 在编辑状态下,输入需要的codes.这里很简单,只是将在BADI Definition中定义的形参forsay给popup出来.
24, 上一步中输入的简单代码如下:
CALL FUNCTION 'POPUP_TO_DISPLAY_TEXT'
EXPORTING
textline1 = forsay.
25,校验代码没有问题后,保存并激活.在点激活时出现如下界面,将所有项都选择后,点绿勾确认按钮.
26,以上完成了BADI的definition和implementation.下面创建一个非常简单的report进行测试.
REPORT Z_TEMP.
DATA: EXIT_SAY TYPE REF TO Z_BADI_SAY_IMPL_CLS,
EXIT_SAY_INS TYPE REF TO Z_BADI_SAY_INTERFACE.
WRITE: 'CLICK ME' HOTSPOT.
AT LINE-SELECTION.
CREATE OBJECT EXIT_SAY.
EXIT_SAY_INS = EXIT_SAY.
CALL METHOD EXIT_SAY_INS->SAY
EXPORTING
FORSAY = 'Hi you'.
27,总结.以后,在不改动上面这个简单的report的情况下,我们通过更改这个report所对应的BADI的say方法,就可以让这个report作出不同的效果.就比如SAP标准程序中有Call method的地方,并且对应BADI的话,我们可以不改动程序,通过应用BADI,实现程序的额外功能.
28.重复13的动作可以创建多个实现
29. 对于classic BAdI可以用以下代码获取执行,(对于New BAdI会报出DATA_INCONS_IN_EXIT_MANAGEM 的Error信息)
*get badi implementation class by interface name
CALL METHOD CL_EXITHANdLER=>GET_INSTANCE
CHANGING
INSTANCE = LR_EXIT.
CALL METHOD LR_EXIT->lgort_check
EXPORTING
LGORT = wa_lgort.
(这种方式只能应用于Classic BAdI,)
30. ECC6.0以后的版本,对于New BAdI要用Get BADI/CALL BADI语法搞定
DATA bd TYPE REF TO Z_BADI_CHECK.
GET BADI bd .
CALL BADI bd->LGORT_CHECK exporting lgort = wa_lgort.
(说明:其中LGORT_CHECK 是BAdI中的Method,系统会自动找到每个implementation 里的代码并执行,当然Method的parameters一定要和Interface定义的一致)
30. 其它一些关于自定义BAdI的文章
以下链接转载自 http://scnblogs.techweb.com.cn/abaplv/archives/tag/badi
Class是object的抽象描述,object只是在程序运行时才能存在。Object是由class描述的,并包含两个层次,inner layer和outer layer。Object的public component就是这个object的interface。Oo的主要目的就是为了保证object本身状态的consistency。Object的attributes一般是internal的,只能被它的method修改。对于具有相同attributes和methods的object他们也有自己的identity来区分。与OO概念相似的有function group,不同的是function group只能有一个instance,而object可以有任意个instance。
Interface是独立于class之外定义的。.它包含向attributes和methods这样的声明语句。其具体功能是通过class来实现的。这些class应该有统一的与外部联系的方式,并通过实现方法来实现interface的所有功能。在程序中你可以创建interface变量来指向interface,但是你不能instantiate一个interface。Interface变量用来指向不同class的object。
与customer exit不同的是,badi考虑到了软件修改的发布流程。Badi enhancement的实现至少需要一个interface以及相应的class来实现它,interface的实现由用户来完成。这种enhancement的一个优点是它提供了reuse的能力。一旦实现了,badi在软件的发布过程中仍然可以重新实现。Implementation本身也可以提供badi。
一个badi包含着enhancement components,其主要包含下面几种components:
l Program enhancements:program enhancements是通过interface methods来实现的,SAP程序来调取生成的badi class的interface methods。
l Menu enhancements:同customer exit一样,可以在badi中维护function code。这些menu entry在GUI definition中已经定义就可以在implemented badi看见。
l Screen enhancements:同customer exit一样你可以在badi中维护screen enhancements。
创建badi时,几个相关的部件就会被创建:interface和为实现interface而生成的class。生成的class主要实现下面的任务:过滤,如果你实施了一个过滤badi,那么这个class就会保证只有相关的implementation才会被调用。
Badi的执行流程:首先service class CL_EXITHANDLER会创建一个object reference,并产生调用program enhancement method的条件。当你定义BADI时,就会产生一个BADI class,用来implement badi interface。调用时,badi class的interface method就会被调用。Badi会搜索所有的BADI Implementation并调用implemented methods。
Badi在调用程序中的实现源代码如下:
REPORT <program_using_badi>.
DATA: r_var TYPE REF TO <badi-interface>.
START-OF-SELECTION.
CALL METHOD cl_exithandler=>get_instance
CHANGING
Instance = r_var.
CALL METHOD r_var->method
EXPORTING
<i_variables>
IMPORTING
<e_variables>.
END-OF-SELECTION.
首先你必须定义一个指向badi interface的reference variable。这个reference variable的名字不一定要包括badi的名字。第一次调用时一个object reference就会被创建,只用interface的method才会被这个reference object调用。可以通过这个reference object来调用你需要的enhancement中的方法。
可以通过t-code SE19来implement badi。
可以给implement class分配任何的名字,不过最好遵循以下规则:namespace以Y或Z开始,对于class的name以CL开始,implementation的name以IM开始,要implement method只要双击method name即可,系统会自动启动Class Builder editor。一旦完成代码编写,一定要激活它。
如果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 + 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的方法了。示例如下:
DATA: r_var TYPE REF TO <badi-interface>.
START-OF-SELECTION.
CALL METHOD
Cl_exithandler=>get_instance
CHANGING
Instance = r_var.
CALL METHOD r_var-><method>
EXPORTING
<i_variables>
IMPORTING
<e_variables>/
如果使用filter dependent badi,要给参数flt_val传递一个适当的值。
对于ABAP virtual machine,screens和class是不能绑定到一块的。所以只用classical programs(type I,For M)才能作为screen的容器。Badi的screen enhancement也必须考虑到这点。当创建badi screen enhancement时,在应用程序的screen上要保留一块subscreen area。然后implementing program就会填充它。应用程序和subscreen的container program并不直接交换信息,而是通过生成的badi class。如果badi包含screen enhancements那么它就不能是reusable的。在subscreen tab你需要输入calling program,screen number和subscreen area。Implementing program和subscreen number是在implementation过程中指定的。
如果想通过badi实现screen enhancement,在应用程序中要实现以下步骤:
l 生成badi class
l 将badi class instance存入到refernce variable中
l 将数据传递给badi class
l 得到enhancement screen的program name和screen number
l 调用screen
在main screen的PAI,需要调用另外一个method把修改后的数据传回给application program。
实现screen enhancement的几个步骤:
l 首先通过adapter class CL_EXITHANDLER的factory method get_instance来得到生成的badi class的一个instance。并将其存储到一个reference variable中。DATA:EXIT TYPE REF TO <badi-interface>. CALL METHOD cl_exithandler=>get_instance CHANGING instance = exit.
l 然后implementation必须能够access badi instance。也就是说必须把reference variable赋给handler class的一个attribute。然后这个reference variable就会赋给badi class。通过下面的语句来实现这个步骤:CALL MEHTOD cl_exithandler=>set_instance_for_subsdcreens
l 为了使implementation获得数据需要通过两个步骤来实现。首先将data传给badi class,这些数据存储在这个方法的implementation的global attributes中,强烈建议在这个步骤提供sample code。通过badi中定义的mehtod来传递数据。然后存储在badi global attributes中的data就会被自动传到implementation的global attributes中,当然,implementation必须是active状态。使用的语句如下:CALL METHOD exit->put_data EXPORTING <data>.
l 在执行CALL SUBSCREEN语句之前,必须得到subscreen的screen number和program name,这个通过方法cl_exithandler=>get_prog_and_dynp_for_subsc来实现。如果没有active implementation,就会得到dummy function group(SAPLSEXM)的dummy subscreen (screen number 200)。如果存在active implementation,在implementation中指定的subscreen就会被使用。语句如下:CALL METHOD cl_exithandler=>get_prog_and_dynp_for_subscr EXPORTING … IMPORTING called_program = … called_dynpro = ..
l 调用相应的subscreen,如果没有active implementation,就会显示default empty subscreen。
l 如果在离开screen之后向得到Implementation中的data,则需要使用method:CALL METHOD exit->get_data IMPORTING <data>。
Implement badi screen enhancement的步骤如下:
l 创建badi的implementation指定包含subscreen的程序名和screen number
l 创建指定的program
l Layout指定的subscreen
l Implementing program必须得到badi的instance
l 从应用程序传递给badi的数据可以被取得。
l 如果想将修改后的数据返回给application program,需要调用相应的方法。
得到badi class instance的方法是CALL METHOD cl_exithandler=>get_instance_for_subscreens,这个reference是通过方法cl_exithandler=>set_instance_for_subscreen来传递的。这允许你在implementation中访问badi的attributes以及interface methods。Implementing program通过方法:exit->get_data IMPORTING <data>来获取badi中的data。通过方法exit1->put_data EXPORTING <data>将修改后的data传回给badi class的instance。
Filter type扩展性局限于以下几个方面:
l 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
如果没有active implementations,那么由enhancement provider提供的default implementation就会被执行。在badi definition中通过goto->default code就可以创建default implementation。还可以创建一个sample implementation。通过goto->sample code就可以创建。几种增强方法的比较:
Customer Exit
BTE
BADI
Source code
+
+
+
Menus
+
-
+
Screens
+
-
+
Table
+
-
[+]
Administration levels
+
-
+
reusable
-
+
+
Filter specific
-
+
+
BADI DEFINITION中的name conventions
l Badi definition: <badi> or z<badi> or /../<badi>
l Interface:IF_EX_<badi> or ZIF_EX_<badi> or /../IF_EX_<badi>
l Methods:any name
l Generated badi class(adapter class) cl_ex_<badi> or zcl_ex_<badi> or /../cl_ex_<badi>
BADI IMPLEMENTATION中的name conventions
l BADI implementation <impl> or z<impl> or /../<impl>
l Interface: IF_EX_<badi> or ZIF_EX_<badi> or /../IF_EX_<badi>
l Methods:在badi definition中定义
l Implementing class:CL_IM_<impl> ZCL_IM_<impl> /../CL_IM_<impl>
找到badi的方法:
l 在应用程序中搜索CL_EXITHANDLER
l REPOSITORY INFORMATION SYSTEM
l 相关component的IMG