使用HTTP接口,对接外围系统,封装调用跟推送类和动态转换json,动态编程和动态调用函数

这里封装了一个类,可以解析任何json,然后根据抬头传入的函数ID找对应的函数模块,动态调用函数模块,使用到了动态结构和动态编程和动态调用函数

文章目录

创建函数模块

创建结构

导入参数

导出参数

创建类

创建服务

激活服务

测试服务

创建消息类型结构

当前核心代码

js 复制代码
  METHOD IF_HTTP_EXTENSION~HANDLE_REQUEST.
    DATA : LV_METHOD   TYPE STRING."HTTP 方法
    DATA : LT_FIELDS TYPE TIHTTPNVP,
           LS_FIELDS TYPE IHTTPNVP.
    TYPES:BEGIN OF GTY_HEADER_FIELDS,
            SNDPRN TYPE STRING,
            ZRFCID TYPE STRING,
          END OF GTY_HEADER_FIELDS.
    DATA LS_HEADER_FIELDS TYPE GTY_HEADER_FIELDS.

    DATA LS_RESPONSE TYPE ZSAPPO_RET_INFO.
    DATA LS_JSON TYPE STRING.
    LV_METHOD = SERVER->REQUEST->GET_HEADER_FIELD( NAME = '~request_method' ).
    SERVER->REQUEST->GET_HEADER_FIELDS( CHANGING FIELDS = LT_FIELDS ).

    "---解析url 参数 ~query_string
    READ TABLE LT_FIELDS INTO LS_FIELDS WITH KEY NAME = '~query_string'.
    IF SY-SUBRC = 0.
      SPLIT LS_FIELDS-VALUE AT '&' INTO TABLE DATA(LT_QUERY_STRING).
      LOOP AT LT_QUERY_STRING INTO DATA(LS_QUERY_STRING).
        IF LS_QUERY_STRING CS 'sndprn' OR LS_QUERY_STRING CS 'zrfcid'.
          CLEAR : LS_FIELDS.
          SPLIT LS_QUERY_STRING AT '=' INTO LS_FIELDS-NAME LS_FIELDS-VALUE.
          APPEND LS_FIELDS TO LT_FIELDS.
        ENDIF.
      ENDLOOP.
    ENDIF.

    LOOP AT LT_FIELDS INTO LS_FIELDS.
      ASSIGN COMPONENT LS_FIELDS-NAME OF STRUCTURE LS_HEADER_FIELDS TO FIELD-SYMBOL(<FS_FIELD>).
      IF <FS_FIELD> IS  ASSIGNED.
        <FS_FIELD> = LS_FIELDS-VALUE.
      ENDIF.
      UNASSIGN <FS_FIELD>.
    ENDLOOP.

    IF LS_HEADER_FIELDS-SNDPRN IS INITIAL.
      LS_RESPONSE-CODE = 'E'.
      LS_RESPONSE-MSG = 'SNDPRN不能为空!'.
    ENDIF.

    CALL METHOD ME->_RESPONSE_JSON
      EXPORTING
        SERVER  = SERVER
        IV_RESP = LS_RESPONSE
      IMPORTING
        EV_JSON = LS_JSON.

  ENDMETHOD.
js 复制代码
  METHOD _RESPONSE_JSON.

    DATA : LV_JSON TYPE STRING.
    DATA : LS_RESPONSE TYPE ZSAPPO_RET_INFO.

    IF IV_RESP IS NOT INITIAL.
      "生成JSON
      EV_JSON = /UI2/CL_JSON=>SERIALIZE( DATA        = IV_RESP
                                         PRETTY_NAME = /UI2/CL_JSON=>PRETTY_MODE-NONE ).

      "---添加响应报文
      SERVER->RESPONSE->IF_HTTP_ENTITY~SET_CONTENT_TYPE( CONTENT_TYPE = 'application/json' ).
      SERVER->RESPONSE->SET_CDATA(
        EXPORTING
          DATA = EV_JSON    " Character data
      ).
    ENDIF.
  ENDMETHOD.

创建URL配置表


维护配置表的内容

维护功能模块参数表



创建动态结构

传入结构的创建

传出结构的创建

调用函数





类ZCL_SCARR_0001类

方法

IF_HTTP_EXTENSION~HANDLE_REQUEST

