matinal:SAP ABAP 发布HTTP RestFul服务全过程解析(五)

1. 背景介绍

RESTful是一种网络应用程序的设计风格和开发方式。REST是Representational State Transfer的简称,中文翻译为“表述性状态转移”。单从定义上来理解REST可能并不是很好理解,对于刚刚接触这一概念的同学,可以将REST理解为一种设计风格,它描述了一个架构样式的网络系统,比如 web 应用程序。

SAP支持ABAP语言构建RESTful的应用程序,使用ABAP RESTful编程模型可以快速开发SAP Fiori应用程序,或是web服务接口。
2. 原理与架构

SAP的ABAP RESTful Programming Model提供了一套标准的架构,使用这套架构可以非常方便地开发端到端的应用程序,而且天然具有RESTful的特性。其架构图如下:
 

这套架构包含3层:

    * Data Modeling & Behavior: 数据模型 & 行为层;在这一层主要完成“CDS数据建模”,“模型行为定义”,以及“行为实现”三项工作。

        - 基于CDS(Core Data Services)的数据建模在此就不过多的解释,CDS是利用HANA高性能的一个有力工具;

        - 行为定义(Behavior Definition)简称BDEF,其使用的BDL(Behavior Definition Language)完成,用来支持业务模型的各种操作,例如CREATE,UPDATE,DETETE等行为,行为定义主要是服务于这个应用程序的各种事务操作。

        - 对于各种“行为”的实现逻辑,是通过ABAP代码来实现的,也即实现ABAP对应Class中的各种对应的方法,例如CREATE,UPDATE,DETETE等。

    * Business Service Provisioning: 业务服务准备层;在这一层主要完成各种“服务”的定义的和实现。

        - Service Definition:服务定义,也即是对上一步中数据模型的映射,有哪些数据和行为是需要以“服务”的形式暴露出来。

        - Service Binding: 在服务绑定中,会完成具体“协议protocol”的实施,以及确定具有提供给consumer的服务类型。(一个Service Definition可以有一个或多个Service Binding)。

    * Service Consumption: 服务消费层;在这一层,各种暴露出来的服务以OData的形式提供给Fiori或者其他前端应用程序进行使用。
3. 建立模型&发布服务

数据建模层的Core Data Services(CDS)的实现是基于底层的数据库表,在CDS层可以使用并直接操作数据库表中的原始数据;

在服务准备层,可以进一步通过CDS Project View将于前台应用程序相关的字段暴露出来,在Projection View中,可用通过UI annotation“注解” 来控制具体字段在的前台UI的显示方式。

通过Service Definition,可以进一步定义哪些数据会被暴露成具有的Business Service。

通过Service Binding,可以绑定一个定义好的service到一个CS(Client-Server)架构的通信协议,例如我们所熟知的OData。同时,使用Service Binding可以完成SAP Fiori Element的预览,在预览中看到应用呈现的具体效果。

至此,我们已经介绍了从底层DB table建模开始到服务发布的过程,通过以上步骤,已经可以完成一个read-only的应用程序开发(可以通过这个App完成数据展示和查询的功能)。
 

4. 行为的定义与增强

如果除了显示和查询外,应用程序还需要有更丰富的行为,我们则可以通过定义“行为 Behavior”和实施“Action & Validation”来实现。

Behavior Definition可以进一步定义对数据的创建、更新、删除(CREATE、UPDATE、DELETE)等操作;在Behavior implementation中可以通过ABAP代码进一步完成具体的创建、更新、删除逻辑(在这一步中,相关的创建、更新、删除ABAP代码会自动生成,我们只需要简单地定义下实现类的声明即可,非常方便)。

除了对于数据的“增、删、改、查”等基础功能,在实际的业务中可能还存在对于“数据的有效性校验”等需求,对于这个需求,可用通过增加实例的“Validation”的方式实现;对于更复杂的业务逻辑,可以进一步同时使用增加“Action”的方式来实现,例如在前台UI点击某一button后,执行某一操作等类似的需求。
 

5. 小结

可以看到,SAP提供了一套非常方便的ABAP RESTful编程框架,开发人员可以基于这套框架,轻松地创建SAP Fiori应用程序或是其他Web服务,并不需要了解具体的底层技术细节,这也让开发者有了更多的时间专注于业务逻辑。这种技术趋势,更符合企业的实际需求。

SAP的ABAP RESTful编程框架不仅适用用on-premise的场景,其同样适用于SAP Cloud Platform上的开发。因此,对于ABAPer而言,使用ABAP RESTful在Cloud上快速构建、发布应用也是非常方便的。
 

网上有很多实现的方式都是通过 IF_HTTP_EXTENSION 接口实现的,这次用的方式不一样。
具体过程如下:
一、代码过程

    使用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.


2.对请求添加Basic Authentication账号密码,否则无法获取。

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

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

2、正确的token

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值