函数动态调用(RTTS)-实战篇

文摘   2024-10-28 18:18   北京  

01

前言

SAP与外围系统做接口时,有一种设计模式如下:

SAP设置一个通用接口,外围系统传入接口编号(映射到SAP中某个SE37函数),传入函数的入参JSON字符串,SAP函数执行完后,将结果序列化成JSON返回给外围系统,这里可能就会涉及到函数的动态调用,下面用一个实例来介绍具体使用方法。


02

准备SE37函数

我这里以ZRFC_SAY_HELLO为例,传入一个字符串IV_VALUE(为空时抛出异常INVALID_PARAM),然后SAP返回一个字符串EV_VALUE,传入一个工厂内表(用来传入工厂代码),返回一个工厂内表(工厂的详细信息)。
代码如下
FUNCTION zrfc_say_hello.*"----------------------------------------------------------------------*"*"本地接口:*"  IMPORTING*"     VALUE(IV_VALUE) TYPE  STRING*"  EXPORTING*"     VALUE(EV_VALUE) TYPE  STRING*"  TABLES*"      IT_INPUT STRUCTURE  T001W OPTIONAL*"      ET_OUTPUT STRUCTURE  T001W OPTIONAL*"  EXCEPTIONS*"      INVALID_PARAM*"----------------------------------------------------------------------  IF iv_value IS INITIAL.    RAISE invalid_param.  ENDIF.  ev_value = |Hello { iv_value }! From sap { sy-datum }{ sy-uzeit }|.  SELECT * INTO TABLE @et_output FROM t001w  UP TO 10 ROWS FOR ALL ENTRIES IN @it_input WHERE werks = @it_input-werks.
ENDFUNCTION.

  

03

SE38 Demo程序

代码和注释见下:
*&---------------------------------------------------------------------**& Report zyxstest01*&---------------------------------------------------------------------**&*&---------------------------------------------------------------------*REPORT zyxstest01.
"SE37函数名称CONSTANTS cns_name TYPE eu_lname VALUE 'ZRFC_SAY_HELLO'.
"入参json字符串DATA lv_json_in TYPE string."出参json字符串DATA lv_json_out TYPE string.
"入参对象引用DATA lo_data_in TYPE REF TO data."出参对象引用DATA lo_data_out TYPE REF TO data.
"结构组件,用来创建动态结构DATA lt_components TYPE abap_component_tab.DATA ls_components TYPE abap_componentdescr.DATA lo_datadescr TYPE REF TO cl_abap_datadescr.DATA lo_struct TYPE REF TO cl_abap_structdescr.
"函数动态参数明细DATA ls_interface TYPE rsfbintfv."函数动态调用时传参DATA lt_param TYPE abap_func_parmbind_tab.DATA ls_param TYPE abap_func_parmbind."函数动态调用时异常参数DATA lt_except TYPE abap_func_excpbind_tab.DATA ls_except TYPE abap_func_excpbind.
FIELD-SYMBOLS: <fs_data_in>, <fs_data_out>, <fs_value>.
lv_json_in = '{"IV_VALUE":"JAVA","IT_INPUT":[{"WERKS":"1000"},{"WERKS":"2000"}]}'."获取函数参数cl_fb_function_utility=>meth_get_interface( EXPORTING im_name = cns_name IMPORTING ex_interface = ls_interface )."导入参数LOOP AT ls_interface-import INTO DATA(ls_import). ls_components-name = ls_import-parameter. ls_components-type ?= cl_abap_datadescr=>describe_by_name( p_name = ls_import-structure ). APPEND ls_components TO lt_components.ENDLOOP."更改参数LOOP AT ls_interface-change INTO DATA(ls_change). ls_components-name = ls_change-parameter. ls_components-type ?= cl_abap_datadescr=>describe_by_name( p_name = ls_change-structure ). APPEND ls_components TO lt_components.ENDLOOP."表参数LOOP AT ls_interface-tables INTO DATA(ls_table). ls_components-name = ls_table-parameter. lo_datadescr ?= cl_abap_datadescr=>describe_by_name( p_name = ls_table-structure ). "根据行结构创建表结构 CALL METHOD cl_abap_tabledescr=>create EXPORTING p_line_type = lo_datadescr RECEIVING p_result = ls_components-type. APPEND ls_components TO lt_components.ENDLOOP.
"创建入参结构CALL METHOD cl_abap_structdescr=>create EXPORTING p_components = lt_components RECEIVING p_result = lo_struct.
CREATE DATA lo_data_in TYPE HANDLE lo_struct.ASSIGN lo_data_in->* TO <fs_data_in>."解析入参JSONCALL METHOD /ui2/cl_json=>deserialize EXPORTING json = lv_json_in CHANGING data = lo_data_in.
"构造函数动态调用参数"入参LOOP AT ls_interface-import INTO ls_import. ASSIGN COMPONENT ls_import-parameter OF STRUCTURE <fs_data_in> TO <fs_value>. CHECK sy-subrc = 0. ls_param-name = ls_import-parameter. ls_param-kind = abap_func_exporting. ls_param-value = REF #( <fs_value> ). INSERT ls_param INTO TABLE lt_param. CLEAR ls_param.ENDLOOP."更改参数LOOP AT ls_interface-change INTO ls_change. ASSIGN COMPONENT ls_change-parameter OF STRUCTURE <fs_data_in> TO <fs_value>. CHECK sy-subrc = 0. ls_param-name = ls_change-parameter. ls_param-kind = abap_func_changing. ls_param-value = REF #( <fs_value> ). INSERT ls_param INTO TABLE lt_param. CLEAR ls_param.ENDLOOP."表参数LOOP AT ls_interface-tables INTO ls_table. ASSIGN COMPONENT ls_table-parameter OF STRUCTURE <fs_data_in> TO <fs_value>. CHECK sy-subrc = 0. ls_param-name = ls_table-parameter. ls_param-kind = abap_func_tables. ls_param-value = REF #( <fs_value> ). INSERT ls_param INTO TABLE lt_param. CLEAR ls_param.ENDLOOP."出参LOOP AT ls_interface-export INTO DATA(ls_export). ls_param-name = ls_export-parameter. ls_param-kind = abap_func_importing. CREATE DATA ls_param-value TYPE (ls_export-structure). INSERT ls_param INTO TABLE lt_param. CLEAR ls_param.ENDLOOP."异常,不传的话,函数抛出异常的时候会DUMPLOOP AT ls_interface-except INTO DATA(ls_exce). ls_except-name = ls_exce-parameter. ls_except-value = sy-tabix. INSERT ls_except INTO TABLE lt_except. CLEAR ls_except.ENDLOOP.
"动态调用FunctionCALL FUNCTION cns_name PARAMETER-TABLE lt_param EXCEPTION-TABLE lt_except.IF sy-subrc = 0. "创建出参结构 REFRESH lt_components. "导出参数 LOOP AT ls_interface-export INTO ls_export. ls_components-name = ls_export-parameter. ls_components-type ?= cl_abap_datadescr=>describe_by_name( p_name = ls_export-structure ). APPEND ls_components TO lt_components. ENDLOOP. "更改参数 LOOP AT ls_interface-change INTO ls_change. ls_components-name = ls_change-parameter. ls_components-type ?= cl_abap_datadescr=>describe_by_name( p_name = ls_change-structure ). APPEND ls_components TO lt_components. ENDLOOP. "表参数 LOOP AT ls_interface-tables INTO ls_table. ls_components-name = ls_table-parameter. lo_datadescr ?= cl_abap_datadescr=>describe_by_name( p_name = ls_table-structure ). "根据行结构创建表结构 CALL METHOD cl_abap_tabledescr=>create EXPORTING p_line_type = lo_datadescr RECEIVING p_result = ls_components-type. APPEND ls_components TO lt_components. ENDLOOP.
"创建出参结构 CALL METHOD cl_abap_structdescr=>create EXPORTING p_components = lt_components RECEIVING p_result = lo_struct.
CREATE DATA lo_data_out TYPE HANDLE lo_struct. ASSIGN lo_data_out->* TO <fs_data_out>.
LOOP AT lt_param INTO ls_param WHERE kind <> abap_func_exporting. ASSIGN COMPONENT ls_param-name OF STRUCTURE <fs_data_out> TO <fs_value>. CHECK sy-subrc = 0. ASSIGN ls_param-value->* TO FIELD-SYMBOL(<fs_val>). <fs_value> = <fs_val>. ENDLOOP.
"出参序列化 lv_json_out = /ui2/cl_json=>serialize( data = lo_data_out ). cl_demo_output=>display_json( lv_json_out ).ENDIF.
BREAK-POINT.