js 复制代码
  METHOD IF_HTTP_EXTENSION~HANDLE_REQUEST.
    DATA : LV_METHOD   TYPE STRING."HTTP 方法
    DATA : LT_FIELDS TYPE TIHTTPNVP,
           LS_FIELDS TYPE IHTTPNVP.
    TYPES:BEGIN OF GTY_HEADER_FIELDS,
            REQKEYID         TYPE STRING,
            BUSINESSID       TYPE STRING,
            SNDPRN           TYPE STRING,
            ZRFCID           TYPE STRING,
            GET_REQUEST_JSON TYPE STRING,
            TOKEN            TYPE STRING,
          END OF GTY_HEADER_FIELDS.
    DATA LS_HEADER_FIELDS TYPE GTY_HEADER_FIELDS.

    DATA LS_RESPONSE TYPE ZSAPPO_RET_INFO.
    DATA LS_JSON TYPE STRING.

    DATA: LR_REQ TYPE REF TO DATA,
          LR_RET TYPE REF TO DATA.

    DATA : LS_FUPARAREF TYPE FUPARAREF,
           LT_FUPARAREF LIKE TABLE OF LS_FUPARAREF.

    DATA : LV_REQ_JSON TYPE STRING.
    DATA : LV_RET_JSON TYPE STRING.
    DATA LV_SIGN(1) TYPE C.
    DATA : LV_JSON_MSG TYPE STRING.
    DATA : LV_HTML         TYPE STRING.

    LV_METHOD = SERVER->REQUEST->GET_HEADER_FIELD( NAME = '~request_method' ).
    SERVER->REQUEST->GET_HEADER_FIELDS( CHANGING FIELDS = LT_FIELDS ).

    "---解析url 参数 ~query_string
    READ TABLE LT_FIELDS INTO LS_FIELDS WITH KEY NAME = '~query_string'.
    IF SY-SUBRC = 0.
      SPLIT LS_FIELDS-VALUE AT '&' INTO TABLE DATA(LT_QUERY_STRING).
      LOOP AT LT_QUERY_STRING INTO DATA(LS_QUERY_STRING).
        IF LS_QUERY_STRING CS 'sndprn' OR LS_QUERY_STRING CS 'zrfcid'.
          CLEAR : LS_FIELDS.
          SPLIT LS_QUERY_STRING AT '=' INTO LS_FIELDS-NAME LS_FIELDS-VALUE.
          APPEND LS_FIELDS TO LT_FIELDS.
        ENDIF.
      ENDLOOP.
    ENDIF.

    LOOP AT LT_FIELDS INTO LS_FIELDS.
      ASSIGN COMPONENT LS_FIELDS-NAME OF STRUCTURE LS_HEADER_FIELDS TO FIELD-SYMBOL(<FS_FIELD>).
      IF <FS_FIELD> IS  ASSIGNED.
        <FS_FIELD> = LS_FIELDS-VALUE.
      ENDIF.
      UNASSIGN <FS_FIELD>.
    ENDLOOP.

    IF LS_HEADER_FIELDS-SNDPRN IS INITIAL.
      LS_RESPONSE-CODE = 'E'.
      LS_RESPONSE-MSG = 'SNDPRN不能为空!'.
    ENDIF.

    IF LS_HEADER_FIELDS-ZRFCID IS INITIAL.
      LS_RESPONSE-CODE = 'E'.
      LS_RESPONSE-MSG = 'ZRFCID不能为空!'.
    ENDIF.

    "获取配置的RFC函数名
    SELECT
      SINGLE
      * FROM ZTURL_SCARR
      WHERE PARNUM = @LS_HEADER_FIELDS-SNDPRN
      AND ZRFCID = @LS_HEADER_FIELDS-ZRFCID
      INTO @DATA(LS_URL).
    IF SY-SUBRC NE 0 AND LS_HEADER_FIELDS-SNDPRN IS NOT INITIAL AND LS_HEADER_FIELDS-ZRFCID IS NOT INITIAL.
      LS_RESPONSE-CODE = 'E'.
      IF LS_RESPONSE-MSG IS INITIAL.
        LS_RESPONSE-MSG = |{ LS_HEADER_FIELDS-SNDPRN }-{ LS_HEADER_FIELDS-ZRFCID }接口配置不存在|.
      ELSE.
        LS_RESPONSE-MSG = |{ LS_RESPONSE-MSG };{ LS_HEADER_FIELDS-SNDPRN }-{ LS_HEADER_FIELDS-ZRFCID }接口配置不存在|.
      ENDIF.
    ENDIF.

    "获取函数的参数等信息
    SELECT *
      FROM FUPARAREF
      WHERE FUNCNAME = @LS_URL-FUNC_NAME
      INTO CORRESPONDING FIELDS OF TABLE @LT_FUPARAREF.
    IF SY-SUBRC <> 0.
      LS_RESPONSE-CODE = 'E'.
      IF LS_RESPONSE-MSG IS INITIAL.
        LS_RESPONSE-MSG = |接口对应RFC不存在|.
      ELSE.
        LS_RESPONSE-MSG = |{ LS_RESPONSE-MSG };接口对应RFC不存在|.
      ENDIF.
    ENDIF.

    IF LS_RESPONSE-CODE EQ 'E'.
      "---参数不全直接退出
      CALL METHOD ME->_RESPONSE_JSON( SERVER = SERVER IV_JSON = LV_HTML DATA = LS_RESPONSE ).
      RETURN.

    ENDIF.

    "---创建动态结构
    CALL METHOD ME->_CREATE_DYNAMIC_STRU
      EXPORTING
        IV_FUNCNAME   = LS_URL-FUNC_NAME                 " 功能模块的名称
        IT_FUPARAREF  = LT_FUPARAREF
      IMPORTING
        ER_REQ_STRUCT = LR_REQ
        ER_RET_STRUCT = LR_RET.

    IF LS_HEADER_FIELDS-GET_REQUEST_JSON EQ 'X'.
      "---获取request_json格式示例

      CALL METHOD ME->_GET_JSON_MSG(
        EXPORTING
          IR_REQ_STRUCT = LR_REQ
        IMPORTING
          EV_JSON_MSG   = LV_JSON_MSG
      ).

      CALL METHOD ME->_RESPONSE_JSON( SERVER = SERVER IV_JSON = LV_JSON_MSG DATA = LS_RESPONSE ).

      RETURN.

    ENDIF.

