目录
章节介绍:
一些前言:
接口调用:
参数定义:
一些结尾:
章节介绍:
之前已经和大家分享了SAP系统和MOM系统的整体设计,以及数据交互时系统的接口对接。上两个章节重点讲了RFC接口和RESTFUL接口,即当外围系统调用SAP的接口时,SAP如何创建RFC接口、如何创建RESTFUL接口、如何提供不同的参数文档给外围系统等等操作。前面呢都是基于外围系统调用SAP系统的方向来写的,既然是双方系统的数据交互,那肯定SAP也需要调用外围系统的接口,所以我们本章节就会展示,SAP开发者如何连接外围系统的API,或者说如何调用外围系统的RESTFUL接口。
因为本次项目中接口对接类型比较多,所以整个第二章节和大家分享SAP和MOM的接口对接时,我分成了三个内容来讲,分别是:
接口对接(上)——外围系统调用SAP的RFC接口,SAP如何创建RFC接口
接口对接(中)——外围系统调用SAP的RESTFUL接口,SAP如何创建restful接口
接口对接(下)——SAP调用外围系统的RESTFUL接口,SAP如何写代码调用
这次我们来讲第二章节的最后一部分内容【接口对接(下)——SAP调用外围系统的RESTFUL接口,SAP如何写代码调用】
一些前言:
在本次分析的内容里面呢,会着重讲解两部分,第一部分是接口的调用;第二部分是参数的定义。(因为每个外围接口的参数大都不一样,写上来也是仅供参考,所以我们先分析调用接口这部分的代码,这个是通用的)
接口调用:
老规矩,先来看看外围系统提供的接口文档:
首先是一些常规的说明,比如网络通信协议、请求方式、数据格式等等,一般长下面这样:

然后是针对本接口的一些参数数据:

因为是我们SAP系统去主动调用对方系统的接口,所以参数文档由对方系统提供,我们按照对方给的参数文档进行数据传输就可以了。
如下,开始写SAP的代码:
我先粘贴代码,等会儿分享代码的具体含义:
FUNCTION ZMM_IMS_POSTBACK.
*"———————————————————————-
*"*"本地接口:
*" EXPORTING
*" REFERENCE(E_TYPE) TYPE BAPI_MTYPE
*" REFERENCE(E_MSEG) TYPE BAPI_MSG
*" TABLES
*" T_DATA TYPE ZMMS0023
*"——————————————————————-
DATA LO_DATA TYPE REF TO DATA.
DATA LV_ECS_JSON_REQ TYPE STRING.
DATA: LV_ECS_JSON_RES TYPE STRING,
LV_URL TYPE STRING,
LV_MSG TYPE STRING,
LV_TYPE TYPE BAPI_MTYPE.
DATA GS_BACK TYPE ZMMS0028.
DATA GT_OUT_MAPPING TYPE /UI2/CL_JSON=>NAME_MAPPINGS.
DATA GT_BACK_MAPPING TYPE /UI2/CL_JSON=>NAME_MAPPINGS.
* 定义行结构
TYPES: BEGIN OF TY_ROW,
TRX_CODE TYPE CHAR30,
SCJD_SAP_POST_STAT TYPE CHAR1,
SCJD_SAP_RETURN_MSG TYPE CHAR200,
END OF TY_ROW.
TYPES: TY_ROWS TYPE STANDARD TABLE OF TY_ROW WITH DEFAULT KEY.
* 定义cur_pids结构(包含rows内表)
TYPES: BEGIN OF TY_CUR_PIDS,
ROWS TYPE TY_ROWS,
END OF TY_CUR_PIDS.
* ZMMS0023是details的行类型,这里直接使用
TYPES: TY_DETAILS TYPE STANDARD TABLE OF ZMMS0022 WITH DEFAULT KEY.
* 定义value结构(包含cur_pids对象和details内表)
TYPES: BEGIN OF TY_VALUE,
CUR_PIDS TYPE TY_CUR_PIDS,
DETAILS TYPE TY_DETAILS,
END OF TY_VALUE.
* 定义根结构
TYPES: BEGIN OF TY_OUT,
VALUE TYPE TY_VALUE,
END OF TY_OUT.
DATA: GS_OUT TYPE TY_OUT.
* 组装数据
LOOP AT T_DATA INTO DATA(LS_DATA).
APPEND INITIAL LINE TO GS_OUT-VALUE-CUR_PIDS-ROWS ASSIGNING FIELD-SYMBOL(<FS_ROW>).
<FS_ROW>-TRX_CODE = LS_DATA-PID1.
<FS_ROW>-SCJD_SAP_POST_STAT = COND #( WHEN LS_DATA-ZTYPE = 'S' THEN 'y' ELSE 'n' ).
<FS_ROW>-SCJD_SAP_RETURN_MSG = LS_DATA-ZMSEG.
ENDLOOP.
* 直接分配details内表
APPEND LINES OF T_DATA[] TO GS_OUT-VALUE-DETAILS.
*gs_out-value-details = t_data[].
LO_DATA = REF #( GS_OUT ).
IF LO_DATA IS NOT BOUND.
MACRO_SAVE_LOG_AFTER_PROC 'OUT'.
RETURN.
ENDIF.
* 获取接口地址:配置成后台表
SELECT SINGLE * FROM ZTXXURL
WHERE ZNAME = 'ZMM_IMS_POSTBACK'
AND SYSID = @SY-SYSID
INTO @DATA(LS_ZTXXURL).
IF LS_ZTXXURL-ZURL IS INITIAL.
E_TYPE = 'E'.
E_MSEG = '接口地址未配置,请到ZTXXURL表中配置接口地址'.
MACRO_SAVE_LOG_AFTER_PROC 'OUT'.
RETURN.
ENDIF.
LV_URL = CONV CHAR200( LS_ZTXXURL-ZURL ).
CONDENSE LV_URL NO-GAPS.
*设置JSON字符转换
GT_OUT_MAPPING = VALUE #(
( ABAP = 'VALUE' JSON = 'value' )
( ABAP = 'DETAILS' JSON = 'details' )
( ABAP = 'WERKS' JSON = 'werks' )
( ABAP = 'VBELN' JSON = 'vbeln')
( ABAP = 'POSNR' JSON = 'posnr')
( ABAP = 'PID1' JSON = 'pid1')
( ABAP = 'TEXT' JSON = 'text')
( ABAP = 'BUDAT' JSON = 'budat')
( ABAP = 'CUR_PIDS' JSON = 'cur_pids')
( ABAP = 'ROWS' JSON = 'rows')
( ABAP = 'TRX_CODE' JSON = 'trx_code')
( ABAP = 'SCJD_SAP_POST_STAT' JSON = 'scjd_sap_post_stat')
( ABAP = 'SCJD_SAP_RETURN_MSG' JSON = 'scjd_sap_return_msg')
).
GT_BACK_MAPPING = VALUE #(
( ABAP = 'CODE' JSON = 'code')
( ABAP = 'MESSAGE' JSON = 'message')
).
*将ABAP数据转换为JSON格式
CALL METHOD /UI2/CL_JSON=>SERIALIZE
EXPORTING
DATA = LO_DATA
* COMPRESS = 'X'
PRETTY_NAME = /UI2/CL_JSON=>PRETTY_MODE-LOW_CASE
NAME_MAPPINGS = GT_OUT_MAPPING
RECEIVING
R_JSON = LV_ECS_JSON_REQ.
*创建CLIENT
DATA:LO_HTTP_CLIENT TYPE REF TO IF_HTTP_CLIENT.
DATA L_RESP TYPE STRING.
DATA:TT_HEADFIELD TYPE TIHTTPNVP .
CALL METHOD CL_HTTP_CLIENT=>CREATE_BY_URL
EXPORTING
URL = LV_URL "API
IMPORTING
CLIENT = LO_HTTP_CLIENT
EXCEPTIONS
ARGUMENT_NOT_FOUND = 1
PLUGIN_NOT_ACTIVE = 2
INTERNAL_ERROR = 3
OTHERS = 4.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4 INTO E_MSEG.
E_MSEG = '创建client错误,错误信息: ' && E_MSEG.
E_TYPE = 'E'.
RETURN.
ENDIF.
LO_HTTP_CLIENT->REQUEST->SET_METHOD('POST').
CALL METHOD LO_HTTP_CLIENT->REQUEST->IF_HTTP_ENTITY~SET_HEADER_FIELD
EXPORTING
NAME = 'Content-Type'
VALUE = 'application/json'.
IF TT_HEADFIELD[] IS NOT INITIAL.
CALL METHOD LO_HTTP_CLIENT->REQUEST->IF_HTTP_ENTITY~SET_HEADER_FIELDS
EXPORTING
FIELDS = TT_HEADFIELD[].
ENDIF.
CALL METHOD LO_HTTP_CLIENT->REQUEST->SET_HEADER_FIELD
EXPORTING
NAME = '~server_protocol'
VALUE = 'HTTP/1.1'.
IF LV_ECS_JSON_REQ IS NOT INITIAL.
DATA(L_CONTEN_LEN) = STRLEN( LV_ECS_JSON_REQ ).
CALL METHOD LO_HTTP_CLIENT->REQUEST->IF_HTTP_ENTITY~SET_CDATA
EXPORTING
DATA = LV_ECS_JSON_REQ
OFFSET = 0
LENGTH = L_CONTEN_LEN.
ENDIF.
*发送请求
CALL METHOD LO_HTTP_CLIENT->SEND
EXPORTING
TIMEOUT = 300
EXCEPTIONS
HTTP_COMMUNICATION_FAILURE = 1
HTTP_INVALID_STATE = 2
HTTP_PROCESSING_FAILED = 3
HTTP_INVALID_TIMEOUT = 4
OTHERS = 5.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4 INTO E_MSEG.
E_MSEG = '发送请求错误,错误信息: ' && E_MSEG.
E_TYPE = 'E'.
CALL METHOD LO_HTTP_CLIENT->CLOSE.
RETURN.
ENDIF.
*返回请求
CALL METHOD LO_HTTP_CLIENT->RECEIVE
EXCEPTIONS
HTTP_COMMUNICATION_FAILURE = 1
HTTP_INVALID_STATE = 2
HTTP_PROCESSING_FAILED = 3
OTHERS = 4.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4 INTO E_MSEG.
E_MSEG = '返回请求错误,错误信息: ' && E_MSEG.
E_TYPE = 'E'.
CALL METHOD LO_HTTP_CLIENT->CLOSE.
RETURN.
ENDIF.
*转换后的JSON字符串赋值
CALL METHOD LO_HTTP_CLIENT->RESPONSE->IF_HTTP_ENTITY~GET_CDATA
RECEIVING
DATA = L_RESP.
LV_ECS_JSON_RES = L_RESP.
*关闭请求
CALL METHOD LO_HTTP_CLIENT->CLOSE.
*读取远程服务器返回的处理结果
LO_DATA = REF #( GS_BACK ).
CALL METHOD /UI2/CL_JSON=>DESERIALIZE
EXPORTING
JSON = LV_ECS_JSON_RES
NAME_MAPPINGS = GT_BACK_MAPPING
CHANGING
DATA = LO_DATA.
* SEARCH LV_ECS_JSON_RES FOR 'false'.
IF GS_BACK-CODE = '0'.
E_TYPE = 'S'.
ELSE.
E_TYPE = 'E'.
ENDIF.
E_MSEG = GS_BACK-MESSAGE.
ENDFUNCTION.
当我们调用外围接口时,其实不需要把我们的程序写成一个接口的样子,但是为了方便,我这里也把调用外围系统的代码封装成了接口,写代码的时候不需要完全和我一样,仅供参考。SAP调用外围API时用的都是这样的一些代码一些结构。
参数定义:
终于到了参数定义定义的专题环节
我用这个接口代码做案例的原因是,它比较特殊,参数结构一层嵌套一层的,有一定的参考意义:

从上面绿色框框可以看出,结构真的是一层嵌套一层,在SAP中这种结构是比较少见了。在SAP里面应该如何定义呢?
看我定义的结构:
* 定义行结构
TYPES: BEGIN OF TY_ROW,
TRX_CODE TYPE CHAR30,
SCJD_SAP_POST_STAT TYPE CHAR1,
SCJD_SAP_RETURN_MSG TYPE CHAR200,
END OF TY_ROW.
TYPES: TY_ROWS TYPE STANDARD TABLE OF TY_ROW WITH DEFAULT KEY.
* 定义cur_pids结构(包含rows内表)
TYPES: BEGIN OF TY_CUR_PIDS,
ROWS TYPE TY_ROWS,
END OF TY_CUR_PIDS.
* ZMMS0023是details的行类型,这里直接使用
TYPES: TY_DETAILS TYPE STANDARD TABLE OF ZMMS0022 WITH DEFAULT KEY.
* 定义value结构(包含cur_pids对象和details内表)
TYPES: BEGIN OF TY_VALUE,
CUR_PIDS TYPE TY_CUR_PIDS,
DETAILS TYPE TY_DETAILS,
END OF TY_VALUE.
* 定义根结构
TYPES: BEGIN OF TY_OUT,
VALUE TYPE TY_VALUE,
END OF TY_OUT.
DATA: GS_OUT TYPE TY_OUT.
这里面有引用了一个自定义的结构类型:ZMMS0022,我截图给大家看一下

总结来说就是:一层一层,由内到外,逐步向上进行定义。
可能大家看到我定义的这个结构,有点疑惑哈,怎么还有一个detail的结构呢?
因为乙方只接受它那边的字段,SAP这边的单据号、行号、公司代码等等重要的字段,它不接收,让我自己随便加字段就好了。SAP和我们公司自己配置的中间日志库的传输日志里面可以记录这些字段,但是乙方它的系统不记录也不做任何处理。好了这就是DETAIL的来历。下面截图中,绿色的框里就是我自己加的参数,没有在乙方的参数文档里面:

好了,这个案例复杂的地方就在定义参数结构这里,接口基础,参数就不基础…
一些结尾:
接口的上、中、下终于都完结了,这个文章是我在春节期间写的,开工后因为项目上线好多问题,最近又又又很忙,没有时间修改润色,我自己都明显感觉到这篇文章写得没有前面两篇好,只能说仅供参考吧,反正这些代码都是万变不离其宗嘛。
之前小白开发手册里面,第九章也是讲解的这个部分,所以也算是一个CALL BACK了
【小白开发手册】
接下来,本栏目第三章会讲解一些项目中的增强知识点、BAPI、小巧思等等,请浅浅期待一下。
对了,别翘二郎腿,我已经脊柱侧弯了,大家照顾好自己的身体,工作是做不完的,要休息!!多休息多锻炼,新的一年祝各位身体健康吧!
网硕互联帮助中心





评论前必须登录!
注册