RAP - Upload von Dateien (Stream)
Wie kannst du einfach Dateien in deine RAP Entität laden und diese in ABAP zur Verfügung stellen? Hier schauen wir uns einmal die Details an.
Inhaltsverzeichnis
In diesem Artikel werden wir uns eine Möglichkeit zum Upload von Dateien anschauen, dabei werden wir auf die verschiedenen Möglichkeiten zur Nutzung eingehen.
Einleitung
Der Up- und Download von Dateien gehört heute in Anwendungen zum Standard. Deshalb benötigen wir im ABAP RESTful Programming Model ebenfalls eine einfache Lösung, um dies durchzuführen. Heute werden wir uns mit dem Upload beschäftigen, also mit der Ablage einer Datei in unserer Anwendung. Dazu werden wir die Anwendung des Report Pattern um die zusätzliche Funktion erweitern.
Erweiterung
In diesem Abschnitt werden wir die Anwendung um zwei Uploads erweitern, um eine Excel Datei und eine Bild in die Anwendung zu laden.
Tabelle
Im ersten Schritt müssen wir die Tabelle erweitern. Für den Upload von Dateien benötigen wir drei Felder mit einer bestimmten Länge.
attachment : abap.rawstring(0);
mimetype : abap.char(128);
filename : abap.char(128);
Das Attachement ist die Datei in Binärform, der Mimetype beschreibt den Typen der Datei und der Filename ist der Name der Datei nach dem Upload. Die Länge der einzelnen Felder sind soweit festgeschrieben. Im ersten Schritt erweitern wir die Tabelle ZBS_DRP_ADDCURR um die 6 Felder.
define table zbs_drp_addcurr {
key client : abap.clnt not null;
key currency : waers not null;
ccomment : abap.char(60);
documentation : abap.string(0);
picture_url : abap.string(0);
last_editor : abap.char(12);
excel_attachment : abap.rawstring(0);
excel_mimetype : abap.char(128);
excel_filename : abap.char(128);
picture_attachment : abap.rawstring(0);
picture_mimetype : abap.char(128);
picture_filename : abap.char(128);
local_last_changed : abp_locinst_lastchange_tstmpl;
last_changed : abp_lastchange_tstmpl;
}
Im zweiten Schritt erweitern wir unsere Draft-Tabelle ZBS_DRP_CURRD, damit unsere Anwendung weiterhin funktioniert. Die Unterstriche entfernen wir, da wir die Felder im Core Data Service noch normalisieren.
define table zbs_drp_currd {
key client : abap.clnt not null;
key currency : waers not null;
decimals : abap.int1;
currencyisocode : abap.char(3);
alternativecurrencykey : abap.char(3);
currencyname : abap.char(40);
currencyshortname : abap.char(15);
currencycomment : abap.char(60);
documentation : abap.string(0);
pictureurl : abap.string(0);
lasteditor : abap.char(12);
excelattachment : abap.rawstring(0);
excelmimetype : abap.char(128);
excelfilename : abap.char(128);
pictureattachment : abap.rawstring(0);
picturemimetype : abap.char(128);
picturefilename : abap.char(128);
locallastchanged : abp_locinst_lastchange_tstmpl;
lastchanged : abp_lastchange_tstmpl;
"%admin" : include sych_bdl_draft_admin_inc;
}
Basis
Da wir einen Basis-View "ZBS_B_DRPAdditionalCurrency" für die Normalisierung der Felder im Datenmodell verwenden, ergänzen wir auch hier die Felder und benennen sie um. Damit passen sie dann auch zu den Feldnamen in der Draft-Tabelle.
define view entity ZBS_B_DRPAdditionalCurrency
as select from zbs_drp_addcurr
{
key currency as Currency,
ccomment as CurrencyComment,
documentation as Documentation,
picture_url as PictureURL,
last_editor as LastEditor,
excel_attachment as ExcelAttachement,
excel_mimetype as ExcelMimetype,
excel_filename as ExcelFilename,
picture_attachment as PictureAttachement,
picture_mimetype as PictureMimetype,
picture_filename as PictureFilename,
last_changed as LastChanged,
local_last_changed as LocalLastChanged
}
Interface
Im Root View des Objekts ergänzen wir auch noch entsprechend die Felder, damit sie dann im RAP Objekt zur Verfügung stehen.
define root view entity ZBS_R_DRPCurrency
as select from I_Currency
composition of many ZBS_I_DRPCurrencyCountry as _Country
association of one to one ZBS_B_DRPAdditionalCurrency as _Data on _Data.Currency = $projection.Currency
association of one to one I_BusinessUserVH as _User on _User.UserID = $projection.lasteditor
{
key Currency,
Decimals,
CurrencyISOCode,
AlternativeCurrencyKey,
_Text[ Language = $session.system_language ].CurrencyName,
_Text[ Language = $session.system_language ].CurrencyShortName,
_Data.CurrencyComment,
_Data.Documentation,
_Data.PictureURL,
_Data.LastEditor,
_Data.ExcelAttachement,
_Data.ExcelMimetype,
_Data.ExcelFilename,
_Data.PictureAttachement,
_Data.PictureMimetype,
_Data.PictureFilename,
_Data.LastChanged,
_Data.LocalLastChanged,
_Country,
_User
}
Consumption
Zum Abschluss der Erweiterung des Datenmodells, ergänzen wir noch die Felder im Consumption View.
define root view entity ZBS_C_DRPCurrency
provider contract transactional_query
as projection on ZBS_R_DRPCurrency
{
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 1.0
@Search.ranking: #HIGH
key Currency,
Decimals,
CurrencyISOCode,
AlternativeCurrencyKey,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.7
@Search.ranking: #MEDIUM
CurrencyName,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
@Search.ranking: #MEDIUM
CurrencyShortName,
CurrencyComment,
Documentation,
PictureURL,
ExcelAttachement,
ExcelMimetype,
ExcelFilename,
PictureAttachement,
PictureMimetype,
PictureFilename,
LastEditor,
_User.PersonFullName as EditorName,
_Country : redirected to composition child ZBS_C_DRPCurrencyCountry
}
Metadata Extension
In der Metadata Extension übernehmen wir ebenfalls die Felder, damit sie im UI angezeigt werden. Dazu legen wir auch einen neuen Abschnitt in der "UI.Facet" auf der Objektseite an.
{
id : 'idFiles',
label : 'Files',
position : 35,
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'FILE'
}
Im unteren Teil fügen wir die Felder ein. Du kannst den Mimetype und den Dateinamen ausblenden und nur noch das Feld Attachment einblenden.
@UI:{
identification: [{ position: 80, qualifier: 'FILE' }]
}
@EndUserText.label: 'Excel'
ExcelAttachement;
@UI.hidden: true
ExcelMimetype;
@UI.hidden: true
ExcelFilename;
@UI:{
identification: [{ position: 80, qualifier: 'FILE' }]
}
@EndUserText.label: 'Picture'
PictureAttachement;
@UI.hidden: true
PictureMimetype;
@UI.hidden: true
PictureFilename;
Verhalten
In der Verhaltensdefinition ergänzen wir noch das Mapping, damit beim Speichern die Daten auch auf der Datenbank landen.
mapping for zbs_drp_addcurr
{
Currency = currency;
CurrencyComment = ccomment;
Documentation = documentation;
PictureURL = picture_url;
LastEditor = last_editor;
ExcelAttachement = excel_attachment;
ExcelMimetype = excel_mimetype;
ExcelFilename = excel_filename;
PictureAttachement = picture_attachment;
PictureMimetype = picture_mimetype;
PictureFilename = picture_filename;
LocalLastChanged = local_last_changed;
LastChanged = last_changed;
}
Ergebnis
Schauen wir uns nun das aktuelle Ergebnis in der UI an, dann sind die Felder nun vorhanden, sehen aber noch sehr nach Standard Eingabe aus. Zumindest sind die Felder aber schon einmal vorhanden und unsere Erweiterung ist abgeschlossen.
Upload Dialog
In diesem Abschnitt wollen wir nun den Upload Dialog an den Feldern ergänzen, dazu müssen wir nur einige Annotationen ergänzen, um die Felder vorzubereiten.
Mimetype
Das Feld des Mimetype müssen wir zuerst mit der neuen Annotation aus dem Bereich "Semantics" setzen. Damit weiß Fiori, dass sich in dem Feld ein Mimetype befindet.
@Semantics.mimeType: true
ExcelMimetype,
Attachment
Im nächsten Schritt erweitern wir das Feld des Attachements mit den nötigen Informationen und übergeben die Felder für den Mimetype und den Filename. Die Informationen werden benötigt für die Darstellung und den Upload später.
@Semantics.largeObject: {
mimeType : 'ExcelMimetype',
fileName : 'ExcelFilename',
contentDispositionPreference: #INLINE
}
ExcelAttachement,
Ergebnis
Die fertige Annotation sieht wie folgt aus. Da es sich hier eher um eine technische Annotation handelt, haben wir diese in den Consumption View übernommen und nicht in die Metadata Extension.
@Semantics.largeObject: {
mimeType : 'ExcelMimetype',
fileName : 'ExcelFilename',
contentDispositionPreference: #INLINE
}
ExcelAttachement,
@Semantics.mimeType: true
ExcelMimetype,
ExcelFilename,
@Semantics.largeObject: {
mimeType : 'PictureMimetype',
fileName : 'PictureFilename',
contentDispositionPreference: #INLINE
}
PictureAttachement,
@Semantics.mimeType: true
PictureMimetype,
PictureFilename,
Schauen wir uns nun die UI an, dann haben sich die Eingabefelder in Upload Dialoge verändert. Über den Pfeil können wir eine Datei hochladen, über das Kreuz wieder entfernen. Der Dateiname wird nach dem Upload angezeigt und ist klickbar. Bei einem Klick auf den Namen, wird die Datei heruntergeladen.
Weitere Tipps
Was können wir noch mit den Inhalten machen? In diesem Abschnitt wollen wir auf zwei weitere Punkte eingehen und etwas genauer beschreiben.
Einschränkung
Du möchtest einschränken, welche Dateien hochgeladen werden? Dann kannst du über die Annotation "Semantics.largeObject.acceptableMimeTypes" weitere Einschränkungen am Dialog vornehmen. Wenn du wissen willst, welche Mimetypes es gibt, findest du hier eine Liste.
@Semantics.largeObject: {
acceptableMimeTypes: [ 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ]
}
ExcelAttachement,
@Semantics.largeObject: {
acceptableMimeTypes: [ 'image/*' ]
}
PictureAttachement,
Bei Excel schränken wir auf die beiden Formate xls und xlsx ein, dazu machen wir eine Aufzählung. Bei den Bildern schränken wir auf alle Formate mit "image" ein, dazu können wir einen Stern als Wildcard nutzen. Versuchen wir dann eine Datei hochzuladen, die nicht zum Filter passt, erhalten wir die folgende Fehlermeldung in Fiori.
Verwendung
Das Bild was wir zum Beispiel in unsere Anwendung laden, können wir dann auch verwenden. Zum Beispiel können wir das Feld für den Header angeben.
@UI: {
headerInfo: {
imageUrl: 'PictureAttachement'
}
}
Nachdem wir dann das Bild geladen haben, wir dieses auch im Header angezeigt. Damit funktioniert neben der URL, auch die Angabe des Bildes als Upload Stream im Feld.
Vollständiges Beispiel
Alle Änderungen, die wir durchgeführt haben, findest du im folgenden Commit unseres GitHub Repositorys rund um das Thema RAP Entwicklung.
Fazit
Der einfache Upload von Dateien in unsere Anwendung funktioniert einfach und zuverlässig. Allerdings speichern wir dann auch die Datei in unserer Anwendung, was Speicherplatz auf der Festplatte benötigt. Der integrierte Upload als Popup wird noch etwas Zeit benötigen.