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

跟随虾哥项目实践,硬件选小智就对了

xiaozhi 开源方案官方适配,二次开发文档齐全

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>.
"解析入参JSON
CALL 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.
"异常,不传的话,函数抛出异常的时候会DUMP
LOOP 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.


"动态调用Function
CALL 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"}]}'.

输出结果如下

1b1453695a5d046a14bf0db194a3a705.png

63a48f446b0ff575d5ab6a34bb79dfee.png

141115c1b3503031e69e2fa939a04b1c.png

—END—

 15aeefb0dace1d0c5f2499c568492bdc.gif

e22e364368c504cc392b830b9a7aaccb.png

温馨提示

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

 d69dbd19c12ba0ef7b800e396bdd666a.jpeg

4229d4573117aaf2ec9b248f596d0717.png

扫码关注我们

以便获取最新更新内容。

e610faf779a026aeb861f542d61cbf42.png

跟随虾哥项目实践,硬件选小智就对了

xiaozhi 开源方案官方适配,二次开发文档齐全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值