简介:面向SAP Fiori应用开发者与ABAP学习者的RAP Fiori教程资料,聚焦ABAP RESTful编程模型在企业级应用开发中的落地路径,适合已具备基础ABAP知识、希望进阶掌握S/4HANA时代Fiori开发范式的技术人员。压缩包内共1个PDF文件,大小约18.31MB,内容源自SAP PRESS专业出版体系,涵盖ABAP RESTful编程模型实现、Core Data Services for ABAP、基于ABAP对象的测试驱动开发,以及Fiori应用从项目规划、环境搭建到测试部署的最佳实践,并涉及身份验证、授权与性能优化等安全议题。已有366人学习,可作为系统梳理RAP开发脉络、对照官方书籍查漏补缺的参考读物,帮助读者理解ABAP语言高级主题与Fiori应用开发的技术细节。
1. 从一本 490 页的 RAP 教程说起:它到底能帮你解决什么
手里这份资源,本质是一套围绕 ABAP RESTful Application Programming Model(下文简称 RAP)与 SAP Fiori 开发的学习资料合集,核心是一本系统讲解 RAP 编程范式的教程,外加几本配套的 ABAP 语言、CDS 数据建模、测试驱动开发方向的参考书。它不是零散的博客拼盘,而是按「架构认知 → 设计流程 → 模型实现 → 应用落地」这条线组织的,从 S/4HANA 的整体架构讲到 Fiori 应用怎么从 CDS 视图一路做到可预览的 List Report 和 Object Page。
如果你正在做 Fiori 开发,或者被安排把老式 ABAP 报表改造成 OData 服务加 Fiori 前端,这套东西的价值在于它把「为什么这么分层」和「每一步点哪里、写什么」放在了一起。适合有基础 ABAP 语法底子、能看懂 SELECT 和内部表、但对 RAP 的 managed/unmanaged 事务模型、behavior definition、service binding 这套东西还没跑通过一遍的从业者。新手可以照着步骤走,熟手能从中拿到参数边界和分层判断的依据。
2. RAP 的分层逻辑:为什么不能跳过 CDS 直接写 OData
很多人第一次接触 RAP,直觉是「我直接写个 OData 服务不就行了」,然后在 Gateway 里手搓 EntitySet,最后发现分页、过滤、草稿、权限全要自己补,越写越像在造轮子。RAP 的设计初衷就是把这类重复劳动收敛到模型层,让 CDS 视图承担数据语义,让 behavior 承担事务语义,让 service binding 只负责暴露协议。理解这条链路,比记住某个事务码重要得多。
2.1 四层结构:CDS、Behavior、Service Definition、Service Binding
RAP 的运行时可以拆成四层,每层职责清晰,混层是翻车的头号原因。
| 层 | 载体 | 职责 | 常见误用 |
|---|---|---|---|
| 数据层 | CDS View(interface / projection) | 定义字段、关联、计算字段、DCL 权限 | 把业务校验写进 CDS |
| 行为层 | Behavior Definition + Implementation | 增删改、草稿、动作、校验、确定 | 在 implementation 里直接拼 SQL |
| 服务定义层 | Service Definition | 声明暴露哪些实体、哪些操作 | 把所有实体一股脑暴露 |
| 服务绑定层 | Service Binding | 绑定 OData V2/V4、生成元数据、预览 | 在 binding 里改语义 |
interface 视图负责贴近数据库表、做基础清洗和关联;projection 视图面向消费场景,做字段裁剪和 UI 注解。这个「interface → projection」的两段式不是形式主义,它的实际收益是:当底层表结构变化时,你只改 interface,projection 和上层 UI 注解不动,前端不炸。我见过不少项目把两者合成一个视图,结果一次字段重命名牵动十几个 Fiori 应用,血泪经验。
behavior definition 里声明managed还是unmanaged是第一个关键决策。managed 模式下框架接管事务缓冲、草稿和保存,你只写校验和动作;unmanaged 模式你自己管 save sequence,灵活但责任全在你身上。判断标准很简单:新写的业务对象、没有历史遗留 save 逻辑,一律 managed;要复用已有的 BAPI 或函数组做持久化,才考虑 unmanaged。
2.2 从零建一个可预览的 List Report:可抄的步骤
下面这条链路是资源里第 4 章的主线,我按实际动手顺序重排了一遍,环境是 Eclipse 里的 ABAP Development Tools(ADT),后端为 S/4HANA 或带 RAP 能力的 NetWeaver 版本。
第一步,建 interface CDS 视图。在 ADT 里新建 Data Definition,指定define view entity,把主表和关联表挂上。
@AbapCatalog.sqlViewName: 'ZI_TRAVEL' @AccessControl.authorizationCheck: #CHECK @EndUserText.label: 'Travel Interface View' define view entity ZI_Travel as select from ztravel association [0..1] to ZI_Customer as _Customer on $projection.CustomerId = _Customer.CustomerId { key travel_id as TravelId, customer_id as CustomerId, begin_date as BeginDate, end_date as EndDate, total_price as TotalPrice, currency_code as CurrencyCode, status as Status, _Customer }sqlViewName是给经典 ABAP 运行时看的兼容名,define view entity才是 RAP 认的实体。association用$projection关联,避免字段名歧义。authorizationCheck: #CHECK表示走 DCL 权限控制,后面要补一个 DCL 文件,否则预览时可能直接报无权限。
第二步,建 projection 视图,只保留 UI 需要的字段并加语义注解。
@EndUserText.label: 'Travel Projection' @UI.headerInfo: { typeName: 'Travel', typeNamePlural: 'Travels' } define view entity ZC_Travel as projection on ZI_Travel { key TravelId, CustomerId, BeginDate, EndDate, @UI.lineItem: [{ position: 10 }] TotalPrice, CurrencyCode, Status, _Customer }projection 层是加@UI注解的地方,lineItem控制列表列,headerInfo控制详情页标题。注解写错位置不会报语法错,但前端会静默不显示,这是最常见的「玄学」问题之一。
第三步,建 behavior definition,声明 managed 和草稿能力。
managed implementation in class zbp_i_travel unique; strict ( 2 ); with draft; define behavior for ZI_Travel alias Travel persistent table ztravel draft table ztravel_d lock master total etag LastChangedAt authorization master ( instance ) { create; update; delete; field ( readonly ) TravelId, CreatedAt, CreatedBy; validation validateDates on save { field BeginDate, EndDate; } action ( features : instance ) acceptTravel result [1] $self; draft action Edit; draft action Activate optimized; draft action Discard; draft action Resume; }with draft打开草稿,lock master指定锁粒度,total etag用于并发控制。validation ... on save表示保存时触发,action声明自定义动作。strict ( 2 )是较新的严格模式,会强制你处理未使用变量等,老项目迁移时可以先降到strict ( 1 )减少改动面。
第四步,生成 behavior implementation 的骨架类,补校验逻辑。
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS validateDates FOR VALIDATE ON SAVE IMPORTING keys FOR Travel~validateDates. ENDCLASS. CLASS lhc_travel IMPLEMENTATION. METHOD validateDates. READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( BeginDate EndDate ) WITH CORRESPONDING #( keys ) RESULT DATA(travels). LOOP AT travels INTO DATA(travel). IF travel-BeginDate > travel-EndDate. APPEND VALUE #( %tky = travel-%tky ) TO failed-travel. APPEND VALUE #( %tky = travel-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = '开始日期不能晚于结束日期' ) ) TO reported-travel. ENDIF. ENDLOOP. ENDMETHOD. ENDCLASS.IN LOCAL MODE读的是事务缓冲里的未保存数据,不是数据库。failed和reported两个内表分工明确:failed 阻止保存,reported 只回显消息。把两者搞混,会出现「报错了但还是存进去了」的诡异现象。
第五步,建 Service Definition 和 Service Binding,绑定 OData V4 后在 ADT 里点 Preview 就能看到 List Report。这一步没有代码,全是向导,但要注意 binding 类型选 V4 还是 V2:Fiori Elements 的新特性基本只在 V4 上完整,V2 适合对接老前端或已有 Gateway 项目。
2.3 参数与注解:几个真正影响行为的开关
@AccessControl.authorizationCheck三档#CHECK、#NOT_REQUIRED、#MANDATORY,区别在于是否强制走 DCL。开发期图省事写#NOT_REQUIRED,上线前忘了改,权限就形同虚设,这是审计时的高频扣分项。
@UI.lineItem的position决定列顺序,importance决定在小屏上是否折叠。@UI.selectionField决定筛选栏出现哪些字段,不写就没有筛选条件,用户只能翻页找数据。
etag字段用于乐观锁,total etag挂在根实体上,子实体变更也会刷新根 etag。如果发现并发编辑时后保存的覆盖了先保存的,先查 etag 有没有正确声明。
3. 把 RAP 应用跑通之后:测试、扩展与常见翻车点
模型能预览只是起点,真正上线前还有几件事要做:给 behavior 补单元测试、给 UI 加 breakout 扩展、处理草稿表的清理。资源里第 4 章后半段和第 5 章分别覆盖了 QUnit 测试和 Overview Page 的搭建,这里挑几个实操中绕不开的点展开。
3.1 QUnit 测试:别等联调才发现校验没生效
behavior 的校验逻辑用 ABAP Unit 测最直接,但涉及 RAP 的实体操作要用 EML(Entity Manipulation Language)在测试类里模拟。
CLASS ltc_travel_test DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. METHODS setup. METHODS invalid_dates_rejected FOR TESTING. ENDCLASS. CLASS ltc_travel_test IMPLEMENTATION. METHOD invalid_dates_rejected. MODIFY ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel CREATE FIELDS ( CustomerId BeginDate EndDate TotalPrice CurrencyCode ) WITH VALUE #( ( CustomerId = 'C001' BeginDate = '20240110' EndDate = '20240105' TotalPrice = 100 CurrencyCode = 'CNY' ) ) FAILED DATA(failed) REPORTED DATA(reported). cl_abap_unit_assert=>assert_not_initial( act = failed-travel msg = '非法日期应被拒绝' ). ENDMETHOD. ENDCLASS.IN LOCAL MODE让测试不落库,FAILED内表非空即证明校验拦截成功。注意测试类要RISK LEVEL HARMLESS,否则 CI 流水线可能跳过。这套写法比手工点预览可靠得多,尤其是校验规则多的时候。
3.2 UI 扩展:breakout 与 metadata extension 的取舍
改字段标签、加一列,用 metadata extension 文件最轻,不动生成代码。要改列表的交互行为、加自定义按钮逻辑,才用 breakout。判断标准:纯展示层调整走注解,涉及事件和逻辑走扩展。资源里提到 breakout 实现 UI 扩展,实际项目里我一般先试注解,注解搞不定再上 breakout,因为 breakout 和框架版本耦合更紧,升级时容易断。
3.3 草稿表与清理:上线后第一个月必查
with draft会生成草稿表,用户点了编辑没保存就退出,草稿会一直留着。SAP 标准有清理报表,但默认周期可能很长。上线后第一个月要盯草稿表行数,配一个定期清理作业,否则表会缓慢膨胀。这不是 RAP 的缺陷,是草稿机制的固有成本,提前规划比事后救火省事。
4. 避坑与排查:五条来自实际项目的记录
现象:预览时列表空白,但 CDS 单独跑有数据。原因:projection 视图漏了@UI.lineItem注解,或者 service binding 绑定的实体不是 projection 而是 interface。 解决:先确认 binding 里暴露的实体名是ZC_开头而非ZI_,再检查 projection 的注解是否写在字段正上方。
现象:保存时报「实体未找到」,但数据明明存在。原因:behavior definition 里的persistent table写错,或lock master的 etag 字段在表里不存在。 解决:对照透明表字段逐个核对,etag 字段必须是表里的真实字段,不能是 CDS 计算字段。
现象:校验消息弹了,数据还是存进去了。原因:只往reported里塞了消息,没往failed里塞对应 key。 解决:两个内表都要 append,failed决定是否阻断,reported只负责显示。
现象:并发编辑时后保存的覆盖先保存的。原因:etag 没声明或声明在子实体上。 解决:在根实体 behavior 里加total etag LastChangedAt,并确保该字段在 update 时被刷新。
现象:OData V4 预览正常,部署到 Fiori Launchpad 后 404。原因:service binding 的路径和 Launchpad 里配置的 target mapping 不一致,或 DCL 权限在正式环境未分配。 解决:先在/IWFND/MAINT_SERVICE里确认服务已激活,再核对 target mapping 的 URL,最后查权限对象。
5. 进阶:用 EML 把 RAP 对象当内部 API 用
RAP 的价值不止于生成 Fiori 界面。behavior 定义好之后,同一套实体可以在 ABAP 程序里通过 EML 调用,相当于给你的业务对象自动配了一个类型安全的内部 API。这个用法在批量处理、接口对接、后台作业里特别顺手,比直接操作数据库表安全得多,因为校验、权限、锁全都自动生效。
" 批量创建并统一提交,失败则整体回滚 MODIFY ENTITIES OF zi_travel ENTITY Travel CREATE FIELDS ( CustomerId BeginDate EndDate TotalPrice CurrencyCode ) WITH VALUE #( FOR i = 1 WHILE i <= 100 ( CustomerId = |C{ i WIDTH = 3 ALIGN = RIGHT PAD = '0' }| BeginDate = '20240201' EndDate = '20240210' TotalPrice = i * 10 CurrencyCode = 'CNY' ) ) FAILED DATA(failed) REPORTED DATA(reported). IF failed-travel IS NOT INITIAL. ROLLBACK ENTITIES. ELSE. COMMIT ENTITIES RESPONSE OF zi_travel FAILED DATA(commit_failed) REPORTED DATA(commit_reported). ENDIF.COMMIT ENTITIES是 RAP 的事务边界,一次提交整批,ROLLBACK ENTITIES撤销缓冲。注意 EML 调用默认走权限检查,后台作业里要确认执行用户的权限,否则会静默失败。这套写法把「批量导入」从几百行手写 SQL 压缩到十几行,而且天然带校验,是我目前处理数据迁移类需求的首选。
验证方法上,我习惯在提交后立刻用READ ENTITIES回读一遍,确认落库字段和预期一致,尤其是计算字段和关联字段,它们在缓冲和数据库里的表现可能不同。这个回读习惯帮我抓到过好几次「注解生效但持久化没跟上」的问题。
从那以后我每次新建 RAP 对象,都强制走一遍「interface → projection → behavior → service binding → 预览 → EML 回读」这条完整链路,任何一环跳过,后面都要花双倍时间补。希望帮到你。
本文还有配套的精品资源,点击获取