2016年时,Jerry曾经写过一系列关于SAP Fiori Smart Template(现在更名为Fiori Elements了)的博客,介绍了所谓的MDD开发方法论 - Metadata Driven Development,即通过开发维护了对应annotation(注解)的CDS view,结合SAP WebIDE,能够花费最少的编程代价,就能够在短时间内获得一个支持增删改查的Fiori应用。

这个系列的博客集可以在Jerry这篇公众号文章里获得:Jerry的通过CDS view + Smart Template 开发Fiori应用的blog合集

三年的时间过去了,ABAP在不断向前进化,如今我们有了新的编程模型:Restful ABAP Programming模型,简称为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 : #LIMITED
define 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模型的强大威力了吗?

后续Jerry会继续介绍如何给这个Fiori应用底层使用的模型增添Action和Validation功能,敬请期待。

要获取更多Jerry的原创文章,请关注公众号"汪子熙":

30分钟用Restful ABAP Programming模型开发一个支持增删改查的Fiori应用的更多相关文章

  1. 如何基于Restful ABAP Programming模型开发并部署一个支持增删改查的Fiori应用

    Jerry之前的文章30分钟用Restful ABAP Programming模型开发一个支持增删改查的Fiori应用 发布之后,有朋友问我,"没错, 我是在你的文章里看到了Fiori应用的 ...

  2. 使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序

    使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序 不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻 ...

  3. Jerry带您了解Restful ABAP Programming模型系列之三:云端ABAP应用调试

    Jerry的Restful ABAP Programming模型介绍系列的前两篇文章: 30分钟用Restful ABAP Programming模型开发一个支持增删改查的Fiori应用 Jerry带 ...

  4. Jerry带您了解Restful ABAP Programming模型系列之二:Action和Validation的实现

    相信通过Jerry的前一篇文章 30分钟用Restful ABAP Programming模型开发一个支持增删改查的Fiori应用,想必大家对Restful ABAP Programming模型已经有 ...

  5. ThinkPHP 的模型使用对数据库增删改查(五)

    原文:ThinkPHP 的模型使用对数据库增删改查(五) ThinkPHP 的模型使用 // 直接连接数据库,但是得先去配置文件中配置下才行 class IndexAction extends Act ...

  6. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_3-2.使用Mybatis注解开发视频列表增删改查

    笔记 2.使用Mybatis注解开发视频列表增删改查     讲解:使用Mybatis3.x注解方式 增删改查实操, 控制台打印sql语句              1.控制台打印sql语句      ...

  7. 基于gin的golang web开发:mysql增删改查

    Go语言访问mysql数据库需要用到标准库database/sql和mysql的驱动.标准库的Api使用比较繁琐这里再引入另一个库github.com/jmoiron/sqlx. go get git ...

  8. 使用SAP Cloud Application Programming模型开发OData的一个实际例子

    刚刚过去的SAP TechEd上,SAP CTO Juergen Mueller向外界传递了一个重要的信息:身处云时代大环境下的SAP从业者,在SAP云平台上该如何选择适合自己的开发方式? Juerg ...

  9. Mock.js简易教程,脱离后端独立开发,实现增删改查功能(转)

    在我们的生产实际中,后端的接口往往是较晚才会出来,并且还要写接口文档,于是我们的前端的许多开发都要等到接口给我们才能进行,这样对于我们前端来说显得十分的被动,于是有没有可以制造假数据来模拟后端接口呢, ...

随机推荐

  1. ES6深入浅出-4 迭代器与生成器-4.总结

    yield的值就是外面调用next得到的值 ES6给的新的语法,如果你给任何一个对象添加一个Symbol.interator的key,同时它的值是一个生成器. 下面选中的就是生成器.生成返回的东西是迭 ...

  2. 软件定义网络基础---SDN的主流构架

    一:基于不同标准的主流构架 二: ONF定义的SDN基本构架 (一) 四个平面.两大接口 三:四个平面 (一)数据平面 数据平面是由若干网元(Netword Element)构成,每个网元包括一个或多 ...

  3. Redis的特性及运用

    Redis特性 一个产品的使用场景肯定是需要根据产品的特性,先列举一下Redis的特点: 读写性能优异 持久化 数据类型丰富 单线程 数据自动过期 发布订阅 分布式 这里我们通过几个场景,不同维度说下 ...

  4. Java 终于在 Java 8 中引入了 Lambda 表达式。也称之为闭包或者匿名函数。

    本文首发于 blog.zhaochunqi.com 转载请注明 blog.zhaochunqi.com 根据JSR 335, Java 终于在 Java 8 中引入了 Lambda 表达式.也称之为闭 ...

  5. CEIWEI USBMonitor USB监控精灵 v2.3.2 USB过滤驱动 USB监控

    CEIWEI USBMonitor USB监控精灵 是一款监控USB端口协议分析软件,用于监控和分析USB设备协议,可以拦截.记录USB软件程序操作USB设备的In.Out数据包.支持监控分析USB票 ...

  6. Spring切面编程AOP

  7. 022 Android .9图片的含义及制作教程

    1.图片(.9.png格式)的概念 (1)9patch图片是andriod app开发里一种特殊的图片形式,文件的扩展名为:.9.png (2)9patch图片的作用就是在图片拉伸的时候保证其不会失真 ...

  8. Python05之常用操作符

    主要有三类:算数运算符,比较运算符,逻辑运算符 一.算数运算符: 加(+)减(-)乘(*)除(/)幂运算(**)地板除(//)取余数(%) 注:/和//的区别: 数据1 / 数据2 = 数据3   ( ...

  9. Python——多态、检查类型

    一.多态 Python变量并不需要声明类型,同一个变量可以在不同的时间引用不同的对象,当一个变量在调用同一个方法,可以呈现出多种行为,而具体呈现出哪种行为由该变量引用的对象来决定,这就是多态. 先看一 ...

  10. C 语言字符串的比较

    C 语言字符串的比较 #include <stdio.h> #include <Windows.h> #include <string.h> int main(vo ...