目录
章节介绍:
之前已经和大家分享了SAP系统和MOM系统的整体设计,以及数据交互时系统的接口对接。上个章节重点讲的是RFC接口,当外围系统调用SAP的RFC接口时,SAP如何创建RFC接口、如何提供不同的参数结构文档给外围系统,这次我们来讲解另一种接口类型,RESTFUL接口类型,这也是SAP和外围系统对接时非常常用的接口类型。
因为本次项目中接口对接类型比较多,所以整个第二章节和大家分享SAP和MOM的接口对接时,我分成了三个内容来讲,分别是:
接口对接(上)------外围系统调用SAP的RFC接口,SAP如何创建RFC接口
接口对接(中)------外围系统调用SAP的RESTFUL接口,SAP如何创建restful接口
接口对接(下)------SAP调用外围系统的RESTFUL接口,SAP如何写代码调用
这次我们来讲【接口对接(中)------外围系统调用SAP的RESTFUL接口,SAP如何创建restful接口】
开发RESTFUL接口原因:
先来讲为什么我将这个接口做成了restful接口
如果大家有看我的前面几篇文章,就可以知道我在做这个项目时,时间是非常紧迫的,我优先选择的都是RFC接口,那为什么我偏偏将这个接口设计成了restful接口呢?答案就是参数类型问题。
两个系统需要传输的数据简化后如下:

在SAP系统中,这种关系的数据很多,AUFK和RESB表,EKKO和EKPO表,MSEG和MKPF表,都是可以通过A表的一个字段和B表做连接就可以获取对应关系。但是MOM系统反馈说,如果SAP返回两个表的话,MOM系统就不好处理两个表的数据,需要我这边将两个表放在一个表里面返回。因为我本身对JAVA不太熟悉,所以我没有什么可以提供的建议,那就开做吧。
MOM想要的SAP返回数据是像下面这种表结构:

放到SAP系统中,如下:

我们在RFC接口里面引用这个结构,在表参数里面,使用LIKE和TYPE都是不行的,分别是下面这样的报错:
LIKE:只能参考扁平结构

TYPE: RFC 中仅允许使用含扁平行结构的表

原因就是因为这个接口是远程RFC接口的话,RFC接口的表参数只能是扁平的结构类型,不能有下层的表展开

这时候,一种简单的处理方式,就是可以将表参数放到导出参数这里来,如下:

这时候,这个远程RFC接口是能够正常处理数据的,但是SAP系统会有一个警告:

警告是:T_TAB(类型 ZPPS0019)可削弱 RFC 中的性能(通过典型序列化)
总所周知,SAP系统中,警告约等于没警告,并且因为接口的数据没多少,我对这个接口的性能是不太在意的。
只不过我在使用POSTMAN测试的时候,发现了一个问题:如果像上面这样设置的话,SAP传出的数据是乱码(忘了保存截图了)。
所以我直接没让MOM开发接收数据测试了,我还是老老实实重新设计成RESTFUL接口吧。
开发RESTFUL接口步骤:
一、SE37开发接口
首先将接口设置成常规函数:

导入参数如下:

导出参数如下:

导入导出的参数设置都大差不差,就只是将远程RFC接口变成了常规函数。
二、SE24创建类
接下来构建类对象:

创建时的界面:

然后会让我们选择包,我们不放在本地包里面,因为我们之后要传到正式机的。
创建后如下:

接口使用IF_HTTP_EXTENSION

属性是自带的:

方法使用IF_HTTP_EXTENSION~HANDLE_REQUEST

方法的参数是SERVER

类型如下:

类型里面放的就可以理解为传入传出参数了,点进去看一下:

上面的设置对于每个restful接口的设计来说,都是大差不差基本一致的,就是类型那里需要设置成我们需要的样子就行。
接下来,我们点击方法,进入源代码,这里就是实现逻辑的地方:

代码如下,可以直接复制使用:
method IF_HTTP_EXTENSION~HANDLE_REQUEST.
DATA: ls_input TYPE ty_input.
DATA:T_TAB TYPE ZPPS0019.
TYPES:BEGIN OF TY_OUTPUT,
T_TAB TYPE ty_out,
E_TYPE TYPE BAPI_MTYPE,
E_MSEG TYPE BAPI_MSG,
END OF TY_OUTPUT.
DATA:LS_OUTPUT TYPE TY_OUTPUT,
ls_message TYPE uj0_s_message.
DATA: lv_verb TYPE string,
lv_json TYPE string.
DATA: lo_request TYPE REF TO if_http_request.
DATA: lt_fields TYPE tihttpnvp,
lv_data TYPE string.
FIELD-SYMBOLS: <fs_field> LIKE LINE OF lt_fields.
lo_request = server->request.
"Only handles Post method
lv_verb = lo_request->get_header_field( name = '~request_method' ).
"get HEADER fields
lo_request->get_header_fields( CHANGING fields = lt_fields ). "Header fields
"body
lv_data = lo_request->if_http_entity~get_cdata( ).
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN lv_data WITH space.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>horizontal_tab IN lv_data WITH space.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>vertical_tab IN lv_data WITH space.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline IN lv_data WITH space.
REPLACE ALL OCCURRENCES OF '#' IN lv_data WITH space.
TRY.
/ui2/cl_json=>deserialize(
EXPORTING
json = lv_data
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
CHANGING data = ls_input
).
* CATCH cx_root.
CATCH cx_root INTO DATA(lx_error).
" 更好的错误处理
ls_message-MSGTY = 'E'.
ls_message-message = lx_error->get_text( ).
ENDTRY.
CASE lv_verb.
WHEN 'POST'.
CALL FUNCTION 'ZPP_IMS_ORDERNEW1'
EXPORTING
I_WERKS = ls_input-i_werks
I_GLTRP = ls_input-i_gltrp
I_FEVOR = ls_input-i_fevor
I_TEMPS = ls_input-i_temps
I_TEMPE = ls_input-i_tempe
IMPORTING
E_TYPE = ls_output-e_type
E_MSEG = ls_output-e_mseg
T_TAB = T_TAB
.
" 如果没有数据,设置空表
IF T_TAB IS INITIAL.
CLEAR ls_output-t_tab.
ELSE.
APPEND LINES OF T_TAB TO ls_output-t_tab.
ENDIF.
WHEN OTHERS.
"如果不是get请求,则返回错误
server->response->set_status( code = 405 reason = '请使用POST方法' ).
RETURN.
ENDCASE.
***
try.
lv_json = /ui2/cl_json=>serialize(
data = ls_output
compress = abap_true
pretty_name = /ui2/cl_json=>pretty_mode-none
).
CATCH cx_root INTO lx_error.
" 序列化错误处理
lv_json = `{"error": "序列化输出失败"}`.
ENDTRY.
server->response->set_status( code = 200 reason = 'Ok' ).
server->response->set_content_type( 'application/json' ).
server->response->set_cdata( data = lv_json ).
endmethod.
这里有两个地方需要注意:
第一个地方就是我们需要在这里重新声明一下参数

第二个地方就是我们调用常规函数的地方是这里:

上面的代码写成这样也是可以的,反正就是这些参数在赋值嘛。

反正最后,返回参数最后起作用的语句是这个:

类里面检查没有语法报错后,就可以开始进行SICF服务配置了。
三、SICF服务配置
这一步是让我们的接口真正成为restful接口,步骤如下:
首先使用事务代码SICF进入下面这个界面:

右键点击这个sap,选择新的子元素

会弹出下面这个消息,不用管,点勾


在创建的时候像下面这样选择:

服务是管理服务,描述根据自己要求来设置
服务数据参数如下:

登录数据如下:

用户名和密码都一起配置上去,外围系统连接接口的时候就不需要输入密码和用户名
处理器清单这里就填写我们上一步使用SE24创建的那个类的名字

错误页的参数如下:

管理页如下:

配置完后进行保存,可以看到我们刚才创建的服务是灰色的,界面如下:

然后我们来激活这个服务,右键点击:

激活服务:

激活服务后,测试服务:

测试的界面如下:

四、POSTMAN调用接口
虽然提示的是该页面无法正常运作,但这是正常的,上面那个就是接口地址。我们直接在postman里面调用一下试试看。

好了,看来我们成功创建了sap系统的restful接口,真棒。
五、参数文档结构
再看一下接口参数文档吧:

结尾:
最后也是一些注意点:
1、 SAP的RFC接口和RESTFUL接口,他们对应的端口号一般是不一致的,如果接口联不通的话,这个要和BASIS顾问确认或者和公司网络管理的同事确认一下;
2、在配置服务时,那个用户名和参数也要设置完整,如果对方保存没权限的话,要设置权限高一点的账号,可以直接修改,不用包请求。
那么本章就结束啦,下一章我们接着讲解【接口对接(下)------SAP调用外围系统的RESTFUL接口,SAP如何写代码调用】