This is a test message to test the length of the message box.
Login
ABAP RAP Upload of Files
Created by Software-Heroes

RAP - File Upload (Stream)

998

How can you easily load files into your RAP object and make them available in ABAP? Let's take a look at the details.



In this article we will look at one way of uploading files, and we will discuss the different ways of using it.

 

Introduction

Uploading and downloading files is now standard in applications. Therefore, in the ABAP RESTful Programming Model we also need a simple solution to do this. Today we will look at uploading, i.e. storing a file in our application. To do this, we will extend the Report Pattern application with the additional function.

 

Extension

In this section, we will extend the application with two uploads to load an Excel file and an image into the application.

 

Table

In the first step, we need to extend the table. To upload files, we need three fields with a certain length.

attachment    : abap.rawstring(0);
mimetype      : abap.char(128);
filename      : abap.char(128);

 

The attachment is the file in binary form, the mimetype describes the type of the file and the filename is the name of the file after uploading. The length of the individual fields is fixed. In the first step we extend the table ZBS_DRP_ADDCURR by the 6 fields.

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;
}

 

In the second step, we extend our draft table ZBS_DRP_CURRD so that our application continues to work. We remove the underscores because we are still normalizing the fields in the Core Data Service.

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

Since we use a basic view "ZBS_B_DRPAdditionalCurrency" to normalize the fields in the data model, we also add the fields here and rename them. This means that they also match the field names in the draft table.

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

In the root view of the object, we also add the fields accordingly so that they are then available in the RAP object.

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

To complete the extension of the data model, we add the fields in the 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 the Metadata Extension we also adopt the fields so that they are displayed in the UI. To do this we also create a new section in the "UI.Facet" on the object page.

{
  id         : 'idFiles',
  label      : 'Files',
  position   : 35,
  type       : #IDENTIFICATION_REFERENCE,
  targetQualifier: 'FILE'
}

 

In the lower part we add the fields. You can hide the Mimetype and the file name and only show the Attachment field.

@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;

 

Behavior

In the behavior definition we add the mapping so that the data ends up in the database when it is saved.

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;
  }

 

Result

If we now look at the current result in the UI, the fields are now there, but still look very much like standard input. At least the fields are already there and our extension is complete.

 

Upload Dialog

In this section we now want to add the upload dialog to the fields. To do this we only need to add a few annotations to prepare the fields.

 

Mimetype

We first need to set the Mimetype field with the new annotation from the "Semantics" area. This tells Fiori that there is a Mimetype in the field.

@Semantics.mimeType: true
ExcelMimetype,

 

Attachment

In the next step, we expand the attachment field with the necessary information and pass the fields for the mimetype and the filename. The information is needed for display and upload later.

@Semantics.largeObject: {
  mimeType : 'ExcelMimetype',
  fileName : 'ExcelFilename',
  contentDispositionPreference: #INLINE
}
ExcelAttachement,

 

Result

The finished annotation looks like this. Since this is more of a technical annotation, we have transferred it to the Consumption View and not to the 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,

 

If we now look at the UI, the input fields in upload dialogs have changed. We can upload a file using the arrow and remove it again using the cross. The file name is displayed after the upload and is clickable. If you click on the name, the file is downloaded.

 

More tips

What else can we do with the content? In this section we want to go into two further points and describe them in more detail.

 

Restrictions

Would you like to restrict which files are uploaded? Then you can make further restrictions to the dialog using the annotation "Semantics.largeObject.acceptableMimeTypes". If you want to know which Mimetypes there are, you can find a list here.

@Semantics.largeObject: {
  acceptableMimeTypes: [ 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ]
}
ExcelAttachement,

@Semantics.largeObject: {
  acceptableMimeTypes: [ 'image/*' ]
}
PictureAttachement,

 

For Excel, we restrict to the two formats xls and xlsx, for this we make a list. For images, we restrict to all formats with "image", for this we can use an asterisk as a wildcard. If we then try to upload a file that does not match the filter, we receive the following error message in Fiori.

 

Usage

We can then also use the image that we load into our application, for example. For example, we can specify the field for the header.

@UI: {
  headerInfo: {
    imageUrl: 'PictureAttachement'
  }
}

 

After we have loaded the image, it will also be displayed in the header. This means that in addition to the URL, the image can also be specified as an upload stream in the field.

 

Complete example

You can find all the changes we have made in the following commit of our GitHub repository on the topic of RAP development.

 

Conclusion

The simple upload of files into our application works easily and reliably. However, we then also save the file in our application, which requires storage space on the hard drive. The integrated upload as a popup will still take some time.


Included topics:
RAPBTPUploadFilesStream
Comments (0)



And further ...

Are you satisfied with the content of the article? We post new content in the ABAP area every Friday and irregularly in all other areas. Take a look at our tools and apps, we provide them free of charge.


RAP - Semantic Key

Category - ABAP

What do you need the semantic key for and how is it represented in the ABAP RESTful Programming Model? You can find out more here.

12/13/2024

RAP - Report Pattern

Category - ABAP

How is the Report Pattern structured in RAP and what can you do with it? Read more in this ABAP article.

12/06/2024

RAP - Translation app (example)

Category - ABAP

Let's take a look at a practical example of developing a RAP application in the ABAP environment and how you can create an app with little effort.

08/02/2024

RAP - Custom Entity Value Help (Deep Dive)

Category - ABAP

With the Custom Entity you have the most freedom in RAP when developing ABAP Cloud applications, but what about potential errors?

07/12/2024

RAP - Deep Action in OData v4

Category - ABAP

In this article we will look at actions with deep structures, how we can create them and pass data to an API endpoint.

05/24/2024