*-----获取传入报文
    LV_REQ_JSON = SERVER->REQUEST->IF_HTTP_ENTITY~GET_CDATA( ).


    IF LV_REQ_JSON IS INITIAL.
      LS_RESPONSE-CODE = 'E'.
      IF LS_RESPONSE-MSG IS INITIAL.
        LS_RESPONSE-MSG = |传入报文不允许为空|.
      ELSE.
        LS_RESPONSE-MSG = |{ LS_RESPONSE-MSG };传入报文不允许为空|.
      ENDIF.

    ENDIF.
    IF LS_RESPONSE-CODE  = 'E'.
      "---存在错误退出接口
      CALL METHOD ME->_RESPONSE_JSON( SERVER = SERVER IV_JSON = LV_HTML DATA = LS_RESPONSE )..
      RETURN.

    ENDIF.

    "---去除tab
    LV_SIGN = CL_ABAP_CHAR_UTILITIES=>HORIZONTAL_TAB.
    REPLACE ALL OCCURRENCES OF REGEX LV_SIGN IN LV_REQ_JSON WITH ``.
    "---去除换行
    LV_SIGN = CL_ABAP_CHAR_UTILITIES=>NEWLINE.
    REPLACE ALL OCCURRENCES OF REGEX LV_SIGN IN LV_REQ_JSON WITH ``.

*&--------------------------post方法动态调用RFC-------------------------------&*

    "---调用RFC
    CALL METHOD ME->_CALL_FUNCTION(
      EXPORTING
        IV_REQ_JSON   = LV_REQ_JSON
        IV_FUNCNAME   = LS_URL-FUNC_NAME                 " 功能模块的名称
        IT_FUPARAREF  = LT_FUPARAREF                 " 功能模块参数
        IR_REQ_STRUCT = LR_REQ
        IR_RET_STRUCT = LR_RET
      IMPORTING
        EV_RET_JSON   = LV_RET_JSON                " 返回json
    ).


    CALL METHOD ME->_RESPONSE_JSON( SERVER = SERVER IV_JSON = LV_RET_JSON DATA = LS_RESPONSE ).

  ENDMETHOD.

_CALL_FUNCTION

js 复制代码
  METHOD _CALL_FUNCTION.
    DATA : LS_PTAB TYPE ABAP_FUNC_PARMBIND,
           LT_PTAB TYPE ABAP_FUNC_PARMBIND_TAB.
    DATA : LS_ETAB TYPE ABAP_FUNC_EXCPBIND,
           LT_ETAB TYPE ABAP_FUNC_EXCPBIND_TAB.

    DATA : LO_TYPEDESCR TYPE REF TO CL_ABAP_TYPEDESCR.
    DATA : LS_FIELD_IN TYPE DFIES,
           LT_DFIES    TYPE DDFIELDS.

    DATA : OBJEKT TYPE REF TO DATA.
    DATA : LV_DATATYPE TYPE CHAR1.

    DATA : LV_ERROR_MSG TYPE STRING.

    FIELD-SYMBOLS: <FS_ABER> TYPE ANY.
    FIELD-SYMBOLS: <FS_PARA_IN> TYPE ANY.
    FIELD-SYMBOLS: <FS_PARA_OUT> TYPE ANY.
    FIELD-SYMBOLS: <FS_ABER_TB> TYPE ANY.

    ASSIGN IR_REQ_STRUCT->* TO FIELD-SYMBOL(<FS_REQ>).
    ASSIGN IR_RET_STRUCT->* TO FIELD-SYMBOL(<FS_RET>).


*--------------------------------------------------------------------*
* 1 解析传入参数
*--------------------------------------------------------------------*
    /UI2/CL_JSON=>DESERIALIZE( EXPORTING JSON = IV_REQ_JSON
                               CHANGING  DATA = <FS_REQ> ).

