需求分析:
1、具体需求
本《使用功能模块输出雇员信息表》有如下需求:
- 从雇员表中获得雇员信息并按图示输出;
-
根据出生日期和入职日期计算雇员的年龄和工龄,并在列表中输出。
其中列表输出效果如图5-4。
2、开发分析
要达成本实践目标,分析有如下:
- 大部分信息包括雇员ID、姓名、职务等可直接从数据库表中获得及输出,可有多种方式进行处理;
- 年龄和工龄分别是根据出生年月和雇佣日期,以及当前日期进行计算的,而且在此需求中年龄和工龄的计算逻辑假设为一样,都是根据当前年和出生年(雇佣年)的差值算出年龄(工龄),然后再将当前月与出生月(雇佣月)进行比较,如果当前月>出生月(雇佣月),则将根据年算出的年龄(工龄)基础上-1;
- 年龄和工龄可以分开编写代码,而考虑代码的复用性,在此需求中使用功能模块予以实现;同时在功能模块中对输入的日期进行判断,如果大于当前日期,则抛出异常。
实践步骤:
本实践可以在ABAP工作台(SE80)中完成,也可以分别使用函数构建器(SE37)和程序编辑器(SE38)完成;编写的代码将有如下几部分组成,按开发人员风格不同,其组成部分并非强制一致。
No | 部分 | 说明 | TCode |
---|---|---|---|
1 | 功能模块建立 | 通过函数构建器,建立函数组和功能模块,以根据输入日期计算年龄(工龄)。 | SE37 |
2 | 程序声明 | 声明本程序执行后是否包含标准标题,数据输出宽度和每页的行数量为多少,另需考虑页脚输出 | SE38 |
3 | 对象定义 | 通过定义要使用的结构、内表和变量等,以在程序执行过程中计算和存储临时值 | - |
4 | 页眉输出 | 通过代码设置输出页眉 | - |
5 | 获取输出数据 | 从表中获得要输出的数据数据并存储到内表中; 然后遍历内表后调用功能模块计算出年龄和工龄后,输出雇员数据 |
- |
1、功能模块建立
执行TCode:SE37后,将显示初始界面如图,在此界面中可以对函数组(Function Group)和功能模块(Function Module)进行维护。
1)创建函数组
建立功能模块时必须指定函数组,由此对实现对功能模块的分类,以方便管理和维护。
在如上初始界面中,点击“转到-->函数组-->创建组”,将弹出“创建功能组”的界面如图所示,在界面中输入名称和文本后点击对勾保存,由此完成了函数组的建立。
2)创建功能模块
在初始界面输入功能模块名称后,点击创建,将显示如图所示的“创建功能模块”的界面,在此指定函数组和文本后点击保存,则将进入功能模块具体属性定义的界面。
在“属性”页签,保持默认设置不修改,如图。
在“导入”(IMPORT)页签,定义参数名称及相应类型文本,如图,在调用功能模块时会将对应变量的值传入到功能模块的此参数中,以在功能模块的代码中进行处理。
在“导出”(EXPORT)页签,定义参数名称及相应类型文本,如图,在调用此功能模块时将通过此参数输出结果。
不设置“正在更改” “表”页签,在“例外”(EXCEPTIONS)中定义程序执行时抛出的异常,如图所示。
切换到“源代码”页签后,输入代码如下,实现根据输入日期进行年龄的计算和输出。
FUNCTION zu05_get_age.
*"----------------------------------------------------------------------
*"*"本地接口:
*" IMPORTING
*" REFERENCE(IDATE) TYPE DATS
*" EXPORTING
*" REFERENCE(OAGE) TYPE I
*" EXCEPTIONS
*" DATE_NOT_VALID
*" DATE_GT_CURRENT
*"----------------------------------------------------------------------
CALL FUNCTION 'DATE_CHECK_PLAUSIBILITY'
EXPORTING
date = idate "根据输入的idate调用功能模块进行检查
EXCEPTIONS
plausibility_check_failed = 1
OTHERS = 2.
IF sy-subrc NE 0. "如果返回非0,则日期不合法
MESSAGE idate && '是无效日期' TYPE 'W'
RAISING date_not_valid.
ENDIF.
IF idate GT sy-datum. "如果输入日期大于当前日期,则日期不对
MESSAGE idate && '大于当前日期,请检查数据是否正确' TYPE 'W'
RAISING date_gt_current.
ENDIF.
oage = sy-datum+0(4) - idate+0(4). "根据当前年与输入年的差额得到年龄
IF sy-datum+4(2) < idate+4(2). "如果当前月小于输入月,得到的年龄需-1
oage = oage - 1.
ENDIF.
ENDFUNCTION.
在此功能模块中,调用了另一个功能模块“DATE_CHECK_PLAUSIBILITY”,以对执行此功能模块时传入的IDATE值是否有效,如果无效(返回的SY-SUBRC不为0)则输出警告信息同时抛出“例外”中指定的异常DATE_NOT_VALID;按常规逻辑,出生日期和雇佣日期肯定不能大于当前日期,因此随后判断IDATE值是否大于当前日期,如大于也抛出DATE_GT_CURRENT。
完成如上各项工作后,点击检查,没问题后则进行激活,由此完成了一个功能模块的创建。
3)功能模块的测试
点击界面上的测试按钮,可对功能模块进行测试,以确定功能模块是否按逻辑执行。
2、程序声明
程序声明部分的代码如下:
REPORT zu0503_emp_get_age_function NO STANDARD PAGE HEADING
LINE-COUNT 50 LINE-SIZE 100.
通过如上代码定义,程序输出时,页面宽度为100(能容纳100个数字或英文字符),每页容纳50行。
3、对象定义
对象定义部分的代码如下:
*****对象定义
TYPES: BEGIN OF emp_mode, " EMP_MODE-结构体类型
employeeid TYPE ztemployee-employeeid,
employeename TYPE ztemployee-employeename,
post TYPE ztemployee-post,
sex TYPE ztemployee-sex,
hiredate TYPE ztemployee-hiredate,
birthdate TYPE ztemployee-birthdate,
END OF emp_mode.
DATA: emp_stru TYPE emp_mode, "通过类型定义结构体
emp_itab TYPE SORTED TABLE OF emp_mode
WITH UNIQUE KEY employeeid. "通过类型定义内表
DATA: eage TYPE i, "雇员年龄
hage TYPE i. "雇员工龄
如上代码,定义了一个类型EMP_MODE,并以此类型定义了一个结构EMP_STRU和一个排序内表EMP_ITAB以获得和处理数据,同时定义了2个变量分别用以存储年龄和工龄值。
4、输出页眉
输出页眉部分的代码如下:
*&----------------------------------------------------------------------*
*& 输出页眉
*&----------------------------------------------------------------------*
TOP-OF-PAGE.
WRITE:/5(8) '员工编号', (8) '员工姓名', (15) '职位', (4) '性别',
(8) '出生日期', (4) '年龄', (8) '入职日期', (4) '工龄',
/5(65) sy-uline.
5、获得和输出数据
获得和输出数据部分的代码如下:
*&----------------------------------------------------------------------*
*& START-OF-SELECTION
*&----------------------------------------------------------------------*
START-OF-SELECTION.
*****获取员工信息
SELECT employeeid employeename post sex hiredate birthdate
INTO TABLE emp_itab
FROM ztemployee.
*****输出员工信息
LOOP AT emp_itab INTO emp_stru.
CALL FUNCTION 'ZU05_GET_AGE' "根据出生日期调用函数返回年龄给EAGE
EXPORTING
idate = emp_stru-birthdate
IMPORTING
oage = eage
EXCEPTIONS
date_not_valid = 1
date_gt_current = 2.
CALL FUNCTION 'ZU05_GET_AGE' "根据入职日期调用函数返回年龄给hage
EXPORTING
idate = emp_stru-hiredate
IMPORTING
oage = hage
EXCEPTIONS
date_not_valid = 1
date_gt_current = 2.
WRITE:/5(8) emp_stru-employeeid, (8) emp_stru-employeename, (15) emp_stru-post,
(4) emp_stru-sex,
(8) emp_stru-birthdate, (4) eage, (8) emp_stru-hiredate, (4) hage.
ENDLOOP.
如上代码,首先从ztemployee表中获得数据后存入到内表emp_itab;随后通过LOOP AT遍历内表数据并存储到结构emp_stru,接下来,分别根据结构中存储的出生日期(emp_stru-birthdate)和入职日期(emp_stru-hiredate),通过CALL FUNCTION调用功能模块,计算出年龄和工龄;同时在调用功能模块后如果遇到异常,则将异常结果赋值给SY-SUBRC(如按代码,在日期无效时为1,大于当前日期时则为2),然后可根据异常情况进行相应处理(如对输出的年龄跟工龄处的输出进行相应提示,或在状态栏输出消息,如上代码中没实现);最后根据需求输出数据。
将如上2~5部分的代码顺序合并后,则得到本需求的实现代码。
本实践小结:功能函数
功能模块(FUNCTION MODULE)也是代码复用的一种技术,且相对于宏(Macro)、子程序(Subroute)等,是独立的ABAP对象,应用更为广泛,在定义后,不仅可以在不同程序中调用,还可以通过RFC(Remote Function Call)技术,实现在在不同的SAP之间、非SAP系统与SAP之间的调用。
1、功能组(函数组Function Group)
建立任一功能模块都需要指定其对应的功能组,功能组是功能模块的容器。也可以把功能组理解为一种ABAP程序,在创建一个功能组后,系统将生成一个名称为SAPL
2、功能模块的属性和参数
功能模块的属性设置主要有类型的选择:
功能模块的参数: