Dieses End-to-End Tutorial fuehrt Sie durch den kompletten Entwicklungsprozess einer RAP-Anwendung - von der leeren Datenbanktabelle bis zur fertigen Fiori Elements App. Sie erstellen eine Projektverwaltung mit vollstaendiger CRUD-Funktionalitaet.
Zielsetzung
Am Ende dieses Tutorials haben Sie:
- Eine Datenbanktabelle fuer Projektdaten
- Interface und Projection CDS Views
- Behavior Definition mit CRUD und Custom Actions
- OData V4 Service fuer die API
- Funktionierende Fiori Elements UI
Voraussetzungen
- SAP BTP ABAP Environment oder S/4HANA 2022+
- ABAP Development Tools (ADT) fuer Eclipse
- Grundkenntnisse in ABAP (SQL, Datentypen)
Fuer den Einstieg in die Entwicklungsumgebung siehe ABAP Cloud Entwicklungsumgebung einrichten.
Architekturueberblick
┌─────────────────────────────────────────────────────────┐│ SAP Fiori Elements UI ││ (automatisch aus Annotations generiert) │├─────────────────────────────────────────────────────────┤│ OData V4 Service ││ Service Binding (SRVB): ZUI_PROJECT_O4 │├─────────────────────────────────────────────────────────┤│ Service Definition (SRVD) ││ ZUI_PROJECT_O4 │├─────────────────────────────────────────────────────────┤│ Projection Layer (C_*) ││ CDS View: ZC_PROJECT Behavior: projection ││ + Metadata Extension (UI Annotations) │├─────────────────────────────────────────────────────────┤│ Business Object Layer (I_*) ││ CDS View: ZI_PROJECT Behavior Definition (BDEF) ││ Behavior Implementation (BIL) │├─────────────────────────────────────────────────────────┤│ Datenbanktabelle: ZPROJECT │└─────────────────────────────────────────────────────────┘Schritt 1: Datenbanktabelle erstellen
Die Datenbanktabelle bildet die Persistenzschicht unseres Business Objects.
ADT Workflow
- Rechtsklick auf Ihr Package → New → Other ABAP Repository Object
- Suche: Database Table → Next
- Name:
ZPROJECT| Description:Project Master Data - Finish
Tabellendefinition
@EndUserText.label : 'Project Master Data'@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE@AbapCatalog.tableCategory : #TRANSPARENT@AbapCatalog.deliveryClass : #A@AbapCatalog.dataMaintenance : #RESTRICTEDdefine table zproject { key client : abap.clnt not null; key project_id : abap.char(10) not null; project_name : abap.char(100); description : abap.string(1024); responsible_person : abap.char(40); start_date : abap.dats; end_date : abap.dats; @Semantics.amount.currencyCode : 'zproject.currency_code' budget : abap.curr(15,2); currency_code : abap.cuky; status : abap.char(1); priority : abap.char(1);
@Semantics.user.createdBy : true created_by : abap.char(12); @Semantics.systemDateTime.createdAt : true created_at : timestampl; @Semantics.user.lastChangedBy : true last_changed_by : abap.char(12); @Semantics.systemDateTime.lastChangedAt : true last_changed_at : timestampl;}Aktivieren: Ctrl+F3
Die @Semantics-Annotationen ermöglichen automatisches Befuellen von Audit-Feldern durch das RAP Framework.
Schritt 2: Interface CDS View (I_*)
Die Interface View definiert das semantische Datenmodell des Business Objects. Sie ist die stabile API fuer andere Konsumenten.
ADT Workflow
- Rechtsklick auf Package → New → Other ABAP Repository Object
- Suche: Data Definition → Next
- Name:
ZI_PROJECT| Description:Project - Interface View - Template: Define Root View Entity
- Finish
CDS View Definition
@AccessControl.authorizationCheck: #NOT_REQUIRED@EndUserText.label: 'Project - Interface View'
define root view entity ZI_PROJECT as select from zproject{ key project_id as ProjectId, project_name as ProjectName, description as Description, responsible_person as ResponsiblePerson, start_date as StartDate, end_date as EndDate,
@Semantics.amount.currencyCode: 'CurrencyCode' budget as Budget,
@Semantics.currencyCode: true currency_code as CurrencyCode,
status as Status, priority as Priority,
@Semantics.user.createdBy: true created_by as CreatedBy,
@Semantics.systemDateTime.createdAt: true created_at as CreatedAt,
@Semantics.user.lastChangedBy: true last_changed_by as LastChangedBy,
@Semantics.systemDateTime.lastChangedAt: true last_changed_at as LastChangedAt}Wichtig: Das Keyword root kennzeichnet die Wurzel-Entity des Business Objects. Mehr zu CDS Views unter ABAP CDS Views.
Schritt 3: Behavior Definition (BDEF)
Die Behavior Definition deklariert, was mit dem Business Object gemacht werden kann (CRUD, Actions, Validations, Determinations).
ADT Workflow
- Rechtsklick auf
ZI_PROJECT→ New Behavior Definition - Implementation Type: Managed
- Finish
BDEF Code
managed implementation in class zbp_i_project unique;strict ( 2 );
define behavior for ZI_PROJECT alias Projectpersistent table zprojectlock masterauthorization master ( instance )etag master LastChangedAt{ // Standard CRUD Operationen create; update; delete;
// Feldsteuerung field ( readonly ) ProjectId; field ( readonly ) CreatedBy, CreatedAt, LastChangedBy, LastChangedAt; field ( numbering : managed ) ProjectId;
// Validierungen validation validateDates on save { field StartDate, EndDate; } validation validateBudget on save { field Budget; }
// Determinations (automatische Werte) determination setDefaultStatus on modify { create; }
// Custom Actions action ( features : instance ) completeProject result [1] $self; action ( features : instance ) cancelProject result [1] $self;
// Feldmapping zur Datenbanktabelle mapping for zproject { ProjectId = project_id; ProjectName = project_name; Description = description; ResponsiblePerson = responsible_person; StartDate = start_date; EndDate = end_date; Budget = budget; CurrencyCode = currency_code; Status = status; Priority = priority; CreatedBy = created_by; CreatedAt = created_at; LastChangedBy = last_changed_by; LastChangedAt = last_changed_at; }}Erklaerung der Schluesselwoerter:
managed: RAP Framework uebernimmt CRUD automatischstrict ( 2 ): Aktiviert Best-Practice-Pruefungennumbering : managed: Automatische ID-Vergabeetag master: Optimistic Locking fuer Parallelzugriff
Fuer Details zu Managed vs. Unmanaged siehe RAP Managed vs Unmanaged.
Schritt 4: Behavior Implementation (BIL)
Die Behavior Implementation enthaelt die ABAP-Logik fuer Validations, Determinations und Actions.
Automatisch generierte Klasse
Nach Aktivierung der BDEF generiert ADT die Klasse ZBP_I_PROJECT. Oeffnen Sie diese und implementieren Sie die Local Handler Class:
CLASS lhc_project DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS: get_instance_features FOR INSTANCE FEATURES IMPORTING keys REQUEST requested_features FOR Project RESULT result,
validateDates FOR VALIDATE ON SAVE IMPORTING keys FOR Project~validateDates,
validateBudget FOR VALIDATE ON SAVE IMPORTING keys FOR Project~validateBudget,
setDefaultStatus FOR DETERMINE ON MODIFY IMPORTING keys FOR Project~setDefaultStatus,
completeProject FOR MODIFY IMPORTING keys FOR ACTION Project~completeProject RESULT result,
cancelProject FOR MODIFY IMPORTING keys FOR ACTION Project~cancelProject RESULT result.ENDCLASS.
CLASS lhc_project IMPLEMENTATION.
METHOD get_instance_features. READ ENTITIES OF zi_project IN LOCAL MODE ENTITY Project FIELDS ( Status ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_project) FAILED failed.
result = VALUE #( FOR ls_project IN lt_project ( %tky = ls_project-%tky %features-%action-completeProject = COND #( WHEN ls_project-Status = 'A' THEN if_abap_behv=>fc-o-enabled ELSE if_abap_behv=>fc-o-disabled ) %features-%action-cancelProject = COND #( WHEN ls_project-Status = 'A' OR ls_project-Status = 'N' THEN if_abap_behv=>fc-o-enabled ELSE if_abap_behv=>fc-o-disabled ) ) ). ENDMETHOD.
METHOD validateDates. READ ENTITIES OF zi_project IN LOCAL MODE ENTITY Project FIELDS ( StartDate EndDate ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_project).
LOOP AT lt_project INTO DATA(ls_project). IF ls_project-EndDate IS NOT INITIAL AND ls_project-EndDate < ls_project-StartDate. APPEND VALUE #( %tky = ls_project-%tky %element-EndDate = if_abap_behv=>mk-on ) TO failed-project.
APPEND VALUE #( %tky = ls_project-%tky %element-EndDate = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Enddatum muss nach Startdatum liegen' ) ) TO reported-project. ENDIF. ENDLOOP. ENDMETHOD.
METHOD validateBudget. READ ENTITIES OF zi_project IN LOCAL MODE ENTITY Project FIELDS ( Budget ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_project).
LOOP AT lt_project INTO DATA(ls_project). IF ls_project-Budget < 0. APPEND VALUE #( %tky = ls_project-%tky %element-Budget = if_abap_behv=>mk-on ) TO failed-project.
APPEND VALUE #( %tky = ls_project-%tky %element-Budget = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Budget darf nicht negativ sein' ) ) TO reported-project. ENDIF. ENDLOOP. ENDMETHOD.
METHOD setDefaultStatus. READ ENTITIES OF zi_project IN LOCAL MODE ENTITY Project FIELDS ( Status ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_project).
MODIFY ENTITIES OF zi_project IN LOCAL MODE ENTITY Project UPDATE FIELDS ( Status Priority ) WITH VALUE #( FOR ls_project IN lt_project WHERE ( Status IS INITIAL ) ( %tky = ls_project-%tky Status = 'N' Priority = 'M' ) ) REPORTED DATA(reported_modify). ENDMETHOD.
METHOD completeProject. MODIFY ENTITIES OF zi_project IN LOCAL MODE ENTITY Project UPDATE FIELDS ( Status ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky Status = 'C' ) ) FAILED failed REPORTED reported.
READ ENTITIES OF zi_project IN LOCAL MODE ENTITY Project ALL FIELDS WITH CORRESPONDING #( keys ) RESULT result. ENDMETHOD.
METHOD cancelProject. MODIFY ENTITIES OF zi_project IN LOCAL MODE ENTITY Project UPDATE FIELDS ( Status ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky Status = 'X' ) ) FAILED failed REPORTED reported.
READ ENTITIES OF zi_project IN LOCAL MODE ENTITY Project ALL FIELDS WITH CORRESPONDING #( keys ) RESULT result. ENDMETHOD.
ENDCLASS.Status-Werte: N = Neu, A = Aktiv, C = Abgeschlossen, X = Abgebrochen
Fuer mehr Details zu Validations und Determinations siehe RAP Determinations und Validations.
Schritt 5: Projection CDS View (C_*)
Die Projection View ist die UI-spezifische Sicht auf das Business Object. Sie definiert, welche Felder fuer eine bestimmte App sichtbar sind.
ADT Workflow
- Rechtsklick auf Package → New → Data Definition
- Name:
ZC_PROJECT| Description:Project - Projection View - Template: Define Projection View
- Finish
Projection View Code
@EndUserText.label: 'Project - Projection View'@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true@Search.searchable: true
define root view entity ZC_PROJECT provider contract transactional_query as projection on ZI_PROJECT{ key ProjectId,
@Search.defaultSearchElement: true @Search.fuzzinessThreshold: 0.8 ProjectName,
Description,
@Search.defaultSearchElement: true ResponsiblePerson,
StartDate, EndDate,
@Semantics.amount.currencyCode: 'CurrencyCode' Budget,
@Semantics.currencyCode: true CurrencyCode,
@ObjectModel.text.element: ['StatusText'] Status, case Status when 'N' then 'Neu' when 'A' then 'Aktiv' when 'C' then 'Abgeschlossen' when 'X' then 'Abgebrochen' else 'Unbekannt' end as StatusText : localized,
@ObjectModel.text.element: ['PriorityText'] Priority, case Priority when 'H' then 'Hoch' when 'M' then 'Mittel' when 'L' then 'Niedrig' else 'Unbekannt' end as PriorityText : localized,
CreatedBy, CreatedAt, LastChangedBy, LastChangedAt}Hinweis: provider contract transactional_query aktiviert die RAP-Transaktionsunterstuetzung. Die case-Ausdruecke erzeugen lesbare Texte fuer Status und Prioritaet.
Schritt 6: Projection Behavior Definition
Die Projection BDEF bestimmt, welche Operationen auf der Projection-Ebene verfuegbar sind.
ADT Workflow
- Rechtsklick auf
ZC_PROJECT→ New Behavior Definition - Implementation Type: Projection
- Finish
Projection BDEF Code
projection;strict ( 2 );
define behavior for ZC_PROJECT alias Project{ use create; use update; use delete;
use action completeProject; use action cancelProject;}Das use Keyword delegiert die Operationen an die Interface-Ebene.
Schritt 7: Metadata Extension (UI Annotations)
Die Metadata Extension definiert das UI-Layout der Fiori Elements App.
ADT Workflow
- Rechtsklick auf
ZC_PROJECT→ New Metadata Extension - Name:
ZC_PROJECT - Finish
Metadata Extension Code
@Metadata.layer: #CORE
annotate entity ZC_PROJECT with{ @UI.headerInfo: { typeName: 'Projekt', typeNamePlural: 'Projekte', title: { value: 'ProjectName' }, description: { value: 'ProjectId' } }
@UI.facet: [ { id: 'GeneralInfo', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Allgemeine Informationen', position: 10 }, { id: 'Dates', purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, targetQualifier: 'Dates', label: 'Zeitraum', position: 20 }, { id: 'Financial', purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, targetQualifier: 'Financial', label: 'Budget', position: 30 } ]
@UI: { lineItem: [{ position: 10, importance: #HIGH }], identification: [{ position: 10 }], selectionField: [{ position: 10 }] } ProjectId;
@UI: { lineItem: [{ position: 20, importance: #HIGH }], identification: [{ position: 20 }], selectionField: [{ position: 20 }] } ProjectName;
@UI: { identification: [{ position: 30 }] } Description;
@UI: { lineItem: [{ position: 30 }], identification: [{ position: 40 }], selectionField: [{ position: 30 }] } ResponsiblePerson;
@UI: { lineItem: [{ position: 40 }], fieldGroup: [{ qualifier: 'Dates', position: 10 }] } StartDate;
@UI: { lineItem: [{ position: 50 }], fieldGroup: [{ qualifier: 'Dates', position: 20 }] } EndDate;
@UI: { lineItem: [{ position: 60 }], fieldGroup: [{ qualifier: 'Financial', position: 10 }] } Budget;
@UI.hidden: true CurrencyCode;
@UI: { lineItem: [{ position: 70, importance: #HIGH, criticality: 'StatusCriticality' }], identification: [{ position: 50 }], selectionField: [{ position: 40 }] } @UI.textArrangement: #TEXT_ONLY Status;
@UI: { lineItem: [{ position: 80 }], identification: [{ position: 60 }] } @UI.textArrangement: #TEXT_ONLY Priority;
@UI: { lineItem: [{ position: 100, type: #FOR_ACTION, dataAction: 'completeProject', label: 'Abschliessen' }] } @UI: { identification: [{ position: 100, type: #FOR_ACTION, dataAction: 'completeProject', label: 'Projekt abschliessen' }] } @UI: { lineItem: [{ position: 110, type: #FOR_ACTION, dataAction: 'cancelProject', label: 'Abbrechen' }] } @UI: { identification: [{ position: 110, type: #FOR_ACTION, dataAction: 'cancelProject', label: 'Projekt abbrechen' }] }}Mehr zu UI Annotations unter CDS Annotations.
Schritt 8: Service Definition (SRVD)
Die Service Definition bestimmt, welche Entities ueber den OData Service exponiert werden.
ADT Workflow
- Rechtsklick auf Package → New → Other ABAP Repository Object
- Suche: Service Definition → Next
- Name:
ZUI_PROJECT_O4 - Finish
Service Definition Code
@EndUserText.label: 'Project Service Definition'define service ZUI_PROJECT_O4 { expose ZC_PROJECT as Project;}Schritt 9: Service Binding (SRVB)
Das Service Binding erstellt den eigentlichen OData Endpoint.
ADT Workflow
- Rechtsklick auf Package → New → Other ABAP Repository Object
- Suche: Service Binding → Next
- Name:
ZUI_PROJECT_O4 - Binding Type: OData V4 - UI
- Service Definition:
ZUI_PROJECT_O4 - Finish
Aktivierung und Publish
- Aktivieren:
Ctrl+F3 - Im Service Binding Editor: Publish klicken
- Nach erfolgreichem Publish: Entity
Projectmarkieren → Preview klicken
Der Browser oeffnet die Fiori Elements Anwendung.
Haeufige Fehler und Loesungen
Fehler: “No behavior implementation found”
Ursache: Die Behavior Implementation Klasse existiert nicht oder ist nicht aktiviert.
Loesung:
- Oeffnen Sie die BDEF
- Rechtsklick → Navigate → Behavior Implementation
- Aktivieren Sie die Klasse mit
Ctrl+F3
Fehler: “Field X is not mapped”
Ursache: Ein CDS-Feld hat kein entsprechendes Mapping zur Datenbanktabelle.
Loesung: Ergaenzen Sie das Mapping in der BDEF:
mapping for zproject{ MissingField = missing_field;}Fehler: “Authorization check failed”
Ursache: @AccessControl.authorizationCheck: #CHECK ist gesetzt, aber keine Access Control existiert.
Loesung: Aendern Sie die Annotation zu #NOT_REQUIRED oder erstellen Sie eine Access Control (DCL).
Fehler: “Draft table not found”
Ursache: Draft ist in der BDEF aktiviert (with draft;), aber die Draft-Tabelle existiert nicht.
Loesung: Erstellen Sie die Draft-Tabelle oder entfernen Sie with draft; aus der BDEF.
Weitere Loesungen unter ABAP Cloud Fehler und Loesungen.
Naechste Schritte
Mit diesem Grundgeruest koennen Sie die Anwendung erweitern:
- Draft-Funktionalitaet: Zwischenspeichern von Eingaben - siehe RAP Draft Handling
- Value Helps: Dropdown-Listen fuer Status und Prioritaet - siehe RAP Value Helps
- Berechtigungen: Instanzbasierte Autorisierung - siehe RAP Authorization
- Feature Control: Dynamische Feld-/Button-Verfuegbarkeit - siehe RAP Feature Control
- Assoziationen: Untergeordnete Entities (z.B. Projektaufgaben) - siehe RAP Basics
Fuer ein interaktives Einsteiger-Tutorial mit Schritt-fuer-Schritt-Screenshots siehe RAP Tutorial Teil 1: Deine erste Fiori App.
Zusammenfassung
Dieses Tutorial hat den vollstaendigen RAP-Entwicklungszyklus durchlaufen:
| Schicht | Artefakt | Zweck |
|---|---|---|
| Persistenz | ZPROJECT (Table) | Datenspeicherung |
| Datenmodell | ZI_PROJECT (CDS) | Semantisches Modell, Business API |
| Verhalten | BDEF + BIL | CRUD, Validations, Actions |
| Projection | ZC_PROJECT (CDS) | UI-spezifische Sicht |
| UI | Metadata Extension | Fiori Layout Annotations |
| Service | SRVD + SRVB | OData Endpoint |
Mit dem RAP Managed Szenario uebernimmt das Framework die komplette CRUD-Logik. Sie konzentrieren sich auf die Geschaeftslogik in Validations, Determinations und Actions. Fuer komplexere Anforderungen mit Legacy-Integration siehe RAP Managed vs Unmanaged.