*--------------------------------------------------------------------*
* 2 函数输入参数赋值
*--------------------------------------------------------------------*
    LOOP AT IT_FUPARAREF INTO DATA(LS_FUPARAREF).

      UNASSIGN: <FS_ABER>, <FS_PARA_IN>.
      CLEAR: LV_DATATYPE, LO_TYPEDESCR.

      "动态创建工作区、内表
      IF LS_FUPARAREF-TYPE = 'X'.
        CREATE DATA OBJEKT TYPE (LS_FUPARAREF-STRUCTURE).
        ASSIGN OBJEKT->* TO <FS_ABER>.
        ASSIGN COMPONENT LS_FUPARAREF-PARAMETER OF STRUCTURE <FS_REQ> TO <FS_PARA_IN>.
      ELSE.
        CREATE DATA OBJEKT TYPE TABLE OF (LS_FUPARAREF-STRUCTURE).
        ASSIGN OBJEKT->* TO <FS_ABER>.
        ASSIGN COMPONENT LS_FUPARAREF-PARAMETER OF STRUCTURE <FS_REQ> TO <FS_PARA_IN>.
      ENDIF.

      LO_TYPEDESCR ?= CL_ABAP_TYPEDESCR=>DESCRIBE_BY_DATA( <FS_ABER> ).
      LV_DATATYPE = LO_TYPEDESCR->KIND.

      IF LS_FUPARAREF-PARAMETER = 'I' AND LS_FUPARAREF-REFERENCE = 'X'.
        CONTINUE.
      ENDIF.

      IF <FS_PARA_IN> IS ASSIGNED.

        _CONVERSION_EXIT_INPUT(
          CHANGING
            CV_DATA = <FS_PARA_IN> ).

        <FS_ABER> = <FS_PARA_IN>. "对指向传入参数的指针进行赋值,等于请求参数名对应的值
      ENDIF.


      " 对动态FM 参数赋值
      LS_PTAB-VALUE     = OBJEKT.
      LS_PTAB-NAME      = LS_FUPARAREF-PARAMETER.

      CASE LS_FUPARAREF-PARAMTYPE.
        WHEN 'I'.
          LS_PTAB-KIND      = ABAP_FUNC_EXPORTING.
        WHEN 'C'.
          LS_PTAB-KIND      = ABAP_FUNC_CHANGING.
        WHEN 'T'.
          LS_PTAB-KIND      = ABAP_FUNC_TABLES.
        WHEN 'E'.
          LS_PTAB-KIND      = ABAP_FUNC_IMPORTING.
      ENDCASE.

      INSERT LS_PTAB INTO TABLE LT_PTAB.
      CLEAR: LS_PTAB.
      UNASSIGN: <FS_PARA_IN>, <FS_ABER_TB>.
    ENDLOOP.

*--------------------------------------------------------------------*
* 3 调用函数
*--------------------------------------------------------------------*
    TRY .
      CALL FUNCTION IV_FUNCNAME
          PARAMETER-TABLE LT_PTAB
          EXCEPTION-TABLE LT_ETAB.
      CATCH CX_SY_DYN_CALL_PARAM_NOT_FOUND INTO DATA(LO_ERROR_NO_FOUND).
        LV_ERROR_MSG = LO_ERROR_NO_FOUND->GET_TEXT( ).
      CATCH CX_SY_DYN_CALL_PARAM_MISSING INTO DATA(LO_ERROR_MISSING).
        LV_ERROR_MSG = LO_ERROR_MISSING->GET_TEXT( ).
      CATCH CX_SY_DYN_CALL_PARAMETER_ERROR INTO DATA(LO_ERROR_PARAMETER).
        LV_ERROR_MSG = LO_ERROR_PARAMETER->GET_TEXT( ).
      CATCH CX_SY_DYN_CALL_ERROR INTO DATA(LO_ERROR_CALL).
        LV_ERROR_MSG = LO_ERROR_CALL->GET_TEXT( ).
    ENDTRY.


*--------------------------------------------------------------------*
* 4 函数输出参数赋值
*--------------------------------------------------------------------*
    LOOP AT IT_FUPARAREF INTO LS_FUPARAREF WHERE PARAMTYPE CA 'CET'.
                                           " AND PARAMETER+0(1) EQ 'E'.  "返回参数必须用E 开头,如果去掉这句就会一并显示表的内容,加上只出现E开头的返回参数

      UNASSIGN: <FS_PARA_OUT>, <FS_ABER>.
      CLEAR: LV_DATATYPE.

      "动态创建工作区、内表
      IF LS_FUPARAREF-TYPE = 'X'.
        CREATE DATA OBJEKT TYPE (LS_FUPARAREF-STRUCTURE).
        ASSIGN COMPONENT LS_FUPARAREF-PARAMETER OF STRUCTURE <FS_RET> TO <FS_PARA_OUT>.
      ELSE.
        CREATE DATA OBJEKT TYPE TABLE OF (LS_FUPARAREF-STRUCTURE).
        ASSIGN COMPONENT LS_FUPARAREF-PARAMETER OF STRUCTURE <FS_RET> TO <FS_PARA_OUT>.
      ENDIF.

      READ TABLE LT_PTAB INTO LS_PTAB WITH KEY NAME = LS_FUPARAREF-PARAMETER.
      IF SY-SUBRC = 0.
        OBJEKT = LS_PTAB-VALUE.
        ASSIGN OBJEKT->* TO <FS_ABER>.
      ENDIF.

      _CONVERSION_EXIT_OUTPUT(
        CHANGING
          CV_DATA = <FS_ABER>
      ).

      <FS_PARA_OUT> = <FS_ABER> . "对指向传出参数的指针进行赋值
    ENDLOOP.

    CALL METHOD /UI2/CL_JSON=>SERIALIZE
      EXPORTING
        DATA   = <FS_RET>
      RECEIVING
        R_JSON = EV_RET_JSON.

  ENDMETHOD.

