写点什么

如何使用 Restful ABAP Programming 编程模型开发一个支持增删改查的 Fiori 应用

作者:Jerry Wang
  • 2022 年 5 月 27 日
  • 本文字数:4161 字

    阅读完需:约 14 分钟

如何使用 Restful ABAP Programming 编程模型开发一个支持增删改查的 Fiori 应用

Restful ABAP Programming 编程模式是 ABAP 这门编程语言在不断向前进化的过程中,诞生的一门新的编程模型,简称为 RAP 模型。该模型定义了一套架构体系,应用开发人员能够凭借其来高效地进行应用的端到端开发,这种应用具有与生俱来的 Restful 特质,能充分利用 HANA 平台的强大计算能力,支持云环境和 Fiori UX。



RAP 模型的三大支柱:


  • Business Service

  • Core Data Service

  • Behavior Definition



下面请跟着 Jerry 一起,通过一个实际的例子,了解一下这种全新的通过 Restful ABAP Programming 模型进行 Fiori 应用开发的步骤吧。


Jerry 还是沿用传统 ABAP On-Premises 编程培训教材里使用过的经典的 SFLIGHT 模型来作为底层数据库存储。


(1)首先创建一个数据库表 ZTRAVEL_JERRY:


@EndUserText.label : 'Database table for travel data XXX'@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE@AbapCatalog.tableCategory : #TRANSPARENT@AbapCatalog.deliveryClass : #A@AbapCatalog.dataMaintenance : #LIMITEDdefine table ztravel_jerry {  key client      : abap.clnt not null;  key travel_id   : /dmo/travel_id not null;  agency_id       : /dmo/agency_id;  customer_id     : /dmo/customer_id;  begin_date      : /dmo/begin_date;  end_date        : /dmo/end_date;  @Semantics.amount.currencyCode : 'ztravel_jerry.currency_code'  booking_fee     : /dmo/booking_fee;  @Semantics.amount.currencyCode : 'ztravel_jerry.currency_code'  total_price     : /dmo/total_price;  currency_code   : /dmo/currency_code;  description     : /dmo/description;  created_by      : syuname;  created_at      : timestampl;  last_changed_by : syuname;  last_changed_at : timestampl;
}
复制代码



因为我们在 ABAP Development Tools 里无法用事务码 SE16 手动往这张表里插入数据,所以我创建一个 ABAP 类,用 ABAP 代码往这个表里插入三条数据。



按 F9 执行这个 ABAP 类,然后看到三条数据成功插入了:



(2) 我们最终的目的是创建一个支持对这张表进行增删改查的 Fiori 应用,而 Restful ABAP Programming 模型的三大支柱之一为 Core Data Service,因此我们首先得有基于数据库表 ZTRAVEL_JERRY 的 CDS view.


所以我首先创建一个 CDS view:


@AbapCatalog.sqlViewName: 'ZVI_TRAVEL'@AbapCatalog.compiler.compareFilter: true@AbapCatalog.preserveKey: true@AccessControl.authorizationCheck: #CHECK@EndUserText.label: 'Travel data - XXX'define root view ZI_TRAVEL_JERRY as select from ztravel_jerry as Travel
/* Associations */ association [0..1] to /DMO/I_Agency as _Agency on $projection.agency_id = _Agency.AgencyID association [0..1] to /DMO/I_Customer as _Customer on $projection.customer_id = _Customer.CustomerID association [0..1] to I_Currency as _Currency on $projection.currency_code = _Currency.Currency { key travel_id, agency_id, customer_id, begin_date, end_date, @Semantics.amount.currencyCode: 'currency_code' booking_fee, @Semantics.amount.currencyCode: 'currency_code' total_price, @Semantics.currencyCode: true currency_code, description,
/*-- Admin data --*/ @Semantics.user.createdBy: true created_by, @Semantics.systemDateTime.createdAt: true created_at, @Semantics.user.lastChangedBy: true last_changed_by, @Semantics.systemDateTime.lastChangedAt: true last_changed_at,
/* Public associations */ _Agency, _Customer, _Currency}
复制代码



然后创建一个 projection view,将该 view 的字段有选择性地暴露出来。


