ABAP Odata Service
1.What's Odata Service
OData (Open Data Protocol)是OASIS标准,其定义了基于HTTP的,用于构建和使用RESTful API的协议。
相关链接:
https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=odata
https://www.odata.org/
https://github.com/SAP/C4CODATAAPIDEVGUIDE
https://blogs.sap.com/2023/03/26/implementing-all-odata-query-uri-options-part-1/
https://blogs.sap.com/2023/03/26/implementing-all-odata-query-uri-options-part-2/
https://blogs.sap.com/2020/08/05/odata-batch-processing-part-1/
https://blogs.sap.com/2020/08/06/odata-batch-processing-part-2/
https://blogs.sap.com/2020/08/19/batch-call-processing-in-sap-netweaver-gateway/
https://blogs.sap.com/2014/09/23/file-uploaddownload-through-netweaver-gateway/
https://blogs.sap.com/2021/05/19/a-step-by-step-process-to-post-odata-services-in-sap-sap-hana-system/
相关Tcode:
SEGW:SAP Gateway Service Builder
/IWFND/TRACES:SAP Gateway:Tracing Tools
/IWFND/STATS:SAP Gateway Statistics
/IWFND/MAINT_SERVICE:Activate and Maintain Service
/IWFND/GW_CLIENT:SAP Gateway Client
2.Create a SAP Gateway Service
SAP Gateway Service Builder
Tcode:SEGW,SAP Gateway Service Builder
1.选择Create Service
2.选择Data Model->Import->DDIC Structure;
通过ABAP DDIC字典中Table,Structure创建工作区,结构表;
3.指定创建的Entity Type,默认勾选Create Default Entity Set,这里Entity Set相当于工作表,Entity Type相当于工作区;
4.选择需要使用到的栏位;
5.指定那些栏位是key值;
6.选择Entity Types,点击Properties,指定每个字段设置;
7.点击Generate Runtime Objects;
8.重写Create,Delete,GetEntity(Read),GetEntitySet(Query),Update方法;
Generate生成对应类可以在Runtime Artifacts中看到;
选择要Redefine的方法,右键->Go to ABAP WorkBench;
对应重写方法代码,需要结合URL请求。
Tcode:/IWFND/MAINT_SERVICE
注意:如果开启不了,提示User no longer logged on,选择/n/IWFND/MAINT_SERVICE执行Tcode;
激活和维护SAP Gateway Service;
如果新建Service,需要点击Add Service,将创建的Service添加,<Service名称>_SRV;
点击SAP Gateway Client,跳转到SAP Gateway Client测试URL请求;
注意:如果跳转不了那么可以选择导航栏,Goto->SAP GW Client;
Tcode: /IWFND/GW_CLIENT
可以直接打开SAP Gateway Client;
注意:如果开启不了,提示User no longer logged on,选择/n方式执行Tcode;
默认返回XML格式数据;
2.1URL Query Option
$batch:执行HTTP POST查询,创建,更新和删除多笔记录;
$format:指定返回数据格式,示例:/EntitySet?$format=json;
$count:返回EntitySet记录数,示例:/EntitySet/$count;
$orderby:排序记录,示例:/EntitySet?$orderby=date desc,time asc;
search:指定查询条件,示例:/EntitySet?search='test';
$select:指定查询栏位,示例:/EntitySet?$select=name,test;
$filter:筛选指定记录,实例:/Entityset?$filter=date eq '20020102' and name eq 'jim';
$top:返回top记录,示例:/EntitySet?$top=10;
$skip:指定跳过指定数量记录,示例:/Entityset?$skip=10;
$inlinecount:返回EntitySet记录数,示例: /EntitySet?$top=10&$inlinecount=allpages;
通过ABAP Code获取对应值;
示例:
"获取URL参数
* DATA:lv_top TYPE string.
* DATA:lv_skip TYPE string.
* DATA:lv_search TYPE string.
* DATA:lv_orderby TYPE /iwbep/t_mgw_tech_order.
* DATA:lv_select TYPE /iwbep/t_mgw_tech_field_names.
* DATA:lv_filter TYPE REF TO /iwbep/if_mgw_req_filter.
* DATA:lv_select_option TYPE /iwbep/t_mgw_select_option.
* DATA:lv_select_string TYPE string.
* "获取$top字符串
* lv_top = io_tech_request_context->get_top( ).
* "获取$skip字符串
* lv_skip = io_tech_request_context->get_skip( ).
* "获取?search字符串
* lv_search = io_tech_request_context->get_search_string( ).
* "获取$order by
* lv_orderby = io_tech_request_context->get_orderby( ).
* "获取$select
* lv_select = io_tech_request_context->get_select( ).
* "获取$filter
* lv_filter = io_tech_request_context->get_filter( ).
* lv_select_option = lv_filter->get_filter_select_options( ).
* lv_select_string = lv_filter->get_filter_string( ).
* "获取keys table
* "lt_key_tab = io_tech_request_context->get_keys( ).
2.2Get EntitySet
获取数据集,调用GET_ENTITYSET方法;
URL:/sap/opu/odata/ZTOM_GS1_SRV/ZT_SFLIGHTSet;
重写GET_ENTITYSET方法;
示例:ZT_SFLIGHTSET_GET_ENTITYSET方法;
method ZT_SFLIGHTSET_GET_ENTITYSET.
"查询所有数据
SELECT * INTO CORRESPONDING FIELDS OF TABLE et_entityset
FROM ztom_sflight.
endmethod.
2.3Get Entity
获取指定key值条件记录,调用GET_ENTITY方法;
URL:/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet(Carrid='AA',Connid='0017',Fldate=datetime'2022-11-17T00%3A00%3A00');
注意:当使用这种方式访问资源时,必须指定每个key的值,不能只放Carrid某一个key值;
这里key值栏位必须和定义Properties中一致,通常首字母大写,其余小写;
重写GET_ENTITY方法;
示例:ZT_SFLIGHTSET_GET_ENTITY方法
method ZT_SFLIGHTSET_GET_ENTITY.
"input parameter
DATA:lv_entity_name TYPE string.
DATA:lv_entity_set_name TYPE string.
DATA:lv_source_name TYPE string.
"(key=value,key2=value2)
DATA:lt_key_tab TYPE /iwbep/t_mgw_name_value_pair.
DATA:ls_key_tab LIKE LINE OF lt_key_tab.
DATA:lo_request_object TYPE REF TO /iwbep/if_mgw_req_entity.
DATA:lo_tech_request_context TYPE REF TO /iwbep/if_mgw_req_entity.
DATA:lt_navigation_path TYPE /iwbep/t_mgw_navigation_path.
"动态where
DATA:lt_where TYPE TABLE OF string.
DATA:ls_where LIKE LINE OF lt_where.
lv_entity_name = iv_entity_name.
lv_entity_set_name = iv_entity_set_name.
lv_source_name = iv_source_name.
lt_key_tab = it_key_tab.
lo_request_object = io_request_object.
lo_tech_request_context = io_tech_request_context.
lt_navigation_path = it_navigation_path.
"key参数
LOOP AT lt_key_tab INTO ls_key_tab.
IF sy-tabix = 1.
CLEAR ls_where.
ls_where = ls_key_tab-name && ' = ''' && ls_key_tab-value && ''''.
APPEND ls_where TO lt_where.
ELSE.
CLEAR ls_where.
ls_where = `AND ` && ls_key_tab-name && ' = ''' && ls_key_tab-value && ''''.
APPEND ls_where TO lt_where.
ENDIF.
ENDLOOP.
IF lt_key_tab IS NOT INITIAL.
SELECT SINGLE * INTO CORRESPONDING FIELDS OF er_entity
FROM ztom_sflight
WHERE (lt_where).
ELSE.
SELECT SINGLE * INTO CORRESPONDING FIELDS OF er_entity
FROM ztom_sflight.
ENDIF.
endmethod.
2.4Get EntitySet,指定$filter
筛选指定条件记录,调用GET_ENTITYSET方法;
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=Carrid eq 'AA' and Connid eq '0017'&$format=json;
filter条件:
eq | is equal |
ne | is not equal |
gt | is greater than |
ge | is greater than or equal |
lt | is less than |
le | is less than or equal |
'&'是特殊字符可以使用%26替换;
'#'是特殊字符可以使用%23替换;
Error URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=Planetype eq '747#400' &$format=json;
Success URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=Planetype eq '747%23400' &$format=json;
filter支持字符Function:
URL:/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=substringof('747',Planetype)&$format=json;
支持语法:substringof('747-100',Planetype);
转换后where语句:( PLANETYPE like '%747%' )
URL:/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=startswith(Planetype,'747')&$format=json
支持语法:startswith(Planetype,'747')
转换后where语句: ( PLANETYPE like '747%' )
重写GET_ENTITYSET方法
示例:ZT_SFLIGHTSET_GET_ENTITYSET方法;
"获取$filter
DATA:lv_filter_string TYPE string.
lv_filter_string = io_tech_request_context->get_filter( )->get_filter_string( ).
IF lv_filter_string IS NOT INITIAL.
"方式1:根据筛选器查询数据
* SELECT * INTO CORRESPONDING FIELDS OF TABLE et_entityset
* FROM ztom_sflight
* WHERE (lv_filter_string).
"方式2:使用util方法筛选
"需要先查询所有数据
SELECT * INTO CORRESPONDING FIELDS OF TABLE et_entityset
FROM ztom_sflight.
/iwbep/cl_mgw_data_util=>filtering(
EXPORTING
it_select_options = it_filter_select_options
CHANGING
ct_data = et_entityset
).
ELSE.
"查询所有数据
SELECT * INTO CORRESPONDING FIELDS OF TABLE et_entityset
FROM ztom_sflight.
ENDIF.
2.5Get EntitySet,指定$orderby
指定排序,调用GET_ENTITYSET方法;
URL:/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$orderby=Carrid desc,Connid asc&$format=json;
重写GET_ENTITYSET方法
示例:ZT_SFLIGHTSET_GET_ENTITYSET方法;
不需要转换,直接使用传入it_order参数类型;
"获取$orderby
DATA:lt_orderby TYPE /iwbep/t_mgw_tech_order.
lt_orderby = io_tech_request_context->get_orderby( ).
"排序
/iwbep/cl_mgw_data_util=>orderby(
EXPORTING
it_order = it_order
CHANGING
ct_data = et_entityset
).
动态Sort代码
示例:
DATA: lt_otab TYPE abap_sortorder_tab,
ls_oline TYPE abap_sortorder.
DATA: ls_order LIKE LINE OF it_order.
LOOP AT it_order INTO ls_order.
ls_oline-name = ls_order-property.
TRANSLATE ls_oline-name TO UPPER CASE. "#EC TRANSLANG
IF ls_order-order = gcs_sorting_order-descending.
ls_oline-descending = 'X'.
ENDIF.
APPEND ls_oline TO lt_otab.
CLEAR ls_oline.
ENDLOOP.
SORT ct_data BY (lt_otab).
2.6Get EntitySet,指定$top,$skip
获取top笔数记录,skip排除指定记录数,调用GET_ENTITYSET方法;
URL:/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$top=5&$skip=10&$format=json;
重写GET_ENTITYSET方法
示例:ZT_SFLIGHTSET_GET_ENTITYSET方法;
"获取$top,$skip
"paging方法,先skip,后取top记录
DATA:lv_top TYPE string.
DATA:lv_skip TYPE string.
"获取$top字符串
lv_top = io_tech_request_context->get_top( ).
"获取$skip字符串
lv_skip = io_tech_request_context->get_skip( ).
"直接调用方式实现paging
/iwbep/cl_mgw_data_util=>paging(
EXPORTING
is_paging = is_paging
CHANGING
ct_data = et_entityset
).
2.7Get EntitySet,指定$inlinecount
返回符合条件记录数,调用GET_ENTITYSET方法;
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=Carrid eq 'AA'&$inlinecount=allpages&$format=json;
返回结果会有count的值;
重写GET_ENTITYSET方法
示例:ZT_SFLIGHTSET_GET_ENTITYSET方法;
"获取$inlinecount
IF io_tech_request_context->has_inlinecount( ) = abap_true.
"获取符合条件总记录数
DESCRIBE TABLE et_entityset LINES DATA(lv_lines).
es_response_context-inlinecount = lv_lines.
ENDIF.
2.8Get EntitySet,指定$count
获取EntitySet记录笔数,调用GET_ENTITYSET方法;
正确URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet/$count?$filter=Carrid eq 'AA'
错误URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet/$count?$filter=Carrid eq 'AA'&$format=json;
Error: "System query options '$expand,$format,$skiptoken,$inlinecount,$select' are not allowed in the requested URI"
$format和$count不能同时存在;
2.9Get EntitySet,指定$select
查询指定栏位,调用GET_ENTITYSET方法;
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=Carrid eq 'AA'&$select=Carrid,Connid&$format=json;
示例:只查询Carrid,Connid栏位;
2.10Get EntitySet,指定$format
指定返回格式,调用GET_ENTITYSET方法;
默认返回XML格式;
URL:/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=Carrid eq 'AA'&$format=json;
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet?$filter=Carrid eq 'AA'&$format=xml;
2.11Get Entity,指定$value
返回指定栏位值,调用GET_ENTITY方法;
URL:/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SFLIGHTSet(Carrid='AA',Connid='0017',Fldate=datetime'2023-07-31T00%3A00%3A00')/Price/$value;
2.12Get EntitySet,指定$expand,$links
展开association栏位,调用GET_ENTITYSET方法;
创建一个新的Entity Type,Entity Set;
ZT_SCARR包含CARRID,CARRNAME,URL等属性;
创建Associations;
这种从SFLIGHT作为起点,需要指定SFLIGHT key值对应的栏位,无法实现;
从SCARR作为起点,指定SCARR key值CARRID对应SFLIGHT的CARRID;
同样重写SCARR的GET_ENTITY方法;
示例:
method ZT_SCARRSET_GET_ENTITY.
"动态where
DATA:lt_where TYPE TABLE OF string.
DATA:ls_where LIKE LINE OF lt_where.
DATA:ls_key_tab LIKE LINE OF it_key_tab.
"key参数
LOOP AT it_key_tab INTO ls_key_tab.
IF sy-tabix = 1.
CLEAR ls_where.
ls_where = ls_key_tab-name && ' = ''' && ls_key_tab-value && ''''.
APPEND ls_where TO lt_where.
ELSE.
CLEAR ls_where.
ls_where = `AND ` && ls_key_tab-name && ' = ''' && ls_key_tab-value && ''''.
APPEND ls_where TO lt_where.
ENDIF.
ENDLOOP.
IF it_key_tab IS NOT INITIAL.
SELECT SINGLE * INTO CORRESPONDING FIELDS OF er_entity
FROM scarr
WHERE (lt_where).
ELSE.
SELECT SINGLE * INTO CORRESPONDING FIELDS OF er_entity
FROM scarr.
ENDIF.
endmethod.
重新SCARR的GET_ENTITYSET方法;
示例:
method ZT_SCARRSET_GET_ENTITYSET.
"查询所有数据
SELECT * INTO CORRESPONDING FIELDS OF TABLE et_entityset
FROM scarr.
"获取$top,$skip
"paging方法,先skip,后取top记录
"直接调用方式实现paging
IF is_paging IS NOT INITIAL.
/iwbep/cl_mgw_data_util=>paging(
EXPORTING
is_paging = is_paging
CHANGING
ct_data = et_entityset
).
ENDIF.
"获取$filter
IF it_filter_select_options IS NOT INITIAL.
"方式2:使用util方法筛选
/iwbep/cl_mgw_data_util=>filtering(
EXPORTING
it_select_options = it_filter_select_options
CHANGING
ct_data = et_entityset
).
ENDIF.
"获取$orderby,排序
IF it_order IS NOT INITIAL.
/iwbep/cl_mgw_data_util=>orderby(
EXPORTING
it_order = it_order
CHANGING
ct_data = et_entityset
).
ENDIF.
"获取$inlinecount
IF io_tech_request_context->has_inlinecount( ) = abap_true.
"获取符合条件总记录数
DESCRIBE TABLE et_entityset LINES DATA(lv_lines).
es_response_context-inlinecount = lv_lines.
ENDIF.
endmethod.
使用$expand,通过SCARR-CARRID查询到SFLIGHT对应CARRID所有数据信息;
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet(Carrid='AA')?$expand=TO_SFLIGHT;
使用$links,通过SCARR-CARRID查询返回所有SFLIGHT对应CARRID的所有URL;
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet(Carrid='AA')/$links/TO_SFLIGHT
2.13Update Entity
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet('AA')?$format=json;
执行GET方法,获取json格式结果;
选择Use as Request,将Get结果放到Request Body中;
执行一下POST,获取HTTP Header参数X-CSRF-Token;
设置Content-Type: application/json; charset=utf-8;
URL:/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet('AA')
修改非key栏位值,执行PUT方法;
"d" : {
"__metadata" : {
"id" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet('AA')",
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet('AA')",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "AA",
"Carrname" : "American Airlines S",
"Currcode" : "USD",
"Url" : "http://www.aa.com",
"TO_SFLIGHT" : {
"__deferred" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet('AA')/TO_SFLIGHT"
}
}
}
}
执行UPDATE_ENTITY方法;
示例:
method ZT_SCARRSET_UPDATE_ENTITY.
DATA:lt_scarr TYPE TABLE OF scarr.
DATA:ls_scarr LIKE LINE OF lt_scarr.
"读取输入数据
io_data_provider->read_entry_data( IMPORTING es_data = ls_scarr ).
"保存数据
MODIFY scarr FROM ls_scarr.
endmethod.
2.14Create Entity
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet;
使用POST方法,执行新增记录;
同样需要GET请求带过来的HTTP Header参数X-CSRF-Token,Content-Type: application/json; charset=utf-8;
示例:HTTP POST请求头,设置需要插入数据的值
{
"d" : {
"__metadata" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "ZF",
"Carrname" : "test Airlines",
"Currcode" : "USD",
"Url" : "http://www.zf.com"
}
}
执行CREATE_ENTITY方法
示例:
method ZT_SCARRSET_CREATE_ENTITY.
DATA:lt_scarr TYPE TABLE OF scarr.
DATA:ls_scarr LIKE LINE OF lt_scarr.
DATA:lv_msg TYPE string.
"读取输入数据
io_data_provider->read_entry_data( IMPORTING es_data = ls_scarr ).
"保存数据
INSERT scarr FROM ls_scarr.
IF sy-subrc <> 0.
lv_msg = 'Insert duplicate keys record!'.
RAISE EXCEPTION TYPE /IWBEP/CX_MGW_BUSI_EXCEPTION
EXPORTING
textid = /IWBEP/CX_MGW_BUSI_EXCEPTION=>RESOURCE_DUPLICATE
entity_type = lv_msg.
ELSE.
"成功插入,er_entity有值
MOVE-CORRESPONDING ls_scarr TO er_entity.
ENDIF.
endmethod.
2.15Delete Entity
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet('ZF');
使用DELETE方法,执行删除记录;
执行DELETE_ENTITY方法
示例:
method ZT_SCARRSET_DELETE_ENTITY.
DATA:ls_key_tab LIKE LINE OF it_key_tab.
DATA:lv_msg TYPE string.
"根据输入参数删除对应carrid记录
CLEAR ls_key_tab.
READ TABLE it_key_tab INTO ls_key_tab WITH KEY name = 'Carrid'.
IF ls_key_tab IS NOT INITIAL.
DELETE FROM scarr WHERE carrid = ls_key_tab-value.
IF sy-subrc = 0.
"删除成功
ELSE.
"删除记录不存在
lv_msg = 'carrid=' && ls_key_tab-value && ',not found!'.
RAISE EXCEPTION TYPE /IWBEP/CX_MGW_BUSI_EXCEPTION
EXPORTING
textid = /IWBEP/CX_MGW_BUSI_EXCEPTION=>RESOURCE_NOT_FOUND
entity_type = lv_msg.
ENDIF.
ELSE.
"没有指定carrid
lv_msg = 'No carrid=' && ls_key_tab-value && ',not allowed!'.
RAISE EXCEPTION TYPE /IWBEP/CX_MGW_BUSI_EXCEPTION
EXPORTING
textid = /IWBEP/CX_MGW_BUSI_EXCEPTION=>RESOURCE_NOT_FOUND
entity_type = lv_msg.
ENDIF.
endmethod.
2.16$batch
示例1:$batch基本实现过程
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/;
选择POST请求,点击Add URI Option;
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/$batch;
Request Header参数:
Content-Type:multipart/mixed; boundary=batch
Request Header Body batch定义
一个batch任务定义:包含header部分,请求内容部分;
Accept: application/json
指定返回json格式结果;
示例:
--batch
Content-Type: application/http
Content-Transfer-Encoding: binary
GET ZT_SCARRSet(Carrid='AA') HTTP/1.1
--batch
Content-Type: multipart/mixed; boundary=changeset
--changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
POST ZT_SCARRSet HTTP/1.1
Content-Type: application/json
{
"d" : {
"__metadata" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "ZK",
"Carrname" : "test1 Airlines",
"Currcode" : "USD",
"Url" : "http://www.zk.com"
}
}
--changeset--
--batch--
注意:每一个--batch和上一个GET,POST请求之间至少空两行;
--batch,表示batch开始;
--batch--,表示batch结束;
每一个batch之间执行结果互相不影响;
--changeset,表示create,update,delete批量process,只要一个失败,都失败;
示例2:$batch changeset,批量Create
示例:
--batch
Content-Type: multipart/mixed; boundary=changeset
--changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
POST ZT_SCARRSet HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"d" : {
"__metadata" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "ZK",
"Carrname" : "test1 Airlines",
"Currcode" : "USD",
"Url" : "http://www.zk.com"
}
}
--changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
POST ZT_SCARRSet HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"d" : {
"__metadata" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "ZH",
"Carrname" : "test1 Airlines",
"Currcode" : "USD",
"Url" : "http://www.zh.com"
}
}
--changeset--
注意:默认一个batch只支持一个--changeset,当设置多个chanegset时,报错:"Default changeset implementation allows only one operation"
可以将多个POST请求分别放到多个batch;
当需要支持一个batch多个--changeset时,需要修改下面三个Method:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS
Step1:Redefine /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN
示例:
method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN.
cv_defer_mode = abap_true.
endmethod.
Step2:Redefine /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END
示例:
method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END.
COMMIT WORK.
endmethod.
Step3:Redefine /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS
根据operation type,处理不同请求
CD Create Deep Entity
CE Create Entity
CM Create Stream
DE Delete Entity
DM Delete Stream
EA Execute Action
XE Expand Entity
XS Expand Entity Set
GE Get Entity
GS Get Entity Set
GD Get Entity Set Delta
GM Get Stream
PE Patch Entity
UE Update Entity
UM Update Stream
HB Changeset Begin
HE Changeset End
HP Changeset Process
IC Get Is Conditional Implemented
示例:
method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS.
"request /IWBEP/IF_MGW_APPL_TYPES=>TY_T_CHANGESET_REQUEST
FIELD-SYMBOLS:<fs_changeset_request> LIKE LINE OF it_changeset_request.
"response list
DATA:ls_changeset_response TYPE /iwbep/if_mgw_appl_types=>ty_s_changeset_response.
DATA:lo_data TYPE REF TO data.
FIELD-SYMBOLS:<fs_data> TYPE ANY.
DATA:lo_struct_descr TYPE REF TO cl_abap_structdescr.
DATA:lo_expand_node TYPE REF TO /iwbep/cl_mgw_expand_node.
DATA:lv_entity_type TYPE /iwbep/mgw_tech_name.
"input parameter
DATA:lv_entity_name TYPE string.
DATA:lv_entity_set_name TYPE string.
DATA:lv_source_name TYPE string.
DATA:lt_key_tab TYPE /iwbep/t_mgw_name_value_pair.
DATA:ls_key_tab LIKE LINE OF lt_key_tab.
DATA:lo_request_object TYPE REF TO /iwbep/if_mgw_req_entity.
DATA:lo_tech_request_context TYPE REF TO /iwbep/if_mgw_req_entity.
DATA:lt_navigation_path TYPE /iwbep/t_mgw_navigation_path.
"request create
DATA:lo_request_c TYPE REF TO /iwbep/if_mgw_req_entity_c.
"根据operation,处理不同请求
LOOP AT it_changeset_request ASSIGNING <fs_changeset_request>.
CASE <fs_changeset_request>-operation_type.
WHEN 'CE'.
"create entity
"获取请求数据
lo_expand_node ?= <fs_changeset_request>-expand_node.
lo_struct_descr ?= lo_expand_node->create_data_descriptor( ).
CREATE DATA lo_data TYPE HANDLE lo_struct_descr.
ASSIGN lo_data->* TO <fs_data>.
<fs_changeset_request>-entry_provider->read_entry_data( IMPORTING es_data = <fs_data> ).
"获取entity name
"执行更新
lo_request_c ?= <fs_changeset_request>-request_context.
lv_entity_type = lo_request_c->get_entity_type_name( ).
IF lv_entity_type = 'ZT_SCARR'.
CLEAR <fs_data>.
zt_scarrset_create_entity(
EXPORTING
iv_entity_name = lv_entity_name
iv_entity_set_name = lv_entity_set_name
iv_source_name = lv_source_name
it_key_tab = lt_key_tab
io_tech_request_context = lo_request_c
it_navigation_path = lt_navigation_path
io_data_provider = <fs_changeset_request>-entry_provider
IMPORTING
er_entity = <fs_data>
).
ENDIF.
"Create成功,设置response
IF <fs_data> IS NOT INITIAL.
CLEAR ls_changeset_response.
copy_data_to_ref(
EXPORTING
is_data = <fs_changeset_request>
CHANGING
cr_data = ls_changeset_response-entity_data
).
ls_changeset_response-headers = <fs_changeset_request>-request_headers.
ls_changeset_response-operation_no = <fs_changeset_request>-operation_no.
APPEND ls_changeset_response TO ct_changeset_response.
ENDIF.
WHEN OTHERS.
ENDCASE.
ENDLOOP.
endmethod.
示例3:$batch changeset,混合Create,Update数据请求
URL: /sap/opu/odata/sap/ZTOM_GS1_SRV/$batch;
POST方法;
Request Body:
示例:
--batch
Content-Type: multipart/mixed; boundary=changeset
--changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
POST ZT_SCARRSet HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"d" : {
"__metadata" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "ZK",
"Carrname" : "test1 Airlines",
"Currcode" : "USD",
"Url" : "http://www.zk.com"
}
}
--changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
PUT ZT_SCARRSet(Carrid='ZH') HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"d" : {
"__metadata" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "ZH",
"Carrname" : "change Airlines",
"Currcode" : "USD",
"Url" : "http://www.zh.com"
}
}
--changeset--
--batch--
示例: /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS方法实现Update
WHEN 'UE'.
"request update
DATA:lo_request_u TYPE REF TO /iwbep/if_mgw_req_entity_u.
"执行更新
lo_request_u ?= <fs_changeset_request>-request_context.
lv_entity_type = lo_request_c->get_entity_type_name( ).
IF lv_entity_type = 'ZT_SCARR'.
"how to get free data type
CREATE DATA lo_data TYPE scarr.
ASSIGN lo_data->* TO <fs_data>.
zt_scarrset_update_entity(
EXPORTING
iv_entity_name = lv_entity_name
iv_entity_set_name = lv_entity_set_name
iv_source_name = lv_source_name
it_key_tab = lt_key_tab
io_tech_request_context = lo_request_u
it_navigation_path = lt_navigation_path
io_data_provider = <fs_changeset_request>-entry_provider
IMPORTING
er_entity = <fs_data>
).
ENDIF.
示例4:$batch changeset,混合Create,Update,Delete数据请求
--batch
Content-Type: application/http
Content-Transfer-Encoding: binary
GET ZT_SCARRSet(Carrid='AA') HTTP/1.1
Accept: application/json
--batch
Content-Type: multipart/mixed; boundary=changeset
--changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
POST ZT_SCARRSet HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"d" : {
"__metadata" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "ZF",
"Carrname" : "test1 Airlines",
"Currcode" : "USD",
"Url" : "http://www.zf.com"
}
}
--changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
PUT ZT_SCARRSet(Carrid='ZH') HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"d" : {
"__metadata" : {
"uri" : "<host>/sap/opu/odata/sap/ZTOM_GS1_SRV/ZT_SCARRSet",
"type" : "ZTOM_GS1_SRV.ZT_SCARR"
},
"Carrid" : "ZH",
"Carrname" : "changes Airlines",
"Currcode" : "USD",
"Url" : "http://www.zh.com"
}
}
--changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
DELETE ZT_SCARRSet(Carrid='ZE') HTTP/1.1
Content-Type: application/json
Accept: application/json
--changeset--
--batch--
示例:/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS方法实现Delete
WHEN 'DE'.
"request delete
DATA:lo_request_d TYPE REF TO /iwbep/if_mgw_req_entity_d.
"执行删除
lo_request_d ?= <fs_changeset_request>-request_context.
lv_entity_type = lo_request_c->get_entity_type_name( ).
IF lv_entity_type = 'ZT_SCARR'.
DATA:lt_keys TYPE /iwbep/t_mgw_tech_pairs.
DATA:ls_keys LIKE LINE OF lt_keys.
lt_keys = lo_request_d->get_keys( ).
LOOP AT lt_keys INTO ls_keys.
CLEAR ls_key_tab.
ls_key_tab-name = ls_keys-name.
ls_key_tab-value = ls_keys-value.
APPEND ls_key_tab TO lt_key_tab.
ENDLOOP.
"调用复位义方法
zt_scarrset_delete_entity(
EXPORTING
iv_entity_name = lv_entity_name
iv_entity_set_name = lv_entity_set_name
iv_source_name = lv_source_name
it_key_tab = lt_key_tab
io_tech_request_context = lo_request_d
it_navigation_path = lt_navigation_path
).
ENDIF.
"删除没有返回,没有exception,即删除成功
ls_changeset_response-operation_no = <fs_changeset_request>-operation_no.
APPEND ls_changeset_response TO ct_changeset_response.