_CONVERSION_EXIT_INPUT

js 复制代码
 METHOD _CONVERSION_EXIT_INPUT.

    " add by luf 20210706
    DATA: lv_exclude_exit TYPE string VALUE 'ABPSP/ABPSN/EXCRT'. "按照项目需求做增强

    DATA: lo_cl_abap_typedescr TYPE REF TO cl_abap_typedescr.
    DATA: lo_cl_abap_elemdescr TYPE REF TO cl_abap_elemdescr.
    DATA: lo_cl_abap_refdescr TYPE REF TO cl_abap_refdescr.
    DATA: lo_cl_abap_structdescr TYPE REF TO cl_abap_structdescr.
    DATA: lo_cl_abap_tabledescr TYPE REF TO cl_abap_tabledescr.
    DATA: lo_cl_abap_classdescr TYPE REF TO cl_abap_classdescr.
    DATA: lo_cl_abap_intfdescr TYPE REF TO cl_abap_intfdescr.

    DATA: ls_zz_trans_comp_descr    TYPE abap_componentdescr.
    DATA: lt_zz_trans_comp_tab    TYPE cl_abap_structdescr=>component_table.
    DATA: lv_zz_trans_table_name TYPE string.
    DATA: ls_zz_trans_fupararef TYPE fupararef,
          lt_zz_trans_fupararef TYPE TABLE OF fupararef.
    DATA: lo_zz_trans_root_error TYPE REF TO cx_root.

    "因为通用名称,所以变量必须特殊
    DATA: lv_zz_trans_funtion_name TYPE string.

    FIELD-SYMBOLS: <fs_zz_trans_field> TYPE any.
    FIELD-SYMBOLS: <fs_zz_trans_workarea> TYPE any.
    FIELD-SYMBOLS : <pt_data> TYPE ANY TABLE.

    IF cv_data IS NOT INITIAL.
      "反射
      lo_cl_abap_typedescr = cl_abap_typedescr=>describe_by_data( cv_data ).
      CASE lo_cl_abap_typedescr->kind.
        WHEN 'E'. "元素
          lo_cl_abap_elemdescr ?= lo_cl_abap_typedescr.
          IF lo_cl_abap_elemdescr->edit_mask IS NOT INITIAL AND lv_exclude_exit NS lo_cl_abap_elemdescr->edit_mask+2. "存在转换例程,且不在排除范围
            lv_zz_trans_funtion_name = 'CONVERSION_EXIT_' && lo_cl_abap_elemdescr->edit_mask+2 && '_INPUT'.
            TRY .
                CALL FUNCTION lv_zz_trans_funtion_name
                  EXPORTING
                    input         = cv_data
                  IMPORTING
                    output        = cv_data
                  EXCEPTIONS
                    error_message = 99.
                IF sy-subrc <> 0.

                ENDIF.
              CATCH cx_root INTO lo_zz_trans_root_error.
            ENDTRY.
          ENDIF.
        WHEN 'S'."结构
          "反射
          lo_cl_abap_structdescr ?= cl_abap_typedescr=>describe_by_data( cv_data ).
          lt_zz_trans_comp_tab[] = lo_cl_abap_structdescr->get_components( )."组成结构体的各个字段组件
          LOOP AT lt_zz_trans_comp_tab INTO ls_zz_trans_comp_descr WHERE as_include = 'X'. "递归INCLUDE结构
            lo_cl_abap_structdescr ?= ls_zz_trans_comp_descr-type.
            APPEND LINES OF lo_cl_abap_structdescr->get_components( ) TO lt_zz_trans_comp_tab[].
          ENDLOOP.
          LOOP AT lt_zz_trans_comp_tab INTO ls_zz_trans_comp_descr.
            IF ls_zz_trans_comp_descr-as_include = 'X'.
              DELETE lt_zz_trans_comp_tab.
              CONTINUE.
            ENDIF.

            "存在例程
            ASSIGN COMPONENT ls_zz_trans_comp_descr-name OF STRUCTURE cv_data TO <fs_zz_trans_field>.
            IF <fs_zz_trans_field> IS ASSIGNED.
              _conversion_exit_input( CHANGING cv_data = <fs_zz_trans_field> ).
              UNASSIGN <fs_zz_trans_field>.
            ENDIF.

          ENDLOOP.

        WHEN 'T'."结构

          IF cv_data IS NOT INITIAL.

            ASSIGN cv_data TO <pt_data>.

            IF <pt_data> IS ASSIGNED.
              "转换处理
              LOOP AT <pt_data> ASSIGNING <fs_zz_trans_workarea>.
                _conversion_exit_input( CHANGING cv_data = <fs_zz_trans_workarea> ).
              ENDLOOP.
            ENDIF.

          ENDIF.

        WHEN OTHERS.
      ENDCASE.

    ENDIF.

  ENDMETHOD.

