文章目录
- ABAP 增强篇
- 第一代增强-基于源码增强
- 用户出口子程序所能使用的数据变量
- VA01增强示例
- 第二代:基于函数出口增强(FUNCTION)
- SMOD与COMD
- 查找出口函数
- 出口对象激活(SMOD)
- 增强详细说明文档
- 示例:通过出口实现采购订单屏幕增强
- 示例:VA01增强(CMOD创建项目)
- 利用系统函数寻找增强
- 第三代:基于类的增强(BADI)
- BADI的查找方法:
- 创建自定义BADI(SE18)
- 第四代:Enhancement-Point
- 显示增强
- 代码
- 运行结果
- 运行结果
- 代码
- 隐式增强
- 写在最后
ABAP 增强篇
第一代增强-基于源码增强
基于源码的增强就是对SAP所预留的空的子过程进行编码,即对标准程序预留的空的FORM进行编码
这类增强都需要修改sap的标准代码,它们在发布的时候都是空的,这些Form集中存储在一些文件名倒数第二个字符为Z的包含程序中(如后面销售凭证出口文档载图中的MV45ATZZ、MV45AOZZ等Include文件)。
这种Form源代码增强和屏幕增强的说明可以从事务码spro后台配置中相关模块的路径里面找到;这些Form的名称一般是以UserExit_ 打头的子模块,所以一般找到所要增强的主程序,再查找UserExit_关键字即可找到相关的出口。
Form源代码增强事先要到 service marketplace 申请对象键(ACCESS KEY),然后才能修改这些子程序,不过可以隐藏增强来实现,这样就不需要修改源代码
用户出口子程序所能使用的数据变量
以MV45AFZZ为例,其主要功能包括销售订单的创建、检查及保存,VBAP、VBAK表的数据在内存中分别是放在内表XVBAP、XVBAK中
查找出口中能使用到哪些内表变量是开发的关键,可以通过SE38查找对应的出口Include文件在哪里使用过:
SAP程序规范是一般会把不同功能代码封闭在不同的Include文件,如是变量定义一般存放于以 TOP 结尾的Include文件中,如上面为 MV45ATOP,在这里面可以找到想要的数据变量。
定义一个结构体变量,定义内表和工作区
DATA: BEGIN OF gs_mchadat,
mandt TYPE MANDT,
posnr TYPE POSNR_VA,
matnr TYPE MATNR,
werks TYPE WERKS_D,
charg TYPE CHARG_D,
xpcbt TYPE MILL_XPCBT,
dpcbt TYPE mill_dpcbt,
END OF gs_mchadat.
DATA: gt_mchadat LIKE gs_mchadat OCCURS 0 WITH HEADER LINE.
VA01增强示例
在以TOP结尾的Include定义的变量及内表数据都可以在用户出口子程序中直接引用,系统执行中的一些业务数据会被暂存在某些内表中供出口程序判断和使用。
根据出口From名称,可以初步判断其调用过程,如子程序USEREXIT_SAVE_DOCUMENT_PREPARE则会在订单维护程序(VA01、VA02)保存前调用。
这里增加一个保存之前验证的逻辑:保存销售订单时,若订单类型为 ZDZ1(用户自定义电子商务订单类型),要求必须填入订单编号,否则不能保存。
通过F1键查找屏幕字段技术信息,订单类型为 VBAK-AUART,采购订单编号在屏幕中的字段名为 VBKD-BSTKD,这两个技术字段直接可以在用户出口中引用:
第二代:基于函数出口增强(FUNCTION)
源代码的增强是以函数模块的形式发布的,所有增加的代码是增加到指定的函数里,具有特定的输入/输出参数。每个出口函数都会与一个出口对象相对应,要使用这个函数,则需要找到对应的出口对象,并激活它才能生效。
第二代增强(基于函数模块的增强),用SMOD和CMOD维护,在SAP发布的版本中,使用 CALL CUSTOMER-FUNCTION ‘XXX’调用函数模块的,可以在程序中查找customer-function来查找第二代增强,第二代增强函数名构成:exit_程序名_‘xxx(3数字)’,在修改的时候不用像第一代增强一样需要ACCESS KEY,直接双击回车即可,但是不能像第一代增强一样使用程序的全局数据,只能使用接口传递进来的参数。
屏幕的增强也是包含在函数模块所属的函数组中。
针对数据表的增强出口是“CL_”开头的结构,这些结构将.INCLUDE 结构的形式包含到时相应的数据表中,用户可以通过向这些结构中添加字段从而达到对数据表字段的增加 (但标准表是不让用户直接通过Include方式来扩充表结构的,除了这预留的扩展结构)
上面的增强可以通过SMOD进行维护,CMOD进行实现。SMOD中的一个增强可以包含上面的源代码、屏幕和表结构的增强。
第二代增强中主要有4类:
® E类 Ehancement exits:函数增强,就是常说的User_exit(用户出口函数)。这些出口函数以EXIT开头,你可以到SE37去查看,也可以在数据字典中TFDIR(函数表)去查询EXIT_开头的函数
® C类,GUI codes(GUI增强)
® S类,Subsreens(屏幕增强):比如,在创建采购订单、工单等主数据时,系统预留了屏幕增强,也就是可以自定义用户输入界面并编写相应的输入输出处理程序
® T类. include structure增强:比如增强 MM06E005 允许用户建立两个结构 CI_EKKODB 和 CI_EKPODB
Enhancement在MODSAP表(增强点与函数关系对应表)中可查到,而TFDIR表中字段 MAND的值为C时才表示此出口函数被激活了。当然可使用SMOD(CMOD)来激活exit function,但有时候一时难以查询到相关Enhancement时就无法使用SMOD(CMOD)来激活,则可使用下面程序将出口函数激活:
* 将EXIT_SAPMM06E_013换成实际所需exit函数名
UPDATE tfdir SET mand = 'C'.
where funcname = 'EXIT_SAPMM06E_013'.
Enhancement比较重要的表MODSAP,比较重要的字段有这个表里重要的字段有增强名(Name,即出口对象名),组件类型(TYP: E/C/S/T),组件功能模块名(Member):里面记录了所有enhancement的增强。
SMOD与COMD
SMOD是查看某个出口,而CMOD是与项目有关的,如果要通过CMOD去查看某个出口情况,需要先知道这个出口在被哪个项目使用了,才可以通过项目名进去查看,一个出口只能被一个项目使用,如果某个出口还没有被使用,需要先通过CMOD创建项目,在这个项目中引用这个出口即可。
查找出口函数
出口对象激活(SMOD)
增强详细说明文档
示例:通过出口实现采购订单屏幕增强
示例:VA01增强(CMOD创建项目)
利用系统函数寻找增强
第三代:基于类的增强(BADI)
BADI:Business Add-In
主要技术是基于ABAP对象来实现增强。
BADI维护是通过SE18、SE19事务来来维护的。SE18用于创建及维护BADI对象;SE19用于维护BADI的实例,即实现
SAP的BADI不但可以实现对标准系统的增强,也可以直接在自定义程序中进行调用
源代码增强以接口形式发布
第三代增强(基于面向对象概念的增强 BADI(business add-in)), 源代码发布以接口的方式,通过接口的方法调用来实现使用的。用户增强实际上是实现一个或多个基于这个接口的实现类,因为接口类实际上是一个抽象类,所以对同一个增强会出现不同的源代码,这些不同的源代码是通过过滤器(adapter)来区别用于不同的业务场景的。这种增强是用SE18、SE19来实现的。
BADI的查找方法:
1、BADI对象的信息存储在SXS_INTER,SXC_EXIT,SXC_CLASS和SXC_ATTR这四个表中。
2、主程序都会调用cl_exithandler=>get_instance来判断对象是否存在,并返回实例。我们可以打开类编辑器se24中,输入类CL_EXITHANDLER,并进入get_instance方法,设置断点,运行一个tcode,看一下exit_name的值,这就是要找的BADI。
3、se37 查看SXV_GET_CLIF_BY_NAME,设置断点,查看name的值。
4、它的调用方式是call method(instance), 可以通过exit_handler关键词来查找。
5、ST05:
1) 选择SQL trace、buffer trace,然后activate trace ,运行TCODE ,deactivate trace
2) display trace,显示display trace的对话框,在表的栏位上加上? V_EXT_IMP和 V_EXT_ACT
3) 查看以IF_EX_开头的字符串,这是interface class 的名字,IF_EX_后面的就是BADI。例如IF_EX_EQUI_UPDATE
6、se18 查找接口,se19 实现接口就可以实现用户增强
BADI的查找方法:
1、主程序都会调用cl_exitHandler=>get_instance(这只是经典BADI是这样来调用的,如果是新式的BADI,则调用为GET BADI handle-BADI定义名、CALL BADI handle->method)来判断对象是否存在,并返回实例。我们可以在se24中对类cl_exitHandler=>get_instance方法进行调试,运行一个tcode,看一下exit_name的值,这就是要找的BADI
2、在主程序中搜索cl_exitHandler,查看它所引用(TYPE REF TO)的接口名,根据接口命名规则 IF_EX_,得到命称
3、通过程序查找
创建自定义BADI(SE18)
首先需要创建一个自定义的BADI增强点(Enhancement Spot)对象
&---------------------------------------------------------------------*
*& Report Z_TEST_BADI_LHY
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT Z_TEST_BADI_LHY.
DATA: badi1 TYPE REF TO ZBADI_DEMO01_IF01,
badi2 TYPE REF TO zbadi_demo01_cl.
DATA: instr TYPE string,
outstr TYPE string.
START-OF-SELECTION.
CREATE OBJECT badi2.
badi1 = badi2.
instr = 'ABCDEFG'.
CALL METHOD badi1->print
EXPORTING
input = instr
IMPORTING
output = outstr.
WRITE: outstr.
"使用第二种方法
PARAMETERS: filter(2) TYPE c.
DATA: handle TYPE REF TO ZBADI_DEMO01,
instr TYPE string,
outstr TYPE string.
GET BADI handle
FILTERS "SE18定义的过滤器名作为这里的参数名
CARRID = 'LH'.
instr = 'ABCDEFG'.
CALL BADI handle->print
EXPORTING
input = instr
IMPORTING
output = outstr.
WRITE: outstr.
第四代:Enhancement-Point
第四代其实是第三代的加强switch Framework
当sap进入newweaver 7.0以后推出的新增强体系,将BADI进行了改进,叫新BADI了。还新增Enhancement Spot 和 Enhancement Section 以及隐式增强点的概念,基本可以在面向对象的程序里实现处处皆可增强的最高境界。
此种不建议使用,只有无法通过 User Exit与BADI都无法实现时,才考虑这个
Enhancement Spot是对Enhancement的一个管理平台,Enhancement-Point技术与BADI是有区别的,首先BADI是SAP预留的类的接口,而Enhancement-Point则是允许用户对现有的SAP代码进行修改,例如插入、替换,只要符合一定的规则即可,不需要SAP预先定义好
一般增强步骤:
-
DEBUG标准程序找到需要增强的位置,点EDIT->SHOW IMPLICIT ENHANCEMENT OPTIONS查看是否有预留增强选项。(标准程序不能自己创建enhancement option ,只能使用系统预留的)
-
创建增强点实现
显示增强
代码
*&---------------------------------------------------------------------*
*& Report Z_TEST_ENHANCEMANT_LHY
*&
*&---------------------------------------------------------------------*
*& Description:测试增强
*&
*&---------------------------------------------------------------------*
REPORT Z_TEST_ENHANCEMANT_LHY.
WRITE : /,'This is enhancement test!'.
ENHANCEMENT-POINT ZTEST_EN_POINT_01 SPOTS ZTEST_EN_POINT_01 .
*$*$-Start: ZTEST_EN_POINT_01-------------------------------------------------------------------$*$*
ENHANCEMENT 1 ZTEST_POINT01_IMP. "active version
WRITE:/,'ZTEST_EN_POINT_01增强点的实施输出测试'.
ENDENHANCEMENT.
*$*$-End: ZTEST_EN_POINT_01-------------------------------------------------------------------$*$*
运行结果
对于ENHANCEMENT-SECTION,定义和实现的方法与ENHANCEMENT-POINT一样。两者的区别是:enhancement-point没有代码,只有一个预留点,允许在这个位置插入新代码(implementation),而nhancement-section和end-enhancement-section.之间有代码,implementation之后,替换旧代码,只执行新代码,原来的代码不再执行
运行结果
代码
&---------------------------------------------------------------------*
*& Report Z_TEST_ENHANCEMANT_LHY
*&
*&---------------------------------------------------------------------*
*& Description:测试增强
*&
*&---------------------------------------------------------------------*
REPORT Z_TEST_ENHANCEMANT_LHY.
WRITE : /,'This is enhancement test!'.
ENHANCEMENT-SECTION ZTEST_EN_SECTION_01 SPOTS ZTEST_EN_SECTION_01 .
WRITE:/,'ZTEST_EN_SECTION_01'.
END-ENHANCEMENT-SECTION.
*$*$-Start: ZTEST_EN_SECTION_01-----------------------------------------------------------------$*$*
ENHANCEMENT 1 ZTEST_SECTION01_IMP. "active version
WRITE:/,'ZTEST_EN_SECTION_01 的实施1: ZTEST_SECTION01_IMP '.
ENDENHANCEMENT.
ENHANCEMENT 2 ZTEST_SECTION01_IMP2. "active version
WRITE:/,'ZTEST_EN_SECTION_01的实施2: ZTEST_SECTION01_IMP '.
ENDENHANCEMENT.
*$*$-End: ZTEST_EN_SECTION_01-----------------------------------------------------------------$*$*
ENHANCEMENT-POINT ZTEST_EN_POINT_01 SPOTS ZTEST_EN_POINT_01 .
*$*$-Start: ZTEST_EN_POINT_01-------------------------------------------------------------------$*$*
ENHANCEMENT 1 ZTEST_POINT01_IMP. "active version
WRITE:/,'ZTEST_EN_POINT_01增强点的实施输出测试'.
ENDENHANCEMENT.
*$*$-End: ZTEST_EN_POINT_01-------------------------------------------------------------------$*$*
隐式增强
写在最后
感谢江正军大佬的文章,文章参考链接:https://www.cnblogs.com/jiangzhengjun/p/4265513.html#_Toc410467152