
RAP - Nativer Datei-Upload
Du willst eine Datei in deine RAP Application hochladen und im Anschluss verarbeiten? Die offizielle Lösung für Up- und Download lässt noch warten, mit einem kleinen Umweg ist es aber bereits Heute möglich.
Inhaltsverzeichnis
In diesem Artikel schauen wir uns einen nativen Upload an, den du ohne Fiori Elements implementieren kannst und der selbst in der Preview funktioniert.
Einleitung
Bisher hatten wir unsere Sales App um verschiedene Aktionen erweitert und beim letzten Mal unser Thema Feature Controls angeschaut, um verschiedene Funktionen zu enablen oder disablen, dies abhängig von den jeweiligen Berechtigungen des aktuellen Benutzers. In einem vergangenen Artikel hatten wir uns auch angeschaut, wie wir per nativem Excel-Upload unsere Entität mit neuen Daten anreichern können, ohne eigentlich eine Implementierung im JavaScript-Framework oder ABAP vornehmen zu müssen. Ab und zu kann es allerdings vorkommen, dass wir auch einen nativen Upload benötigen, um zum Beispiel verschiedene Textformate, Raw-Dateien oder Bilder hochzuladen, die wir nicht speichern wollen, sondern vielleicht direkt weiterverarbeiten.
Die offizielle Lösung der SAP wird noch etwas Zeit benötigen. Hier ist ein Up- und Download von generischen Dateien geplant, ohne eine jeweilige Implementierung. Bei dieser Lösung handelt es sich eher um eine Art Workaround, da hier auch sehr viele Objekte angelegt werden müssen, um das Ergebnis zu erreichen.
Popup
In diesem Kapitel beschreiben wir die Implementierung, die du vornehmen musst, um ein Popup zu erhalten, in dem ein Upload einer Datei möglich ist.
Architektur
Unsere Architektur sieht deshalb vor, dass wir zwei Schichten von Objekten haben. Auf der obersten Ebene haben wir das Popup, welches dem User am Ende präsentiert wird. Dazu brauchen wir eine weitere Assoziation auf die Dateien, die für den Datei-Upload nötig ist. Für die beiden abstrakten Entitäten benötigen wir dann jeweils noch eine Behavior Definition, in der wir das Verhalten und die Beziehung der Entitäten definieren. Dies ist dann die Grundlage, um die Struktur als Parameter in einer Action innerhalb unseres RAP-Objekts zu verwenden.
Datei
Im ersten Schritt definieren wir die Entität für die eigentliche Datei. Dabei verwenden wir die drei typischen Felder, die wir auch beim klassischen Upload direkt in die Entität benötigen: das eigentliche File, den Mime-Type und den Filename. Hier solltest du darauf achten, dass die Entität als ROOT Entity definiert wird, da wir hierfür ein Verhalten definieren müssen.
@EndUserText.label: 'File Upload Entity'
define root abstract entity ZBS_S_SAFileUpload
{
@Semantics.largeObject: {
mimeType : 'MimeType',
fileName : 'Filename'
}
Attachment : abap.rawstring;
@Semantics.mimeType: true
@UI.hidden : true
MimeType : abap.char(128);
@UI.hidden : true
Filename : abap.char(128);
}
Auf dieser abstrakten Entität definieren wir uns dann ein Verhalten. Dies kannst du per Rechtsklick über das Kontextmenü auf dem Objekt machen. Im Grunde müssen wir hier nur den Zusatz WITH HIERARCHY definieren, ansonsten müssen wir keine weiteren Anpassungen in der Definition machen.
abstract;
strict ( 2 );
with hierarchy;
define behavior for ZBS_S_SAFileUpload
{
}
Dialog
Nun definieren wir uns die Entität für das eigentliche Popup, welches der User am Ende zur Eingabe erhält. Der wichtige Aspekt für den Datei-Upload ist die entsprechende Assoziation, die wir im unteren Teil anlegen. Der Name der eigentlichen Assoziation spielt dabei keine Rolle. Wir verweisen mit einer 1-zu-1-Assoziation auf den File-Upload, die Entität, die wir im ersten Schritt angelegt haben. Wir definieren uns die abstrakte Entität ebenfalls als ROOT, da wir auch auf diesem Objekt eine Verhaltensdefinition anlegen müssen. Die Felder im oberen Teil können wir frei definieren. Haben wir noch weitere Eingabeinformationen, die der User mitgeben kann, dann haben wir hier die Möglichkeit, weitere Felder zu definieren.
@EndUserText.label: 'Flat File Upload Dialog'
define root abstract entity ZBS_S_SAPopupFlatFile
{
@EndUserText.label: 'Description'
Description : abap.char(60);
@EndUserText.label: 'Test Mode'
TestMode : abap_boolean;
@EndUserText.label: 'File Name'
_Files : association [1] to ZBS_S_SAFileUpload on 1 = 1;
}
Die Verhaltensdefinition legen wir nun für das Objekt an. Hier müssen wir den Zusatz WITH HIERARCHY wieder verwenden und darauf achten, dass die Assoziation, die wir in der Entität definieren, ebenfalls den Zusatz hat. Ansonsten wird das Feld nicht in die Entität generiert und ist nicht sichtbar.
abstract;
strict ( 2 );
with hierarchy;
define behavior for ZBS_S_SAPopupFlatFile
{
association _Files with hierarchy;
}
Implementierung
Jedenfalls gibt es bei der Implementierung der Methode noch eine Besonderheit. Hier verwenden wir nicht nur den Zusatz PARAMETER, sondern auch DEEP PARAMETER, damit die tiefe Struktur unseres Popups verwendet wird.
static action UploadFlatFile deep parameter ZBS_S_SAPopupFlatFile;
Für weitere Testzwecke definieren wir uns dann in der eigentlichen Methode eine Konvertierungslogik, die über die Schlüssel geht, die wir erhalten haben, und dort das Attachment nimmt und von XSTRING auf STRING konvertiert, damit wir den Inhalt später im Test lesen können.
LOOP AT keys INTO FINAL(key).
FINAL(file_content) = xco_cp=>xstring( key-%param-_files-Attachment )->as_string(
xco_cp_character=>code_page->utf_8 ).
ENDLOOP.
Test
Bevor wir in den Test gehen, solltest du dann noch die Action in die Consumption-Schicht propagieren, sodass sie dort verfügbar ist, und über die Metadaten im UI einblenden. Diese Schritte haben wir aus dem Artikel herausgelassen, findest du aber im GitHub-Repository.
Textdatei
Für den Test bereiten wir eine normale TXT-Datei vor, die wir im Texteditor anlegen. Dabei setzen wir auch ein Trennzeichen (ENTER) zwischen die beiden Zeilen und speichern das Ganze als UTF-8 auf unserem Laufwerk ab.
Dialog
Führen wir dann die Action im UI aus, erhalten wir das von uns definierte Popup. Die beiden Zusatzfelder für die Beschreibung und den Testmodus sind im oberen Bereich, darunter befinden sich die Attachments, wo wir auch eine Wertehilfe automatisch generiert bekommen. Die Reihenfolge der Felder können wir soweit definieren, die eigentliche Assoziation wird aber immer ganz unten im Popup generiert. Du solltest dich auch nicht von der Visualisierung ablenken lassen, es kann jeweils nur eine Datei hochgeladen werden.
Debugger
Starten wir dann den Debugger, können wir uns die Inhalte der übergebenen Strukturen ansehen. Im Key finden wir unter den Parametern die jeweiligen Befüllungen aus dem Popup: die Beschreibung, den Testmodus und die Assoziation zu Files. Dies entspricht dem Namen der Assoziation, wie wir sie im abstrakten Core Data Service definiert haben. Die drei Felder für den File-Upload befinden sich ebenfalls darin und wurden mit unserer Datei und den Werten befüllt.
Achtungspunkte
Da es sich um einen Workaround handelt, gibt es natürlich auch einige Punkte, die du beachten solltest, wenn du so eine Lösung bei dir implementierst:
- Default Function - Eine Default Function kann für unsere Action nicht implementiert werden. Wir können keine Default-Werte setzen, wenn der User das Popup öffnet. Dies wird aktuell durch die DEEP PARAMETER nicht unterstützt, die wir implementiert haben, um den Datei-Upload zu realisieren.
- Anzahl - Wie wir bereits im Artikel angesprochen haben, kannst du jeweils nur eine Datei mit dieser Funktion hochladen. Es ist kein Massen-Upload von verschiedenen Dateien möglich, um zum Beispiel mehrere Anhänge hinzuzufügen.
- UI-Annotationen - Grundsätzlich kannst du die UI-Annotationen innerhalb des Popups anpassen, aber nur für alle anderen Felder. Das Feld Attachment zieht er sich anhand des Namens aus der Sub-Entität. Hier wird der Name nicht übernommen, den wir ihm über die UI-Annotation gegeben haben.
Vollständiges Beispiel
Das vollständige Beispiel findest du in GitHub im entsprechenden Paket für die Sales App. Die Änderungen aus diesem Artikel findest du in diesem Commit und kannst damit die Änderungen, plus die Zusatzinformationen, nachvollziehen.
Fazit
Grundsätzlich ist ein nativer Upload mit eingebauten ABAP-Mitteln auch bereits heute möglich. So kannst du auch Excel-Dateien direkt in ABAP laden und über die XCO-Bibliotheken zerlegen und einfügen. Grundsätzlich kannst du dafür aber auch Reuse-Komponenten direkt in Fiori verwenden, die auch heute schon verschiedene Validierungslogiken haben, ohne zusätzliche Logik in deiner Anwendung zu implementieren.



