SAP restful http 接口集中管理发布(SICF)
项目上有很多restful接口的需求,其中涉及到多个外围系统,就想着如何通过只发布一个服务,而不用通过Webservice,也不通过RFC方式,让个外围系统传入不同的报文,来决定动态的调用不同的业务处理程序。这时候就可以用SAP发布HTTP请求的方式(RESTFUL服务)来实现。
SE24继承 IF_HTTP_EXTENSION 接口,实现系统接口方法IF_HTTP_EXTENSION~HANDLE_REQUEST,再SICF配置服务几步来实现。
工作中需要发布 http 接口,以供第三方系统调用,网上有很多实现的方式都是通过 IF_HTTP_EXTENSION 接口实现的
跟外围系统定义报文格式的时候,确定了报文的总体格式,要求不管什么接口,总体格式不变。结构如下:
{
"HEAD": {
"TARGET_SYS": "SAP",
"INTF_ID": "INT_FI001",
"SOURCE_SYS": "OA"
},
"DATA":""
}
其中定义了两个固定格式,head与data,head中包含了接口的目标系统、源系统以及接口编号,data部分用于传输业务数据,结构与业务字段需根据实际确定。
注意,由于在json转abap对象时没有指定具体数据类型,所以由前端系统将所有数据转成字符串类型传输,避免在sap将小数转换成浮点数。
原始数据:
转换后数据:
确定好报文格式后,剩下来的只需要在SAP内对JSON解析时特殊处理了。
返回报文JSON串解析
METHOD if_rest_resource~post.
DATA lo_object TYPE REF TO object.
DATA lo_infter TYPE REF TO zif_interface_http.
DATA lv_clname TYPE c LENGTH 30.
DATA ls_head TYPE zsifheadinfo.
DATA ls_return TYPE bapiret2.
DATA:BEGIN OF ls_data,
head TYPE zsifheadinfo,
data TYPE REF TO data,
END OF ls_data.
" 获取报文。
DATA(lv_json) = mo_request->get_entity( )->get_string_data( ).
/ui2/cl_json=>deserialize( EXPORTING json = lv_json
CHANGING data = ls_data ).ASSIGN COMPONENT 'HEAD' OF STRUCTURE ls_data TO FIELD-SYMBOL(<fs_head>).
IF sy-subrc <> 0 OR <fs_head> IS NOT ASSIGNED OR <fs_head> IS INITIAL.
ls_return-message = '数据解析异常:缺少HEAD数据'.
return_error( ls_return ).
RETURN.
ELSE.
MOVE-CORRESPONDING <fs_head> TO ls_head.
ENDIF.ASSIGN COMPONENT 'DATA' OF STRUCTURE ls_data TO FIELD-SYMBOL(<fs_data>).
IF sy-subrc <> 0 OR <fs_data> IS NOT ASSIGNED OR <fs_data> IS INITIAL.
ls_return-message = '数据解析异常:缺少DATA数据'.
return_error( ls_return ).
RETURN.
ENDIF." 根据接口id确定业务实现类
SELECT SINGLE object_name 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_uuid_error INTO DATA(lo_uuid_error).
ls_return-message = lo_uuid_error->get_text( ).
return_error( ls_return ).
RETURN.
CATCH cx_sy_create_object_error INTO DATA(lo_object_error).
ls_return-message = lo_object_error->get_text( ).
return_error( ls_return ).
RETURN.
CATCH cx_sy_dyn_call_illegal_method INTO DATA(lo_illegal_method).
ls_return-message = lo_illegal_method->get_text( ).
return_error( ls_return ).
RETURN.
CATCH cx_sy_dyn_call_illegal_type INTO DATA(lo_illegal_type).
ls_return-message = lo_illegal_type->get_text( ).
return_error( ls_return ).
RETURN.
CATCH cx_sy_dyn_call_param_not_found INTO DATA(lo_param_not_found).
ls_return-message = lo_param_not_found->get_text( ).
return_error( ls_return ).
RETURN.
CATCH cx_root INTO DATA(lo_root).
ls_return-message = lo_root->get_text( ).
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)'.
return_error( ls_return ).
RETURN.
ENDIF.DATA re_data TYPE string.
DATA iv_data TYPE string.iv_data = /ui2/cl_json=>serialize( <fs_data> ).
lo_infter->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.
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的转换,用于更方便传递内容。
接口 zif_interface_http 的方法如下:
INTERFACE zif_interface_http
PUBLIC.
METHODS 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 check_data
CHANGING VALUE(cs_return) TYPE bapiret2.
METHODS save_data
CHANGING VALUE(cs_return) TYPE bapiret2.
METHODS call_bapi
CHANGING VALUE(cs_return) TYPE bapiret2.
METHODS abap2json
IMPORTING iv_return TYPE bapiret2
RETURNING VALUE(ev_data) TYPE string.
METHODS json2data
IMPORTING iv_data TYPE string OPTIONAL
CHANGING VALUE(re_data) TYPE data.
METHODS lock_order
CHANGING VALUE(cs_return) TYPE bapiret2.
ENDINTERFACE.
配置表中的业务处理类只有一个实例构造方法,其他方法引用接口。代码如下
DATA lo_error TYPE REF TO cx_sy_dyn_call_illegal_method.
TRY.
zif_interface_http~json2data( EXPORTING iv_data = iv_data
CHANGING re_data = mt_data ).
zif_interface_http~check_data( CHANGING cs_return = re_return ).
zif_interface_http~lock_order( CHANGING cs_return = re_return ).
zif_interface_http~call_bapi( CHANGING cs_return = re_return ).
zif_interface_http~save_data( CHANGING cs_return = re_return ).
re_data = zif_interface_http~abap2json( iv_return = re_return ).
CATCH cx_sy_dyn_call_illegal_method INTO lo_error.
re_return-message = lo_error->if_message~get_text( ).
ENDTRY.
处理之后的响应报文由各不同的类传递出json对象,直接返回给发送方。
剩下的就是一个返回错误的方法,没什么好说的,返回一个400的报错.
HTTP公共发送接口
首选获取外围系统对应的IP或域名地址,接口编号。在此URL上给参数赋值。
FUNCTION zFIfm_http_send_com.
*"----------------------------------------------------------------------
*"*"本地接口:
*" IMPORTING
*" VALUE(IV_URL) TYPE STRING
*" VALUE(IV_DATA) TYPE STRING
*" VALUE(IV_APPTOKEN) TYPE STRING OPTIONAL
*" VALUE(IV_ACCESSTOKEN) TYPE STRING OPTIONAL
*" EXPORTING
*" VALUE(EV_RESPONSE) TYPE STRING
*" VALUE(ES_MESSAGE) TYPE ZSHR_MESSAGE
*"----------------------------------------------------------------------
DATA: lv_url TYPE string,
lo_http_client TYPE REF TO if_http_client,
lv_msgtx TYPE string,
lv_len TYPE i.
lv_url = iv_url.
"1检查URL ,DATA.
IF lv_url IS INITIAL.
ev_mtype = 'E'.
ev_message = 'Http请求地址不能为空'.
RETURN.
ENDIF.
IF lv_data IS INITIAL.
ev_mtype = 'E'.
ev_message = 'Http请求内容不能为空'.
RETURN.
ENDIF.
IF iv_intfid IS INITIAL.
ev_mtype = 'E'.
ev_message = '接口编号不能为空'.
RETURN.
ENDIF.
"2解析URL
CALL FUNCTION 'SWLWP_URI_PARSE'
EXPORTING
uri = lv_url
IMPORTING
host = lv_host
port = lv_port
EXCEPTIONS
uri_no_path = 1
OTHERS = 2.
IF sy-subrc <> 0.
ev_mtype = 'E'.
ev_message = '解析请求地址错误'.
RETURN.
ENDIF.
"3创建请求实例。
CALL METHOD cl_http_client=>create
EXPORTING
host = lv_host
service = lv_port
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
ev_mtype = 'E'.
ev_message = '创建Http请求实例错误'.
RETURN.
ENDIF.
"4 设置请求的URL地址
CALL METHOD cl_http_utility=>set_request_uri
EXPORTING
request = lo_http_client->request
uri = lv_url.
"5 设置Post方法
CALL METHOD lo_http_client->request->set_method
EXPORTING
method = if_http_entity=>co_request_method_post.
"6 Basic Authentication 认证
IF iv_auth_need IS NOT INITIAL.
SELECT SINGLE username,password INTO (@lv_username,@lv_password)
FROM ztinf WHERE intfid = @iv_intfid.
IF sy-subrc IS INITIAL.
CALL METHOD lo_http_client->authenticate
EXPORTING
username = lv_username
password = lv_password.
ELSE.
ev_mtype = 'E'.
ev_message = 'Basic Authentication 认证用户密码未配置(ZTINF)'.
RETURN.
ENDIF.
ENDIF.
" 7 设置请求内容类型
IF iv_content_type IS NOT INITIAL.
lv_content_type = iv_content_type.
CALL METHOD lo_http_client->request->set_content_type
EXPORTING
content_type = lv_content_type.
ENDIF.
"8 设置请求 header 参数
lo_http_client->request->set_header_fields( fields = it_fields ).
"9 设置请求内容
CALL METHOD lo_http_client->request->set_cdata
EXPORTING
data = lv_data.
"10 发送http 请求
CALL METHOD lo_http_client->send
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2.
IF sy-subrc <> 0.
ev_mtype = 'E'.
CASE sy-subrc.
WHEN 1.
ev_message = '发送Http请求失败,通信错误'.
WHEN 2.
ev_message = '发送Http请求失败,无效状态'.
WHEN OTHERS.
ENDCASE.
RETURN.
ENDIF.
" 11 接收返回信息
CALL METHOD lo_http_client->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3.
IF sy-subrc <> 0.
ev_mtype = 'E'.
CASE sy-subrc.
WHEN 1.
ev_message = 'Http 通信失败'.
WHEN 2.
ev_message = 'Http 无效状态'.
WHEN 3.
ev_message = 'Http 处理失败'.
WHEN OTHERS.
ENDCASE.
RETURN.
ENDIF.
" 12 获取返回body
IF ev_response IS SUPPLIED.
DATA(lv_response) = lo_http_client->response->get_cdata( ).
ev_response = lv_response.
ev_mtype = 'S'.
ev_message = 'Http请求发送成功'.
DATA(lv_data_x) = lo_http_client->response->get_data( ).
ev_data = lv_data_x.
ENDIF.
CALL METHOD lo_http_client->close.
ENDFUNCTION.
应用实例1:
"调用JAVA等接口地址及URL参数赋值,多个参数赋值采用KEY,VALUE键值对方式,如
lv_service = 'http://10.0.73.149:8110/CS/api/public/hscs/ae/importJson?token=' .
lv_token = 'sourceSystem=FI&accessKey=7815696ecbf1c96e6894b779456d330e'.
lv_service = lv_service && lv_token.
lv_data = '{"sourceSystem":' && '"FI",' && '"documentNo":"111",' &&
'"eventBatchName":"FI_XXX_v1.0",' &&
'"accountingDate":"' && sy-datum(4) && '-' && sy-datum+4(2) && '-' && sy-datum+6(2) && ',' &&
'"accountingCompany":"001","reversalFlag":"N" ' &&
'"value1":" ' && ls_result-period && '",' &&
'"value1":" ' && ls_result-orgeh_id && '",' &&
'"value3":" ' && ls_result-period && '"}' . "金额
*根据URL创建一个HTTP客户端
cl_http_client=>create_by_url(
EXPORTING
url = lv_url
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4 ).
IF sy-subrc NE 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno INTO lv_msgtx
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
es_message-msgty = 'E'.
es_message-msgtx = lv_msgtx.
RETURN.
ENDIF.
*是否显示登陆弹出框-否
lo_http_client->propertytype_logon_popup = lo_http_client->co_disabled.
*合成header值
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Content-Type'
value = 'application/json'.
IF iv_apptoken IS NOT INITIAL.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Authorization'
value = iv_apptoken.
ENDIF.
IF iv_accesstoken IS NOT INITIAL.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Authorization'
value = iv_accesstoken.
ENDIF.
*传输json内容
lv_len = strlen( iv_data ) .
CALL METHOD lo_http_client->request->set_cdata
EXPORTING
data = iv_data
offset = 0
length = lv_len.
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2 ).
IF sy-subrc NE 0.
lo_http_client->get_last_error( IMPORTING message = lv_msgtx ).
es_message-msgty = 'E'.
es_message-msgtx = lv_msgtx.
RETURN.
ENDIF.
*获取返回内容
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
IF sy-subrc NE 0.
lo_http_client->get_last_error( IMPORTING message = lv_msgtx ).
es_message-msgty = 'E'.
es_message-msgtx = lv_msgtx.
RETURN.
ENDIF.
"获取接口response返回
ev_response = lo_http_client->response->get_cdata( ).
*关闭接口
CALL METHOD lo_http_client->close.
WAIT UP TO 1 SECONDS. " 用于数据多时 防止接口返回错误
“服务没有报错时解析返回JSON串
IF ev_response NS 'Error' OR ev_response NS 'error'. " 解决服务报错 导致dump 问题
CALL FUNCTION 'ZHRFM_JSON_TO_ABAP'
EXPORTING
iv_json = lv_response_body
IMPORTING
ev_data = lt_info.
ENDIF.
ENDFUNCTION.
JSON转换成内表
METHOD json_to_data_internal.
"JSON ABAP
"{...} object --> field, structure, ...
"[...] array --> table
DATA:
lv_char TYPE c,
lv_token TYPE string,
lv_dummy TYPE string, "is used in case of invalid fieldname
lt_dummy LIKE STANDARD TABLE OF lv_dummy, "is used in case of invalid table
lv_is_filled TYPE abap_bool,
lr_line TYPE REF TO data,
lr_td TYPE REF TO cl_abap_typedescr,
lr_ttd TYPE REF TO cl_abap_tabledescr,
lx_root TYPE REF TO cx_root.
FIELD-SYMBOLS:
<la_any> TYPE any,
<la_line> TYPE any,
<lt_any> TYPE ANY TABLE,
<lt_srtd> TYPE SORTED TABLE,
<lt_hash> TYPE HASHED TABLE,
<lt_stnd> TYPE STANDARD TABLE.
lr_td = cl_abap_typedescr=>describe_by_data( ca_data ).
CASE lr_td->type_kind.
WHEN cl_abap_typedescr=>typekind_dref.
ASSIGN ca_data->* TO <la_any>.
IF sy-subrc <> 0. ASSIGN lv_dummy TO <la_any>. ENDIF.
WHEN OTHERS.
ASSIGN ca_data TO <la_any>.
ENDCASE.
WHILE strlen( cv_json ) > 0.
lv_char = cv_json(1).
SHIFT cv_json BY 1 PLACES.
CASE lv_char.
WHEN '{'. "object starts --> next level
json_to_data_internal(
EXPORTING
iv_is_tabline = abap_false
IMPORTING
ev_is_filled = ev_is_filled
CHANGING
cv_json = cv_json
ca_data = <la_any> ).
WHEN '['. "array starts --> next level
lr_td = cl_abap_typedescr=>describe_by_data( <la_any> ).
IF lr_td->kind EQ cl_abap_typedescr=>kind_table.
ASSIGN <la_any> TO <lt_any>.
ELSE. "Type mismatch - to prevent short dump
ASSIGN lt_dummy TO <lt_any>.
ENDIF.
CREATE DATA lr_line LIKE LINE OF <lt_any>.
ASSIGN lr_line->* TO <la_line>.
CLEAR lv_is_filled.
json_to_data_internal(
EXPORTING
iv_is_tabline = abap_true
IMPORTING
ev_is_filled = lv_is_filled
CHANGING
cv_json = cv_json
ca_data = <la_line> ).
IF <la_line> IS NOT INITIAL
OR lv_is_filled EQ abap_true.
ev_is_filled = abap_true.
lr_td = cl_abap_typedescr=>describe_by_data( <lt_any> ).
lr_ttd ?= lr_td.
IF lr_ttd->table_kind EQ cl_abap_tabledescr=>tablekind_sorted.
" sorted table
ASSIGN <lt_any> TO <lt_srtd>.
INSERT <la_line> INTO TABLE <lt_srtd>.
ELSEIF lr_ttd->table_kind = cl_abap_tabledescr=>tablekind_hashed.
" hashed table
ASSIGN <lt_any> TO <lt_hash>.
INSERT <la_line> INTO TABLE <lt_hash>.
ELSE.
" standard table
ASSIGN <lt_any> TO <lt_stnd>.
APPEND <la_line> TO <lt_stnd>.
ENDIF.
ENDIF.
WHEN ']'. "Array ends --> previous level
IF lv_token IS NOT INITIAL.
convert_token(
EXPORTING
ia_data = <la_any>
CHANGING
cv_token = lv_token ).
TRY.
<la_any> = lv_token.
ev_is_filled = abap_true.
CATCH cx_root INTO lx_root. "#EC NO_HANDLER
ENDTRY.
ENDIF.
RETURN.
WHEN '}'. "Object ends --> previous level
IF lv_token IS NOT INITIAL.
convert_token(
EXPORTING
ia_data = <la_any>
CHANGING
cv_token = lv_token ).
TRY.
<la_any> = lv_token.
ev_is_filled = abap_true.
CATCH cx_root INTO lx_root. "#EC NO_HANDLER
ENDTRY.
ENDIF.
RETURN.
WHEN ':'. "key ends, value starts
TRANSLATE lv_token TO UPPER CASE.
SHIFT lv_token LEFT DELETING LEADING space.
IF lv_token IS NOT INITIAL.
IF lv_token EQ '$ROOT'. "Do nothing - already assigned!
ELSEIF lv_token EQ '$T'. "ignore the value! do special things
json_to_brf_struc(
CHANGING
ca_data = <la_any>
cv_json = cv_json ).
ev_is_filled = abap_true.
ELSE.
ASSIGN COMPONENT lv_token OF STRUCTURE ca_data TO <la_any>.
IF sy-subrc NE 0. "Field not found?
ASSIGN lv_dummy TO <la_any>. "ignore the value!
ENDIF.
ENDIF.
ENDIF.
CLEAR lv_token.
WHEN ','. "next value -- same level
IF lv_token IS NOT INITIAL.
convert_token(
EXPORTING
ia_data = <la_any>
CHANGING
cv_token = lv_token ).
TRY.
<la_any> = lv_token.
ev_is_filled = abap_true.
CATCH cx_root INTO lx_root. "#EC NO_HANDLER
ENDTRY.
ENDIF.
CLEAR lv_token.
IF iv_is_tabline EQ abap_true. "to trigger next table line
CONCATENATE '[' cv_json INTO cv_json.
RETURN.
ENDIF.
WHEN '"'. "string starts
get_string(
IMPORTING
ev_string = lv_token
CHANGING
cv_json = cv_json ).
WHEN OTHERS. "ie. numbers, ...
CONCATENATE lv_token lv_char INTO lv_token.
ENDCASE.
ENDWHILE.
ENDMETHOD.
SAP 发布HTTP接口之完整的Restful ( 含Token 验证)
在工作中需要发布 http 接口,以供第三方系统调用,网上有很多实现的方式都是通过 IF_HTTP_EXTENSION 接口实现的,这次用的方式不一样。
具体过程如下:
一、代码过程
1. 使用SE24创建一个类 ZLOCAL_CL_REST,并且继承超类 CL_REST_HTTP_HANDLER 。
2. 重构方法 IF_REST_APPLICATION~GET_ROOT_HANDLER,HANDLE_CSRF_TOKEN,其中HANDLE_CSRF_TOKEN 是用于token验证的,如果不需要token验证则直接重构即可,不需要代码,需要验证的话可以保留,无需重构。
3.重构的代码,其中/GET/PO 为接口路径,ZLOCAL_CL_GET_PURCHASEORDER 为接口类
4.TOKEN 验证 如果需要进行验证的,则不需要重构方法HANDLE_CSRF_TOKEN,在原有的代码逻辑下,使用GET 方法时,在发送请求时登入了 Authentication账号密码即可正确获取token。不需要token则直接重构即可,不需要代码。
5.上述完成后,再次使用SE24 创建一个类,类名为前面的接口类 ZLOCAL_CL_GET_PURCHASEORDER .并且继承超类 CL_REST_RESOURCE。
6.继承后,根据接口的不同调用方式,重构相应的方法
这里使用GET方式进行演示
METHOD if_rest_resource~get.
*CALL METHOD SUPER->IF_REST_RESOURCE~GET
* .
DATA: lv_output_json TYPE string.
DATA: lv_ebeln TYPE ebeln.
DATA: BEGIN OF ls_out,
ebeln TYPE ebeln,
bukrs TYPE bukrs,
bsart TYPE bsart,
aedat TYPE aedat,
ernam TYPE ernam,
lifnr TYPE lifnr,
ekorg TYPE ekorg,
END OF ls_out.
DATA: BEGIN OF ls_output,
code TYPE char3,
clnt TYPE sy-mandt,
status TYPE char10,
content TYPE string,
data LIKE ls_out,
END OF ls_output.
DATA(rt_parameters) = mo_request->get_uri_query_parameters( )." 获取参数 "
LOOP AT rt_parameters ASSIGNING FIELD-SYMBOL(<fs_par>).
TRANSLATE <fs_par>-name TO UPPER CASE.
TRANSLATE <fs_par>-value TO UPPER CASE.
ENDLOOP.
ls_output-clnt = sy-mandt.
READ TABLE rt_parameters INTO DATA(ls_par) WITH KEY name = 'EBELN'.
IF sy-subrc IS INITIAL AND ls_par-value IS NOT INITIAL.
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = ls_par-value
IMPORTING
output = lv_ebeln.
SELECT SINGLE * INTO CORRESPONDING FIELDS OF ls_out FROM ekko
WHERE ebeln = lv_ebeln.
IF sy-subrc IS INITIAL.
ls_output-data = ls_out.
ls_output-code = cl_rest_status_code=>gc_success_ok.
ls_output-status = 'success'.
ls_output-content = '获取成功'.
ELSE.
ls_output-data = ls_out.
ls_output-code = cl_rest_status_code=>gc_success_ok.
ls_output-status = 'fail'.
ls_output-content = '获取失败'.
ENDIF.
ELSE.
ls_output-data = ls_out.
ls_output-code = cl_rest_status_code=>gc_redirection_permanent.
ls_output-status = 'fail'.
ls_output-content = '参数错误'.
ENDIF./ui2/cl_json=>serialize(
EXPORTING
data = ls_output
compress = abap_false
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
RECEIVING
r_json = lv_output_json ).
" 响应内容"
mo_response->create_entity( )->set_string_data( lv_output_json ).
" 响应内容类型 : application/json"
mo_response->create_entity( )->set_content_type( iv_media_type = if_rest_media_type=>gc_appl_json ).
" 响应状态 : 非必须"
mo_response->set_status( cl_rest_status_code=>gc_success_ok ).
" 响应说明 : 非必须"
mo_response->set_reason( cl_rest_status_code=>get_reason_phrase( cl_rest_status_code=>gc_success_ok ) ).
ENDMETHOD.
POST方式获取body.
" POST 方式传入参数,JSON"
DATA(lv_input_json) = io_entity->get_string_data( ).
二、使用SICF配置服务
配置如下,处理器为 ZLOCAL_CL_REST ,即第一次创建的类。
三、Postman 测试
1、正确调用
2、如果路径不正确会提示没有合适的资源。
3、方法没启用,提示不受支持。
四、使用token
- 使用token 需要在 POST 方式调用,先对类ZLOCAL_CL_GET_PURCHASEORDER中的方法IF_REST_RESOURCE~POST 重构,为了测试这里简单重构了。
METHOD if_rest_resource~post. TYPES:BEGIN OF ts_indata , matnr TYPE matnr, maktx TYPE maktx, END OF ts_indata. DATA: ls_data TYPE ts_indata. TYPES: BEGIN OF ts_outdata, code TYPE char3. INCLUDE TYPE ts_indata. TYPES: END OF ts_outdata. DATA: ls_outdata TYPE ts_outdata. " POST 方式传入参数,JSON" DATA(lv_input_json) = io_entity->get_string_data( ). " JSON 转换为内表" /ui2/cl_json=>deserialize( EXPORTING json = lv_input_json CHANGING data = ls_data ). CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT' EXPORTING input = ls_data-matnr IMPORTING output = ls_data-matnr EXCEPTIONS length_error = 1 OTHERS = 2. SELECT SINGLE maktx FROM makt INTO ls_data-maktx WHERE matnr = ls_data-matnr. " 内表转换JSON" DATA: lv_output_json TYPE string. MOVE-CORRESPONDING ls_data TO ls_outdata. ls_outdata-code = cl_rest_status_code=>gc_success_ok . /ui2/cl_json=>serialize( EXPORTING data = ls_outdata compress = abap_false pretty_name = /ui2/cl_json=>pretty_mode-camel_case RECEIVING r_json = lv_output_json ). " 响应内容" mo_response->create_entity( )->set_string_data( lv_output_json ). " 响应状态 : 非必须" mo_response->set_status( cl_rest_status_code=>gc_success_ok ). " 响应说明 : 非必须" mo_response->set_reason( cl_rest_status_code=>get_reason_phrase( cl_rest_status_code=>gc_success_ok ) ). ENDMETHOD.
-
对请求添加Basic Authentication账号密码,否则无法获取。
-
使用Postman 获取token
请求的Headers 中添加 x-csrf-token 参数,值为 fetch,即可在响应的 Headers 中取得 token 值。
测试token
1、使用错误的token会提示验证失败
2、正确的token,验证时同样需要Basic Authentication账号密码。