SAP接口方式之HTTP请求发布Restful服务

news2025/3/13 17:35:03

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_HANDLERHANDLE_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

  1. 使用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.
    
  2. 对请求添加Basic Authentication账号密码,否则无法获取。

  3. 使用Postman 获取token
    请求的Headers 中添加 x-csrf-token 参数,值为 fetch,即可在响应的 Headers 中取得 token 值。

测试token
1、使用错误的token会提示验证失败

2、正确的token,验证时同样需要Basic Authentication账号密码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2314419.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spark-TTS:基于大模型的文本语音合成工具

GitHub&#xff1a;https://github.com/SparkAudio/Spark-TTS Spark-TTS是一个先进的文本到语音系统&#xff0c;它利用大型语言模型&#xff08;LLM&#xff09;的强大功能进行高度准确和自然的语音合成&#xff1b;旨在高效、灵活、强大地用于研究和生产用途。 一、介绍 Sp…

Netty基础—3.基础网络协议一

大纲 1.网络基础的相关问题总结 2.七层模型和四层模型 3.物理层(网线 光缆 01电信号) 4.数据链路层(以太网协议 网卡mac地址) 5.网络层(IP协议 子网划分 路由器) 6.传输层(TCP和UDP协议 Socket 端口) 7.应用层(HTTP协议 SMTP协议) 8.浏览器请求一个域名会发生什…

【mysql】centOS7安装mysql详细操作步骤!

【mysql】centOS7安装mysql详细操作步骤&#xff01;—通过tar包方式 需要 root 权限&#xff0c;使用 root 用户进行命令操作。 1. 查看 CentOS 版本 cat /etc/redhat-release2. 安装rpm包&#xff0c;以8为例 打开 MySQL 官方 yum 仓库网站&#xff0c;获取与当前 CentOS …

使用Nodejs基于DeepSeek加chromadb实现RAG检索增强生成 本地知识库

定义 检索增强生成&#xff08;RAG&#xff09;的基本定义 检索增强生成&#xff08;Retrieval-Augmented Generation&#xff0c;简称RAG&#xff09;是一种结合了信息检索技术与语言生成模型的人工智能技术。RAG通过从外部知识库中检索相关信息&#xff0c;并将其作为提示&…

笔试刷题专题(一)

文章目录 最小花费爬楼梯&#xff08;动态规划&#xff09;题解代码 数组中两个字符串的最小距离&#xff08;贪心&#xff08;dp&#xff09;&#xff09;题解代码 点击消除题解代码 最小花费爬楼梯&#xff08;动态规划&#xff09; 题目链接 题解 1. 状态表示&#xff1…

LeetCode977有序数组的平方

思路①&#xff1a;先平方&#xff0c;后快排&#xff0c;输出&#xff08;基准元素&#xff0c;左小右大&#xff09; 时间复杂度&#xff1a;O&#xff08;nlogn&#xff09; 思路②&#xff1a;双指针左右开弓&#xff0c;首先原数组已经是按照非递减顺序排序&#xff0c;那…

网络变压器的主要电性参数与测试方法(4)

Hqst盈盛&#xff08;华强盛&#xff09;电子导读&#xff1a;网络变压器的主要电性参数与测试方法&#xff08;4&#xff09;.. 今天我们继续来看看网络变压器的2个重要电性参数与它的测试方法&#xff1a; 1.反射损耗&#xff08;Return loss&…

Windows10 WSL又又又一次崩了 Docker Desktop - Unexpected WSL error

问题&#xff1a;Windows10 WSL又又又一次崩了 这回报错&#xff1a; 然后再打开WSL Ubuntu就卡住了&#xff0c;等很长时间没反应&#xff0c;就关掉了。 手动启动Docker Desktop&#xff0c;报错&#xff1a; An unexpected error occurred while executing a WSL comman…

【前端基础】:HTML

超链接标签: a href: 必须具备, 表示点击后会跳转到哪个页面. target: 打开方式. 默认是 _self. 如果是 _blank 则用新的标签页打开 <a href"http://www.baidu.com">百度</a>链接的几种形式: 外部链接: href 引用其他网站的地址 <a href"http…

