【ABAP】使用 SICF 发布可配置 Restful 接口
2026/5/30 3:44:50 网站建设 项目流程

一、前言

在 SAP 系统与外部系统对接场景中,RESTful 接口是数据交互的常用方案。传统接口往往需要针对性编码,新增业务对接需求时改动繁琐、复用性差。
本文介绍基于 SICF 实现的可配置 RESTful 接口方案。该框架搭建完成后,后续开发无需修改接口底层代码,只需编写对应业务 RFC 函数,并在自定义配置表中维护请求 ID 与目标函数的映射关系,就能快速实现数据对接与接口访问。整体方案上手简单、使用便捷,能极大提升接口开发与迭代效率。

二、方案介绍

2.1 实现思路

基于 SAP 原生 HTTP 服务 SICF + 标准接口 IF_HTTP_EXTENSION 实现 RESTful 风格接口。

通过自定义配置表 ZCAT004 做路由映射:

外部传入唯一请求标识 REQKEYID → 系统自动匹配对应 RFC 函数 → 动态调用函数并返回 JSON 结果。

2.2 整体调用流程

外部 POST 请求 → SICF 服务节点 → HANDLE_REQUEST 入口 → 解析 JSON 获取 REQKEYID → 查询 ZCAT004 匹配 RFC 函数 → 动态组装参数 → 动态调用函数 → 结果序列化 JSON 返回。

三、配置步骤

3.1 创建配置表 ZCAT004

主要用于存储请求ID — RFC函数名 映射关系,实现接口路由可配置化。其余字段大家也可以按照业务需求自行添加。

a. 进入 SE11,输入需要创建的表名 ZCAT004,点击创建

b. 在字段页签中添加如下字段,数据元素可以按照图中的数据类型自行定义。接口唯一ID和功能模块两个字段注意不要修改,后续 SICF 服务中会用到

字段

关键

字段

初始值数据元素

数据

类型

长度简短描述
MANDTMANDTCLNT3客户端
REQKEYIDZE_REQKEYIDCHAR40接口唯一ID
FUNCNAMERS38L_FNAMCHAR30功能模块的名称
WORKFLOWIDZE_WORKFLOWIDCHAR10OA流程id
TITLEZE_TITLECHAR40OA流程描述
URLZE_URLCHAR255接口地址
ZCRDATE7ERNAMCHAR12负责创建对象的人员姓名

3.2 创建 HTTP 处理类 ZCL_HTTP

实现标准接口:IF_HTTP_EXTENSION

a. 创建类名称

进入 SE24,输入 ZCL_HTTP,点击创建

b. 实现接口 IF_HTTP_EXTENSION

c. 添加系统函数调用方法 CALL_FUNCTION

这个方法的主要作用是接收前端传入的 JSON 请求 → 自动根据配置动态调用对应的 SAP 后台函数 → 把函数执行结果转回 JSON 返回给前端

为方法定义参数:

方法内容(直接复制可复用)