_CONVERSION_EXIT_OUTPUT

js 复制代码
  METHOD _CONVERSION_EXIT_OUTPUT.

    " add by luf 20210706
    DATA: lv_exclude_exit TYPE string VALUE 'ABPSP/ABPSN/EXCRT'. "按照项目需求做增强

    DATA: lo_cl_abap_typedescr TYPE REF TO cl_abap_typedescr.
    DATA: lo_cl_abap_elemdescr TYPE REF TO cl_abap_elemdescr.
    DATA: lo_cl_abap_refdescr TYPE REF TO cl_abap_refdescr.
    DATA: lo_cl_abap_structdescr TYPE REF TO cl_abap_structdescr.
    DATA: lo_cl_abap_tabledescr TYPE REF TO cl_abap_tabledescr.
    DATA: lo_cl_abap_classdescr TYPE REF TO cl_abap_classdescr.
    DATA: lo_cl_abap_intfdescr TYPE REF TO cl_abap_intfdescr.

    DATA: ls_zz_trans_comp_descr    TYPE abap_componentdescr.
    DATA: lt_zz_trans_comp_tab    TYPE cl_abap_structdescr=>component_table.
    DATA: lv_zz_trans_table_name TYPE string.
    DATA: ls_zz_trans_fupararef TYPE fupararef,
          lt_zz_trans_fupararef TYPE TABLE OF fupararef.
    DATA: lo_zz_trans_root_error TYPE REF TO cx_root.

    "因为通用名称,所以变量必须特殊
    DATA: lv_zz_trans_funtion_name TYPE string.

    FIELD-SYMBOLS: <fs_zz_trans_field> TYPE any.
    FIELD-SYMBOLS: <fs_zz_trans_workarea> TYPE any.
    FIELD-SYMBOLS : <pt_data> TYPE ANY TABLE.

    IF cv_data IS NOT INITIAL.
      "反射
      lo_cl_abap_typedescr = cl_abap_typedescr=>describe_by_data( cv_data ).
      CASE lo_cl_abap_typedescr->kind.
        WHEN 'E'. "元素
          lo_cl_abap_elemdescr ?= lo_cl_abap_typedescr.
          IF lo_cl_abap_elemdescr->edit_mask IS NOT INITIAL AND lv_exclude_exit NS lo_cl_abap_elemdescr->edit_mask+2. "存在转换例程,且不在排除范围
            lv_zz_trans_funtion_name = 'CONVERSION_EXIT_' && lo_cl_abap_elemdescr->edit_mask+2 && '_OUTPUT'.
            TRY .
                CALL FUNCTION lv_zz_trans_funtion_name
                  EXPORTING
                    input         = cv_data
                  IMPORTING
                    output        = cv_data
                  EXCEPTIONS
                    error_message = 99.
                IF sy-subrc <> 0.

                ENDIF.
              CATCH cx_root INTO lo_zz_trans_root_error.
            ENDTRY.
          ENDIF.
        WHEN 'S'."结构
          "反射
          lo_cl_abap_structdescr ?= cl_abap_typedescr=>describe_by_data( cv_data ).
          lt_zz_trans_comp_tab[] = lo_cl_abap_structdescr->get_components( )."组成结构体的各个字段组件
          LOOP AT lt_zz_trans_comp_tab INTO ls_zz_trans_comp_descr WHERE as_include = 'X'. "递归INCLUDE结构
            lo_cl_abap_structdescr ?= ls_zz_trans_comp_descr-type.
            APPEND LINES OF lo_cl_abap_structdescr->get_components( ) TO lt_zz_trans_comp_tab[].
          ENDLOOP.
          LOOP AT lt_zz_trans_comp_tab INTO ls_zz_trans_comp_descr.
            IF ls_zz_trans_comp_descr-as_include = 'X'.
              DELETE lt_zz_trans_comp_tab.
              CONTINUE.
            ENDIF.

            "存在例程
            ASSIGN COMPONENT ls_zz_trans_comp_descr-name OF STRUCTURE cv_data TO <fs_zz_trans_field>.
            IF <fs_zz_trans_field> IS ASSIGNED.
              _conversion_exit_output( CHANGING cv_data = <fs_zz_trans_field> ).
              UNASSIGN <fs_zz_trans_field>.
            ENDIF.

          ENDLOOP.

        WHEN 'T'."结构

          ASSIGN cv_data TO <pt_data>.

          IF <pt_data> IS ASSIGNED.
            "转换处理
            LOOP AT <pt_data> ASSIGNING <fs_zz_trans_workarea>.
              _conversion_exit_output( CHANGING cv_data = <fs_zz_trans_workarea> ).
            ENDLOOP.
          ENDIF.

        WHEN OTHERS.
      ENDCASE.

    ENDIF.

  ENDMETHOD.