04

重点代码介绍

1.获取函数参数,这个类方法可以获取函数的所有出入参、表、异常等信息
cl_fb_function_utility=>meth_get_interface(     EXPORTING       im_name = cns_name     IMPORTING       ex_interface = ls_interface ).

2.根据结构名获取组件类型

ls_components-type ?= cl_abap_datadescr=>describe_by_name( p_name = ls_change-structure ).

3.根据行结构类型创建表类型

CALL METHOD cl_abap_tabledescr=>create    EXPORTING      p_line_type = lo_datadescr    RECEIVING      p_result    = ls_components-type.

4.根据组件内表创建动态结构类型

CALL METHOD cl_abap_structdescr=>create  EXPORTING    p_components = lt_components  RECEIVING    p_result     = lo_struct.

5.根据动态结构类型创建对象引用,并分配给字段符号

CREATE DATA lo_data_in TYPE HANDLE lo_struct.ASSIGN lo_data_in->* TO <fs_data_in>.

6.动态调用Function

CALL FUNCTION cns_name  PARAMETER-TABLE lt_param  EXCEPTION-TABLE lt_except.

7.JSON序列化和反序列化

CALL METHOD /ui2/cl_json=>deserialize  EXPORTING    json = lv_json_in  CHANGING    data = lo_data_in.     lv_json_out = /ui2/cl_json=>serialize( data = lo_data_out ).



05

输出结果

输入JSON:
lv_json_in = '{"IV_VALUE":"JAVA","IT_INPUT":[{"WERKS":"1000"},{"WERKS":"2000"}]}'.
输出结果如下


 

END

 

温馨提示

如果你喜欢本文,请分享给有需要的朋友,想要获得更多信息,请关注我,若有问题以及建议,请在文末留言或者私信。





 

 

扫码关注我们

以便获取最新更新内容


 

码农干货铺
永远要保持一种无论何时何地都逼着自己更努力更优秀来享受更好生活的学习状态
 最新文章