METHOD call_function. DATA: ptab TYPE abap_func_parmbind_tab, ptab_line TYPE abap_func_parmbind, etab TYPE abap_func_excpbind_tab, etab_line TYPE abap_func_excpbind, data_export TYPE REF TO data, data_ref TYPE REF TO data, * lt_mapping TYPE name_mappings, lv_response_json TYPE string. "接口返回参数 DATA: dyn_table TYPE REF TO data. DATA: lt_dd04l TYPE STANDARD TABLE OF dd04l. DATA:lv_error_msg TYPE bapi_msg. "JSON格式化 DATA(json_data) = /ui2/cl_json=>generate( json = json )."name_mappings = lt_mapping ). ASSIGN json_data->* TO FIELD-SYMBOL(<json_data>). IF <json_data> IS ASSIGNED. ASSIGN COMPONENT 'IS_REQ' OF STRUCTURE <json_data> TO FIELD-SYMBOL(<fs_req>). IF <fs_req> IS ASSIGNED. ASSIGN COMPONENT 'REQKEYID' OF STRUCTURE <fs_req>->* TO FIELD-SYMBOL(<fv_reqkeyid>). IF <fv_reqkeyid> IS ASSIGNED. DATA(lv_reqkeyid) = CONV /zyb/sappo_keyid( <fv_reqkeyid>->* ). "CHAR 40 ENDIF. ENDIF. ENDIF. SELECT fupararef~funcname, fupararef~paramtype, fupararef~pposition, fupararef~parameter, fupararef~structure FROM fupararef AS fupararef INNER JOIN zcat004 AS zcat004 ON zcat004~funcname = fupararef~funcname WHERE zcat004~reqkeyid = @lv_reqkeyid INTO TABLE @DATA(parameters_tab). IF sy-subrc <> 0. code = '400'. reason = 'target_function no exist'. EXIT. ENDIF. TRY. "函数入参动态拼接 LOOP AT parameters_tab ASSIGNING FIELD-SYMBOL(<parameter>). CLEAR ptab_line. ptab_line-name = <parameter>-parameter. ptab_line-kind = COND #( WHEN <parameter>-paramtype = 'E' THEN abap_func_importing WHEN <parameter>-paramtype = 'I' THEN abap_func_exporting WHEN <parameter>-paramtype = 'T' THEN abap_func_tables WHEN <parameter>-paramtype = 'C' THEN abap_func_changing ELSE '' ). DATA(json_field_name) = COND string( WHEN ptab_line-kind = abap_func_exporting THEN 'IMPORT' WHEN ptab_line-kind = abap_func_tables THEN 'TABLE' WHEN ptab_line-kind = abap_func_changing THEN 'CHANGE' WHEN ptab_line-kind = abap_func_importing THEN 'EXPORT' ELSE '' ). DATA(lv_parameter) = <parameter>-parameter. "根据函数的入参匹配接口传入参数 ASSIGN COMPONENT lv_parameter OF STRUCTURE <json_data> TO FIELD-SYMBOL(<parameter_val>). IF sy-subrc <> 0 OR json_field_name = 'EXPORT'. CASE json_field_name. WHEN 'TABLE'. "创建动态表结构 CREATE DATA dyn_table TYPE TABLE OF (<parameter>-structure). "创建动态内表 ASSIGN dyn_table->* TO FIELD-SYMBOL(<dyn_table>). GET REFERENCE OF <dyn_table> INTO ptab_line-value. INSERT ptab_line INTO TABLE ptab. CONTINUE. WHEN OTHERS. "动态定义承接返回参数的结构 CREATE DATA data_export TYPE (<parameter>-structure). ASSIGN data_export TO FIELD-SYMBOL(<data_export>). ptab_line-value = <data_export>. INSERT ptab_line INTO TABLE ptab. CONTINUE. ENDCASE. ENDIF. IF json_field_name EQ 'TABLE'. CREATE DATA data_ref TYPE TABLE OF (<parameter>-structure). ELSE. CREATE DATA data_ref TYPE (<parameter>-structure)."如果是表类型,参考的是结构,是不是有问题呢 ENDIF. FIELD-SYMBOLS: <temp> TYPE any. ASSIGN <parameter_val>->* TO <temp>. IF data_ref IS BOUND. ASSIGN data_ref->* TO FIELD-SYMBOL(<data_ref>). ENDIF. "将传入参数按照特定格式转换 DATA(json_temp) = /ui2/cl_json=>serialize( data = <parameter_val> ). /ui2/cl_json=>deserialize( EXPORTING json = json_temp CHANGING data = <data_ref> )."name_mappings = lt_mapping GET REFERENCE OF <data_ref> INTO ptab_line-value. INSERT ptab_line INTO TABLE ptab. ENDLOOP. CATCH cx_root. ENDTRY. etab_line-name = 'OTHERS'. etab_line-value = 10. INSERT etab_line INTO TABLE etab. TRY. READ TABLE parameters_tab INTO DATA(ls_parameters_tab) INDEX 1. "动态调用函数,业务逻辑部分 CALL FUNCTION ls_parameters_tab-funcname PARAMETER-TABLE ptab EXCEPTION-TABLE etab. SORT parameters_tab BY parameter. CLEAR:data_ref. UNASSIGN:<data_ref>. LOOP AT ptab INTO ptab_line WHERE kind = abap_func_importing."只返回导出的数据 ASSIGN ptab_line-value->* TO <data_ref>. "Serialize Data to Json DATA(lv_string) = /ui2/cl_json=>serialize( data = <data_ref> )."name_mappings = lt_mapping lv_parameter = ptab_line-name. IF lv_response_json IS INITIAL. lv_response_json = |"{ lv_parameter }":{ lv_string }|. ELSE. lv_response_json = |{ lv_response_json },"{ lv_parameter }":{ lv_string }|. ENDIF. ENDLOOP. lv_response_json = '{' && lv_response_json && '}'. ev_response_json = lv_response_json. code = '200'. 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. ENDMETHOD.
d. 编写接口的唯一入口