JVM垃圾收集器合集

前言&#xff1a;JVM GC收集器的回顾与比较 JVM&#xff08;Java虚拟机&#xff09;中的垃圾收集器是自动管理内存的重要机制&#xff0c;旨在回收不再使用的对象所占用的内存空间。以下是JVM中几种常见的垃圾收集器的详细介绍&#xff1a; 一、新生代垃圾收集器 1.Serial收集…

Sourcetree——使用.gitignore忽略文件或者文件夹

一、为何需要文件忽略机制&#xff1f; 1.1 为什么要会略&#xff1f; 对于开发者而言&#xff0c;明智地选择忽略某些文件类型&#xff0c;能带来三大核心优势&#xff1a; 仓库纯净性&#xff1a;避免二进制文件、编译产物等污染代码库 安全防护&#xff1a;防止敏感信息&…

本地部署 OpenManus 保姆级教程(Windows 版)

一、环境搭建 我的电脑是Windows 10版本&#xff0c;其他的没尝试&#xff0c;如果大家系统和我的不一致&#xff0c;请自行判断&#xff0c;基本上没什么大的出入啊。 openManus的Git地址&#xff1a;https://github.com/mannaandpoem/OpenManus 根据官网的两种安装推荐方式如…

视频推拉流:EasyDSS平台直播通道重连转推失败原因排查与解决

视频推拉流EasyDSS视频直播点播平台&#xff0c;集视频直播、点播、转码、管理、录像、检索、时移回看等功能于一体&#xff0c;可提供音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务。 用户使用EasyDSS平台对直播通道进行转推&#xff0c;发现只要关闭…

【科研绘图系列】python绘制分组点图(grouped dot plot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据函数`generateRectBoxDF` 函数主要作用参数解释逻辑流程`nmfDotPlot` 函数主要作用参数解释逻辑流程画图1画图2画图3画图4介绍 【科研绘图系列】python绘制…

Springfox、Springdoc和Swagger

Springfox、Swagger 和 Springdoc Springfox、Swagger 和 Springdoc 是用于在 Spring Boot 项目中生成API文档的工具&#xff0c;但它们之间有显著的区别和演进关系&#xff1a; 1.Swagger 简介 Swagger 是一个开源项目&#xff0c;旨在为 RESTful APIs 提供交互式文档。最…

在Spring Boot项目中如何实现获取FTP远端目录结构

Java语言实现获取FTP远端目录结构的实现方式有多种,在Spring Boot 项目中,最简单和快速的方式就是使用Spring Integration 实现FTP相关的功能。 前言 本篇的示例和演示基于Windows 的FTP 服务,关于如何在Windows 开启FTP服务可以参考: Windows 如何开启和使用FTP服务 本…

Flutter_学习记录_device_info_plus 插件获取设备信息

引入三方库device_info_plus导入头文件 import package:device_info_plus/device_info_plus.dart;获取设备信息的主要代码 DeviceInfoPlugin deviceInfoPlugin DeviceInfoPlugin(); BaseDeviceInfo deviceInfo await deviceInfoPlugin.deviceInfo;完整案例 import package…

Java高频面试之集合-10

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;详解红黑树&#xff1f;HashMap为什么不用二叉树/平衡树呢&#xff1f; 一、红黑树&#xff08;Red-Black Tree&#xff…

never_give_up

一个很有意思的题&#xff1a; never_give_up - Bugku CTF平台 注意到注释里面有1p.html&#xff0c;我们直接在源代码界面看&#xff0c;这样就不会跳转到它那个链接的&#xff1a; 然后解码可得&#xff1a; ";if(!$_GET[id]) {header(Location: hello.php?id1);exi…

Python Selenium库入门使用,图文详细。附网页爬虫、web自动化操作等实战操作。

文章目录 前言1 创建conda环境安装Selenium库2 浏览器驱动下载&#xff08;以Chrome和Edge为例&#xff09;3 基础使用&#xff08;以Chrome为例演示&#xff09;3.1 与浏览器相关的操作3.1.1 打开/关闭浏览器3.1.2 访问指定域名的网页3.1.3 控制浏览器的窗口大小3.1.4 前进/后…