_GET_JSON_MSG

js 复制代码
  METHOD _GET_JSON_MSG.

    ASSIGN IR_REQ_STRUCT->* TO FIELD-SYMBOL(<FS_REQ>).

    "--- <fs_req> 若有表则需要手动添加行

    "---生成json报文
    EV_JSON_MSG = /UI2/CL_JSON=>SERIALIZE( DATA           = <FS_REQ>
                                           NUMC_AS_STRING = 'X' ).
  ENDMETHOD.

_RESPONSE_JSON

js 复制代码
  METHOD _RESPONSE_JSON.

    DATA : LV_JSON TYPE STRING.
    DATA : LS_RESPONSE TYPE ZSAPPO_RET_INFO.

    IF IV_JSON IS INITIAL AND DATA IS INITIAL.

      LS_RESPONSE-CODE = 'E'.
      LS_RESPONSE-MSG = TEXT-001.

      "生成JSON
      LV_JSON = /UI2/CL_JSON=>SERIALIZE( DATA        = LS_RESPONSE
                                         PRETTY_NAME = /UI2/CL_JSON=>PRETTY_MODE-NONE ).

    ELSEIF IV_JSON IS NOT INITIAL.

      LV_JSON = IV_JSON.

    ELSEIF DATA IS NOT INITIAL.

      "生成JSON
      LV_JSON = /UI2/CL_JSON=>SERIALIZE( DATA        = DATA
                                         PRETTY_NAME = /UI2/CL_JSON=>PRETTY_MODE-NONE ).

    ENDIF.

    "---添加相应报文
    SERVER->RESPONSE->IF_HTTP_ENTITY~SET_CONTENT_TYPE( CONTENT_TYPE = 'application/json' ).
    SERVER->RESPONSE->SET_CDATA(
      EXPORTING
        DATA = LV_JSON    " Character data
    ).

  ENDMETHOD.

_CREATE_DYNAMIC_STRU

js 复制代码
  METHOD _CREATE_DYNAMIC_STRU.
    DATA: LS_COMPONENTS TYPE ABAP_COMPONENTDESCR,
          LT_COMPONENTS TYPE ABAP_COMPONENT_TAB,
          LO_ELEMT_TYPE TYPE REF TO CL_ABAP_DATADESCR.
    DATA: LR_REQ  TYPE REF TO DATA,
          LR_RET  TYPE REF TO DATA,
          LR_ITAB TYPE REF TO DATA.
    " RFC函数动态赋值结构
    DATA: LS_PTAB TYPE ABAP_FUNC_PARMBIND,
          LT_PTAB TYPE ABAP_FUNC_PARMBIND_TAB.
    DATA: LT_ETAB TYPE ABAP_FUNC_EXCPBIND_TAB.
    FIELD-SYMBOLS: <FS_ITAB> TYPE ANY,
                   <FS_REQ>  TYPE ANY,
                   <FS_RET>  TYPE ANY.

*&--------------------------创建动态传入结构-------------------------------&*
    LOOP AT IT_FUPARAREF[] INTO DATA(LS_FUPARAREF) WHERE PARAMTYPE CA 'ICT'.
      CLEAR: LS_COMPONENTS,LO_ELEMT_TYPE.
      IF LS_FUPARAREF-TYPE = 'X'.
        LO_ELEMT_TYPE ?= CL_ABAP_STRUCTDESCR=>DESCRIBE_BY_NAME( LS_FUPARAREF-STRUCTURE ).
      ELSE.
        CREATE DATA LR_ITAB TYPE TABLE OF (LS_FUPARAREF-STRUCTURE).
        ASSIGN LR_ITAB->* TO <FS_ITAB>.
        LO_ELEMT_TYPE ?= CL_ABAP_STRUCTDESCR=>DESCRIBE_BY_DATA( <FS_ITAB> ).
      ENDIF.

      LS_COMPONENTS-NAME = LS_FUPARAREF-PARAMETER.
      LS_COMPONENTS-TYPE = LO_ELEMT_TYPE.
      APPEND LS_COMPONENTS TO LT_COMPONENTS.
    ENDLOOP.

    DATA(LO_STRUCT) = CL_ABAP_STRUCTDESCR=>CREATE( P_COMPONENTS = LT_COMPONENTS ).
    CREATE DATA ER_REQ_STRUCT TYPE HANDLE LO_STRUCT.