上面创建的 call_function 是核心业务逻辑,而这段handle_request 是整个 HTTP 接口的唯一入口,也是SAP标准Web接口的固定入口方法。所有前端/第三方发来的HTTP请求,都会先进入这个方法,再转发给动态函数调用逻辑

双击 IF_HTTP_EXTENSION~HANDLE_REQUEST 方法

编写代码(直接复制可复用)

METHOD if_http_extension~handle_request. DATA: lv_string TYPE string, "传入和传出JSON格式数据所用到的变量 lv_json_req TYPE string, "传入和传出JSON格式数据所用到的变量 lv_json_res TYPE string, "传入和传出JSON格式数据所用到的变量 lv_function TYPE string. **------获取调用时候传入的参数 * CLEAR:lt_request. lv_string = server->request->get_cdata( ). "获取传入的数据 "JSON序列化 * DATA(json) = /ui2/cl_json=>serialize( data = lv_string * compress = 'X' * pretty_name = /ui2/cl_json=>pretty_mode-camel_case ). * lv_function = server->request->get_header_field( 'FUCTION_NAME' )."这里的值是约定的function名称(HEADER参数) * IF lv_function IS INITIAL. * lv_function = server->request->get_form_field( 'FUCTION_NAME' )."这里的值是约定的function名称(FPRM-DATA参数) * ENDIF. * lv_json_res = '{"code":"S","MESSAGE":"成功"}'. *———————动态调用rfc函数---------------* me->call_function( EXPORTING json = lv_string IMPORTING ev_response_json = lv_json_res code = DATA(code) reason = DATA(reason) ). *------设置返回数据格式为JSON CALL METHOD server->response->if_http_entity~set_content_type EXPORTING content_type = 'application/json'. *------设置返回数据 server->response->set_cdata( EXPORTING data = lv_json_res " Character data ). server->response->set_status( code = code reason = reason ). ENDMETHOD.

3.3 发布服务

a. 创建子元素

输入事务代码 SICF,按回车随后点击执行,在 /default_host/sap/ 目录下右击 sap,选择新的子元素,这里我命名成 ZHTTP

b. 配置处理器清单 ZCL_HTTP

填写刚才创建的 ZCL_HTTP 类,点击保存

c. 激活服务

回到菜单栏,右击 ZHTTP 子元素,选择激活服务

四、测试服务

4.1 在 ZCAT004 表添加映射规则

维护 REQKEYID 和 FUNCNAME 的对应关系:

4.2 编写函数模块

进入 SE37 编写功能函数模块,这里我写了一个简单的库存查询函数 ZMMFM045 ,可以按照工厂、物料编码、批次、库存地点以及货位等维度查询库存并以内表形式返回。代码略。。。。

4.3 使用 postman 测试

这里 SAP 的鉴权方式使用 Basic Auth 的方式即可访问接口。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询