【SAP】SAP restful http 接口集中管理发布(SICF)

3 篇文章 0 订阅

引言

最近在项目上有做一些restful接口的需求,其中涉及到多个外围系统,就想着如何通过只发布一个服务,让个外围系统传入不同的报文,来决定动态的调用不同的业务处理程序,于是就有了这篇博客.

实现过程

跟外围系统定义报文格式的时候,确定了报文的总体格式,要求不管什么接口,总体格式不变。结构如下:

{
    "HEAD": {
        "TARGET_SYS": "SAP",
        "INTF_ID": "INT_FI001",
        "SOURCE_SYS": "OA"
    },
    "DATA":""
}

其中定义了两个固定格式,head与data,head中包含了接口的目标系统、源系统以及接口编号,data部分用于传输业务数据,结构与业务字段需根据实际确定。

确定好报文格式后,剩下来的只需要在SAP内处理了。代码如下:

METHOD if_rest_resource~post.
    DATA: lo_json   TYPE REF TO zcl_json_to_data,
          lo_object TYPE REF TO object,
          lo_infter TYPE REF TO zif_interface_http,
          lv_clname TYPE c LENGTH 30,
          ls_head   TYPE zsifheadinfo,
          ls_return TYPE bapiret2.
    DATA: lv_data TYPE REF TO data.
    
    "获取报文。
    DATA(lv_json) = mo_request->get_entity( )->get_string_data( ).
    
    "通过Json动态生成内部结构
    CREATE OBJECT lo_json.
    lo_json->deserialize_json_declare_main(
        EXPORTING
          iv_json = lv_json
        IMPORTING
          data    = lv_data ).

    IF lv_data IS BOUND.
      ASSIGN lv_data->* TO FIELD-SYMBOL(<fs_str>).
    ELSE.
      ls_return-message = '结构生成异常'.
      me->return_error( ls_return ).    
      RETURN.
    ENDIF.

    IF <fs_str> IS ASSIGNED..
      /ui2/cl_json=>deserialize(
         EXPORTING
             json = lv_json
         CHANGING
             data = <fs_str> ).
    ENDIF.

    IF <fs_str> IS INITIAL.
      ls_return-message = '数据解析异常'.
      me->return_error( ls_return ).
      RETURN.
    ENDIF.

    ASSIGN COMPONENT 'HEAD' OF STRUCTURE <fs_str> TO FIELD-SYMBOL(<fs_head>).
    IF sy-subrc NE 0 OR <fs_head> IS NOT ASSIGNED.
      ls_return-message = '数据解析异常:缺少HEAD数据'.
      me->return_error( ls_return ).
      RETURN.
    ELSE.
      MOVE-CORRESPONDING <fs_head> TO ls_head.
    ENDIF.

    ASSIGN COMPONENT 'DATA' OF STRUCTURE <fs_str> TO FIELD-SYMBOL(<fs_data>).
    IF sy-subrc NE 0 OR <fs_data> IS NOT ASSIGNED.
      ls_return-message = '数据解析异常:缺少DATA数据'.
      me->return_error( ls_return ).
      RETURN.
    ENDIF.
    
   "根据接口id确定业务实现类.
    SELECT SINGLE zfname INTO lv_clname
     FROM ztiftable
    WHERE intf_id  = ls_head-intf_id
      AND  zactive = 'X'
      AND  zinout  = 'I'.

    TRY.
        CREATE OBJECT lo_object TYPE (lv_clname)
          EXPORTING
            iv_head = ls_head
            iv_uuid = cl_system_uuid=>create_uuid_c36_static( ).

      CATCH cx_sy_create_object_error INTO DATA(cx_sy_create_object_error).
        ls_return-message = cx_sy_create_object_error->get_text( ).
        me->return_error( ls_return ).
        RETURN.
      CATCH cx_sy_dyn_call_illegal_method INTO DATA(cx_sy_dyn_call_illegal_method).
        ls_return-message = cx_sy_dyn_call_illegal_method->get_text( ).
        me->return_error( ls_return ).
        RETURN.
      CATCH cx_sy_dyn_call_illegal_type INTO DATA(cx_sy_dyn_call_illegal_type).
        ls_return-message = cx_sy_dyn_call_illegal_type->get_text( ).
        me->return_error( ls_return ).
        RETURN.
      CATCH cx_sy_dyn_call_param_not_found INTO DATA(cx_sy_dyn_call_param_not_found).
        ls_return-message = cx_sy_dyn_call_param_not_found->get_text( ).
        me->return_error( ls_return ).
        RETURN.
    ENDTRY.

    IF lo_object IS INSTANCE OF zif_interface_http.
      lo_infter ?= lo_object.
    ENDIF.

    IF lo_infter IS INITIAL.
        ls_return-message = '对象未引用接口类(zif_interface_http)'.
        me->return_error( ls_return ).      
      RETURN.
    ENDIF.

    DATA: re_data TYPE string,
          iv_data TYPE string.

    iv_data = /ui2/cl_json=>serialize( <fs_data> ).

    lo_infter->me_procrss_data(
        EXPORTING
          iv_data   = iv_data
       CHANGING
          re_data   = re_data
          re_return = ls_return ).

    IF re_data IS NOT INITIAL.
      mo_response->set_reason( 'ok' ).
      mo_response->set_status( 200 ).
      mo_response->create_entity( )->set_string_data( re_data ).
      mo_response->create_entity( )->set_content_type( if_rest_media_type=>gc_appl_json ).
    ELSE.
      me->return_error( ls_return ).
    ENDIF.
  ENDMETHOD.