@EndUserText.label: 'Travel projection view - Processor'@AccessControl.authorizationCheck: #NOT_REQUIRED
@UI: { headerInfo: { typeName: 'Travel', typeNamePlural: 'Travels', title: { type: #STANDARD, value: 'TravelID' } } }
@Search.searchable: true
define root view entity ZC_TRAVEL_JERRY as projection on ZI_TRAVEL_JERRY { @UI.facet: [ { id: 'Travel', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Travel', position: 10 } ]
@UI: { lineItem: [ { position: 10, importance: #HIGH } ], identification: [ { position: 10, label: 'Travel ID [1,...,99999999]' } ] } @Search.defaultSearchElement: true key travel_id as TravelID,
@UI: { lineItem: [ { position: 20, importance: #HIGH } ], identification: [ { position: 20 } ], selectionField: [ { position: 20 } ] } @Consumption.valueHelpDefinition: [{ entity : {name: '/DMO/I_Agency', element: 'AgencyID' } }]
@ObjectModel.text.element: ['AgencyName'] ----meaning? @Search.defaultSearchElement: true agency_id as AgencyID, _Agency.Name as AgencyName,
@UI: { lineItem: [ { position: 30, importance: #HIGH } ], identification: [ { position: 30 } ], selectionField: [ { position: 30 } ] } @Consumption.valueHelpDefinition: [{ entity : {name: '/DMO/I_Customer', element: 'CustomerID' } }]
@ObjectModel.text.element: ['CustomerName'] @Search.defaultSearchElement: true customer_id as CustomerID,
@UI.hidden: true _Customer.LastName as CustomerName,
@UI: { lineItem: [ { position: 40, importance: #MEDIUM } ], identification: [ { position: 40 } ] } begin_date as BeginDate,
@UI: { lineItem: [ { position: 41, importance: #MEDIUM } ], identification: [ { position: 41 } ] } end_date as EndDate,
@UI: { lineItem: [ { position: 50, importance: #MEDIUM } ], identification: [ { position: 50, label: 'Total Price' } ] } @Semantics.amount.currencyCode: 'CurrencyCode' total_price as TotalPrice,
@Consumption.valueHelpDefinition: [{entity: {name: 'I_Currency', element: 'Currency' }}] currency_code as CurrencyCode,
@UI.identification: [ { position: 60, label: 'Remarks' } ] description as Description,
@UI.hidden: true last_changed_at as LastChangedAt
}
复制代码


大家可以注意到,这个 projection view 里包含了很多 @UI 注解,作用和 Fiori Elements 一样,作为元数据,告诉对应的渲染框架,运行时这些字段应该以什么样的方式渲染在 Fiori UI 上。



(3) 现在三大支柱之一的 Core Data Service 已经就位了,接下来我们基于前一步得到的 projection view 创建 Business Service. 选中 projection view,右键选择 New Service Definition:



这个服务定义的第一条记录,就是通过 ABAP expose 关键字把 projection view ZC_TRAVEL_JERRY 暴露出来,模型名称为 TravelProcessor:



@EndUserText.label: 'Service Defintion for ZC_Travel_JERRY'define service ZUI_C_TRAVEL_JERRY {  expose ZC_TRAVEL_JERRY as TravelProcessor;  expose /DMO/I_Customer as Passenger;  expose /DMO/I_Agency as TravelAgency;  expose /DMO/I_Airport as Airport;  expose I_Currency as Currency;  expose I_Country as Country;}
复制代码


然后基于这个 Service Definition 创建一个 Service Binding,可以简单把 Service Binding 理解成 Service Definition 的一个实例:




Service Binding 创建完毕后,点击 Activate 激活:



之前 Service Definition 里用 expose 关键字暴露并指定成的模型 TravelProcessor 此时就可见了,双击:



双击后会自动打开一个链接,一个 Fiori 应用就呈现在我们眼前了。我们没有进行一行的 JavaScript web 编程,就得到了一个专业的支持高级搜索的 Fiori 应用,能查看底层数据库表 ZTRAVEL_JERRY 的内容。



(4) 至此我们已经了解了 Restful ABAP Programming 模型的前两大支柱,还剩下 Behavior Definition. 既然 RAP 的口号是打造具有 Restful 特性的应用,但到目前为止我们还没有感受到 RAP 对 Restful 的支持,这有待 Behavior Definition 来完成。


选中之前创建的 CDS view,创建一个新的 Behavior Definition:



实现类型指定为 Managed:



我们可以看到这个 Behavior Definition 的定义里,又多了一些新的 ABAP 关键字。这个 Behavior Definition 负责定义底层模型的 Transaction Behavior,即代码第 18 到 20 行的 create,update,delete.



当然增删改查的功能光定义不行,还得创建其对应的实现。上图 Definition 中已经指定了实现这些行为的 ABAP 类名称为 ZCL_BP_I_TRAVEL_M_JERRY. 为此,右键选择 New Behavior Implementation:



创建这个特殊的 ABAP 实现类:



这个实现类里面也不需要开发人员手动编写代码来完成对底层数据库表的增删改查操作——既然能称之为一个编程模型,那么这些通用的功能都通过框架类 CL_ABAP_BEHAVIOR_HANDLER 统一完成了,应用开发人员只需要定义一个对该类的声明即可。




把这一步创建好的 Behavior Definition 模型和其实现全部激活,然后回到我们之前浏览器里打开的 Fiori 应用,刷新,会发现多了 Create 和 Delete 两个按钮,这意味着该应用对创建和删除的支持也已经自动可用了。



同之前的搜索功能一样,这些功能的自动获得,都是建立在应用开发人员一行 JavaScript 代码都不用编写的基础上的,由此大家感受到了 Restful ABAP Programming 模型的强大威力了吗?


总结


本文介绍了通过 Restful ABAP Programming 编程模型开发前端应用的方式。该模型定义了一套架构体系,应用开发人员能够凭借其来高效地进行应用的端到端开发,这种应用具有与生俱来的 Restful 特质,能充分利用 HANA 平台的强大计算能力,支持云环境和 Fiori UX.

发布于: 2022 年 05 月 27 日阅读数: 22
用户头像

Jerry Wang

关注

🏆InfoQ写作平台-签约作者🏆 2017.12.03 加入

SAP成都研究院开发专家,SAP社区导师,SAP中国技术大使。2007 年从电子科技大学计算机专业硕士毕业后加入 SAP 成都研究院工作至今。工作中使用 ABAP, Java, JavaScript 和 TypeScript 进行开发。

评论

发布
暂无评论
如何使用 Restful ABAP Programming 编程模型开发一个支持增删改查的 Fiori 应用_RESTful_Jerry Wang_InfoQ写作社区