*&--------------------------创建动态传出结构-------------------------------&*
    CLEAR: LT_COMPONENTS, LO_STRUCT.
    LOOP AT IT_FUPARAREF[] INTO LS_FUPARAREF WHERE PARAMTYPE CA 'ECT'.
      CLEAR: LS_COMPONENTS,LO_ELEMT_TYPE.
      IF LS_FUPARAREF-TYPE = 'X'.
        LO_ELEMT_TYPE ?= CL_ABAP_STRUCTDESCR=>DESCRIBE_BY_NAME( LS_FUPARAREF-STRUCTURE ).
      ELSE.
        CREATE DATA LR_ITAB TYPE TABLE OF (LS_FUPARAREF-STRUCTURE).
        ASSIGN LR_ITAB->* TO <FS_ITAB>.
        LO_ELEMT_TYPE ?= CL_ABAP_STRUCTDESCR=>DESCRIBE_BY_DATA( <FS_ITAB> ).
      ENDIF.
      LS_COMPONENTS-NAME = LS_FUPARAREF-PARAMETER.
      LS_COMPONENTS-TYPE = LO_ELEMT_TYPE.
      APPEND LS_COMPONENTS TO LT_COMPONENTS.
    ENDLOOP.

    LO_STRUCT = CL_ABAP_STRUCTDESCR=>CREATE( P_COMPONENTS = LT_COMPONENTS ).
    CREATE DATA ER_RET_STRUCT TYPE HANDLE LO_STRUCT.

  ENDMETHOD.

函数模块ZFC_SCARR_1

导入参数

导出参数

源代码

js 复制代码
FUNCTION ZFC_SCARR_1.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     VALUE(IV_FLAG) TYPE  I DEFAULT 1
*"     VALUE(IS_DATA) TYPE  SCARR
*"  EXPORTING
*"     VALUE(ES_RET) TYPE  ZSAPPO_RET_INFO
*"     VALUE(EV_JSON) TYPE  STRING
*"     VALUE(EV_MATNR) TYPE  MATNR
*"  TABLES
*"      IT_ITEMS STRUCTURE  ZSL0001
*"----------------------------------------------------------------------

  SELECT
    DISTINCT
    A~CARRID,
    A~CARRNAME,
    B~CONNID,
    B~FLDATE,
    B~CURRENCY
    FROM SCARR AS A
    LEFT JOIN SFLIGHT AS B ON A~CARRID = B~CARRID
    WHERE A~CARRID = @IS_DATA-CARRID
    INTO CORRESPONDING FIELDS OF TABLE @IT_ITEMS
    UP TO 3 ROWS.

  IF IT_ITEMS[] IS NOT INITIAL.
    ES_RET-CODE = 'S'.
    ES_RET-MSG = '恭喜!成功读取数据'.
  ELSE.
    ES_RET-CODE = 'E'.
    ES_RET-MSG = '对不起,读取数据失败!'.
  ENDIF.

  SELECT SINGLE MATNR FROM MARA WHERE ERSDA = '20191024' INTO @EV_MATNR.
ENDFUNCTION.

Postman调试

请求参数

json 复制代码
{
    "IS_DATA": {
        "MANDT": "",
        "CARRID": "AA",
        "CARRNAME": "AA航班",
        "CURRCODE": "",
        "URL": "https://www.url.com"
    },
    "IT_ITEMS": []
}

返回的JSON

json 复制代码
{
    "ES_RET": {
        "RETKEYID": "",
        "CODE": "S",
        "MSG": "恭喜!成功读取数据",
        "KEY1": "",
        "KEY2": "",
        "KEY3": "",
        "RETMESSAGEID": ""
    },
    "EV_JSON": "",
    "EV_MATNR": "169",
    "IT_ITEMS": [
        {
            "CARRID": "AA",
            "CARRNAME": "American Airlines",
            "CONNID": 17,
            "FLDATE": "2025-03-06",
            "CURRENCY": "USD"
        },
        {
            "CARRID": "AA",
            "CARRNAME": "American Airlines",
            "CONNID": 17,
            "FLDATE": "2025-04-07",
            "CURRENCY": "USD"
        },
        {
            "CARRID": "AA",
            "CARRNAME": "American Airlines",
            "CONNID": 17,
            "FLDATE": "2025-05-09",
            "CURRENCY": "USD"
        }
    ]
}
相关推荐
ikgade2 小时前
ArcGIS Manager Server Add Host页面报错 HTTP Status 500
网络协议·http·arcgis
歪歪1003 小时前
如何在项目中选择使用HTTP还是WebSocket?
网络·websocket·网络协议·计算机网络·http·网络安全
小信丶8 小时前
Spring 6 的 @HttpExchange 注解:声明式 HTTP 客户端的现代化利器
java·spring·http
墨白曦煜8 小时前
HTTP首部字段(速查-全47种)
网络·网络协议·http
老坛程序员16 小时前
抓包解析MCP协议:基于JSON-RPC的MCP host与MCP server的交互
人工智能·网络协议·rpc·json·交互
歪歪10020 小时前
Http与WebSocket网络通信协议的对比
网络·websocket·网络协议·计算机网络·http·网络安全·信息与通信
粟悟饭&龟波功21 小时前
【网络安全】二、入门篇:HTTP 协议进阶 ——GET/POST 常用传参方法详解
安全·web安全·http
ZoeLandia1 天前
Vue 项目 JSON 在线编辑、校验如何选?
前端·vue.js·json
乐予吕1 天前
用 HTTP OPTIONS 发现 API 的隐藏能力
后端·http·api