以上代码的大致内容就是,通过接口传入的报文,生成对应的abap内部类型,进一步将报文转换为内表或结构体,从而根据HEAD与DATA字段来将其拆分处理,HEAD为接口相关数据,DATA为业务数据。之后通过接口编号找到对应的类名,实例化出一个对应的对象,后面如果lo_object是zif_interface_http接口的实例,则将其引用赋值给lo_infter变量,这样就可以利用lo_infter来调用zif_interface_http接口中定义的方法来进行业务处理,在处理之前将data数据执行了abap2json的转换,用于更方便传递内容。
以上内容涉及到一个类与一个接口,zcl_json_to_data类参考另一位大佬的项目,根据json生成abap对象,实际使用时有一些调整。接zif_interface_http的方法如下:

interface ZIF_INTERFACE_HTTP
  public .
  
  methods ME_PROCRSS_DATA
    importing
      !IV_DATA type STRING optional
      !IV_UUID type STRING optional
    changing
      value(RE_DATA) type STRING optional
      !RE_RETURN type BAPIRET2 optional .
  methods ME_CHECK_DATA
    changing
      value(RE_RETURN) type BAPIRET2 .
  methods ME_SAVE_DATA
    changing
      value(RE_RETURN) type BAPIRET2 .
  methods ME_CALL_BAPI
    changing
      value(RE_RETURN) type BAPIRET2 .
  methods ME_ABAP2JSON
    importing
      !IV_RETURN type BAPIRET2
    returning
      value(EV_DATA) type STRING .
  methods ME_JSON2DATA
    importing
      !IV_DATA type STRING optional
    changing
      value(RE_DATA) type DATA .
endinterface.

配置表中的业务处理类只有一个实例构造方法,其他方法引用接口。代码如下

  METHOD zif_interface_http~me_procrss_data.
    DATA lo_error TYPE REF TO cx_sy_dyn_call_illegal_method.
    TRY.
        me->zif_interface_http~me_json2data( EXPORTING iv_data = iv_data CHANGING re_data = me->mt_data ).

        me->zif_interface_http~me_check_data( CHANGING re_return = re_return ).

        me->zif_interface_http~me_call_bapi( CHANGING re_return = re_return ).

        me->zif_interface_http~me_save_data( CHANGING re_return = re_return  ).

        re_data = me->zif_interface_http~me_abap2json( EXPORTING iv_return = re_return ).

      CATCH cx_sy_dyn_call_illegal_method INTO lo_error.
        re_return-message = lo_error->if_message~get_text( ).
    ENDTRY.

  ENDMETHOD.

处理之后的响应报文由各不同的类传递出json对象,直接返回给发送方。

剩下的就是一个返回错误的方法,没什么好说的,返回一个400的报错.
PS:本博文的服务发布过程参考我的另一篇文章SAP 发布HTTP接口之完整的Restful 含( 含Token 验证)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值