Overview
This guide demonstrates how to implement Excel Template Download and Bulk Data Upload functionality in a Fiori Elements List Report application using RAP (RESTful ABAP Programming) in SAP BTP ABAP Environment.
Features covered:
- Download an Excel template with predefined column headers
- Upload Excel file with data to create multiple records
- Client-side file handling with UI5
- Server-side Excel parsing using XCO library
Prerequisites
- SAP BTP ABAP Environment or SAP S/4HANA (RAP enabled)
- SAP Business Application Studio (BAS)
- Basic knowledge of RAP, CDS, and Fiori Elements
- Existing RAP Business Object with List Report application
Step 1: Create Abstract Entity for File Parameters
Create an abstract entity to handle the file upload parameters passed from the UI to the backend.
@EndUserText.label: 'Abstract entity for Excel file parameters'
define abstract entity ZAE_EXCEL_FILE_PARAM
{
mimeType : abap.string(0);
fileName : abap.string(0);
fileContent : abap.rawstring(0);
}Note: This entity defines the structure for passing file metadata (MIME type, file name) and the actual file content (as base64 encoded raw string) from the frontend to the backend.
Step 2: Add Actions in Behavior Definition
Add static actions for download and upload functionality in your behavior definition file.
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
etag master LastChangedAt
lock master total etag LastChangedAt
authorization master ( global )
{
// ... existing configurations ...
// Static actions for Excel operations
static action downloadTemplate;
static action uploadExcel parameter ZAE_EXCEL_FILE_PARAM;
// ... other actions ...
}Add method definitions in your behavior implementation class:
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS:
downloadTemplate FOR MODIFY
IMPORTING keys FOR ACTION Travel~downloadTemplate,
uploadExcel FOR MODIFY
IMPORTING keys FOR ACTION Travel~uploadExcel.
ENDCLASS.Step 3: Configure UI Extension in Business Application Studio
3.1 Connect OData Service and Create List Report
- Open your project in SAP Business Application Studio
- Connect your OData V4 service
- Generate a List Report application using the Fiori Elements template
3.2 Add Controller Extension
Open Page Map view in BAS
Navigate to your List Report page
Find “Controller Extensions” section for your page
Click “Add Controller Extension”
Provide a controller name (e.g.,
ExcelHandler)
3.3 Add Custom Actions via Page Editor
Go to Application Info page
Click on List Report to open Page Editor
In Page Editor, navigate to: Table → Toolbar → Actions
Click “Add Custom Action” and configure:
For Download Template Button:
Property Value
Action ID downloadTemplateActionButton Text Download TemplateHandler File Select your controller extension Handler Method downloadTemplateFor Upload Excel Button:
Property Value
Action ID uploadExcelActionButton Text Upload ExcelHandler File Select your controller extension Handler Method uploadExcelDialog
Step 4: Implement Controller Extension (Frontend)
4.1 Controller Extension Code
Create/update the controller extension file:
webapp/ext/controller/ExcelHandler.controller.js
sap.ui.define([
'sap/ui/core/mvc/ControllerExtension',
'sap/ui/export/Spreadsheet',
'sap/m/MessageBox',
'sap/m/MessageToast',
'sap/ui/core/Fragment'
], function (ControllerExtension, Spreadsheet, MessageBox, MessageToast, Fragment) {
'use strict';
return ControllerExtension.extend('yournamespace.ext.controller.ExcelHandler', {
override: {
onInit: function () {
// Initialize service path - adjust according to your service
this.oServicePath = "/YourEntitySet/com.sap.gateway.srvd.your_service.v0001.";
},
editFlow: {
onAfterActionExecution: function (oEvent) {
// Handle action execution based on action name
if (oEvent.split(".")[6] === 'downloadTemplate') {
this.downloadTemplate();
}
if (oEvent.split(".")[6] === 'uploadExcel') {
this.uploadExcelDialog();
}
}
}
},
/**
* Download Excel Template
* Generates an Excel file with column headers for data entry
*/
downloadTemplate: function () {
// Define columns for the template
var aColumns = [
{
label: 'Travel ID',
property: 'TravelID',
type: 'String',
width: 15
},
{
label: 'Agency ID',
property: 'AgencyID',
type: 'String',
width: 15
},
{
label: 'Customer ID',
property: 'CustomerID',
type: 'String',
width: 15
},
{
label: 'Begin Date',
property: 'BeginDate',
type: 'Date',
width: 12
},
{
label: 'End Date',
property: 'EndDate',
type: 'Date',
width: 12
},
{
label: 'Booking Fee',
property: 'BookingFee',
type: 'Number',
scale: 2,
width: 12
},
{
label: 'Total Price',
property: 'TotalPrice',
type: 'Number',
scale: 2,
width: 12
},
{
label: 'Currency Code',
property: 'CurrencyCode',
type: 'String',
width: 12
},
{
label: 'Description',
property: 'Description',
type: 'String',
width: 40
},
{
label: 'Status',
property: 'Status',
type: 'String',
width: 12
}
];
// Configure spreadsheet settings
var oSettings = {
workbook: {
columns: aColumns
},
dataSource: [{}], // Empty data for template (headers only)
fileName: 'Travel_Upload_Template.xlsx',
showProgress: false
};
// Generate and download Excel file
var oSheet = new Spreadsheet(oSettings);
oSheet.build()
.then(function () {
MessageToast.show("Template downloaded successfully!");
})
.catch(function (oError) {
MessageBox.error("Error generating template: " + oError.message);
})
.finally(function () {
oSheet.destroy();
});
},
/**
* Open Upload Dialog
* Creates and displays a dialog for file selection
*/
uploadExcelDialog: function () {
var oView = this.getView();
var that = this;
if (!this.oDialog) {
this.oDialog = Fragment.load({
id: oView.getId(),
controller: this,
name: "yournamespace.ext.fragment.FileUploadDialog"
}).then(function (oDialog) {
oView.addDependent(oDialog);
return oDialog;
});
}
this.oDialog.then(function (oDialog) {
oDialog.open();
});
},
/**
* Handle File Selection
* Reads and stores selected file content
* @param {sap.ui.base.Event} oEvent - File change event
*/
onFileChange: function (oEvent) {
var oFile = oEvent.getParameters().files[0];
if (!oFile) {
return;
}
// Store file metadata
this.fileType = oFile.type;
this.fileName = oFile.name;
// Read file content as Base64
var oFileReader = new FileReader();
oFileReader.onload = function (oLoadEvent) {
// Extract Base64 content (remove data URL prefix)
this.fileContent = oLoadEvent.target.result.split(",")[1];
}.bind(this);
oFileReader.readAsDataURL(oFile);
},
/**
* Handle Upload Button Press
* Sends file content to backend for processing
*/
onUploadPress: function () {
var that = this;
this.oFileUploaderInput = this.getView().byId("idFileUpload");
// Validate file selection
if (!this.fileContent) {
MessageBox.error("Please select a file to upload");
return;
}
// Get OData model
var oModel = this.base.getModel();
// Create action binding context
var oContext = oModel.bindContext(this.oServicePath + "uploadExcel(...)");
// Set action parameters
oContext.setParameter("mimeType", this.fileType);
oContext.setParameter("fileName", this.fileName);
oContext.setParameter("fileContent", this.fileContent);
// Execute action
oContext.execute()
.then(function () {
MessageToast.show("Excel uploaded successfully!");
that._closeDialogAndReset();
// Refresh list to show new data
that.base.getExtensionAPI().refresh();
})
.catch(function (oError) {
MessageBox.error("Upload failed: " + oError.message);
that._closeDialogAndReset();
});
},
/**
* Handle Cancel Button Press
* Closes the upload dialog
*/
onCancelUpload: function () {
this.getView().byId("idFileUploadDialog").close();
},
/**
* Helper: Close dialog and reset file input
* @private
*/
_closeDialogAndReset: function () {
this.oDialog.then(function (oDialog) {
oDialog.close();
});
if (this.oFileUploaderInput) {
this.oFileUploaderInput.clear();
}
this.fileContent="";
}
});
});4.2 Create Upload Dialog Fragment
Create a fragment file for the upload dialog:
webapp/ext/fragment/FileUploadDialog.fragment.xml
Step 5: Implement Backend Logic (ABAP)
5.1 Define Table Type for Excel Data
Add the following type definitions in your behavior implementation class:
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
" Type definitions for Excel parsing
TYPES:
lty_c20 TYPE c LENGTH 20,
lty_c40 TYPE c LENGTH 40,
lty_c100 TYPE c LENGTH 100,
BEGIN OF ty_excel_upload,
travel_id TYPE lty_c20,
agency_id TYPE lty_c20,
customer_id TYPE lty_c20,
begin_date TYPE string, " Will be converted to date
end_date TYPE string, " Will be converted to date
booking_fee TYPE string, " Will be converted to decimal
total_price TYPE string, " Will be converted to decimal
currency_code TYPE lty_c20,
description TYPE lty_c100,
status TYPE lty_c20,
END OF ty_excel_upload,
tt_excel_upload TYPE STANDARD TABLE OF ty_excel_upload WITH EMPTY KEY.
" Constants for messaging
CONSTANTS:
c_msg_id TYPE symsgid VALUE 'ZTRAVEL_MSG',
c_msg_number TYPE symsgno VALUE '001'.
METHODS:
downloadTemplate FOR MODIFY
IMPORTING keys FOR ACTION Travel~downloadTemplate,
uploadExcel FOR MODIFY
IMPORTING keys FOR ACTION Travel~uploadExcel.
ENDCLASS.5.2 Implement Upload Method
CLASS lhc_travel IMPLEMENTATION.
METHOD downloadTemplate.
" Template download is handled on the frontend
" This method can be used for logging or additional backend processing if needed
ENDMETHOD.
METHOD uploadExcel.
DATA: lt_excel TYPE tt_excel_upload,
lt_data_create TYPE TABLE FOR CREATE zi_travel,
lv_file_content TYPE xstring,
lv_index TYPE i.
"---------------------------------------------------
" 1. Get and Validate File Content
"---------------------------------------------------
lv_file_content = keys[ 1 ]-%param-fileContent.
IF lv_file_content IS INITIAL.
APPEND VALUE #(
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text="No file content provided. Please select a file." )
) TO reported-travel.
RETURN.
ENDIF.
"---------------------------------------------------
" 2. Parse Excel File Using XCO Library
"---------------------------------------------------
TRY.
" Create document reader from file content
DATA(lo_document) = xco_cp_xlsx=>document->for_file_content( lv_file_content )->read_access( ).
" Get first worksheet
DATA(lo_worksheet) = lo_document->get_workbook( )->worksheet->at_position( 1 ).
" Define selection pattern (skip header row, start from row 2)
DATA(lo_selection_pattern) = xco_cp_xlsx_selection=>pattern_builder->simple_from_to(
)->from_row( xco_cp_xlsx=>coordinate->for_numeric_value( 2 )
)->get_pattern( ).
" Read data into internal table
lo_worksheet->select( lo_selection_pattern
)->row_stream(
)->operation->write_to( REF #( lt_excel )
)->execute( ).
CATCH cx_root INTO DATA(lx_excel_error).
APPEND VALUE #(
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Excel parsing error: { lx_excel_error->get_text( ) }| )
) TO reported-travel.
RETURN.
ENDTRY.
"---------------------------------------------------
" 3. Clean and Validate Data
"---------------------------------------------------
" Remove empty rows
DELETE lt_excel WHERE
travel_id IS INITIAL AND
agency_id IS INITIAL AND
customer_id IS INITIAL.
IF lt_excel IS INITIAL.
APPEND VALUE #(
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-warning
text="Excel file contains no valid data rows." )
) TO reported-travel.
RETURN.
ENDIF.
"---------------------------------------------------
" 4. Map Excel Data to RAP Create Structure
"---------------------------------------------------
lv_index = 0.
LOOP AT lt_excel INTO DATA(ls_excel).
lv_index += 1.
" Convert string values to appropriate types
DATA(lv_begin_date) = CONV d( ls_excel-begin_date ).
DATA(lv_end_date) = CONV d( ls_excel-end_date ).
DATA(lv_booking_fee) = CONV decfloat34( ls_excel-booking_fee ).
DATA(lv_total_price) = CONV decfloat34( ls_excel-total_price ).
APPEND VALUE #(
%cid = |CID_{ lv_index }|
%data = VALUE #(
AgencyID = ls_excel-agency_id
CustomerID = ls_excel-customer_id
BeginDate = lv_begin_date
EndDate = lv_end_date
BookingFee = lv_booking_fee
TotalPrice = lv_total_price
CurrencyCode = ls_excel-currency_code
Description = ls_excel-description
Status = ls_excel-status
)
%control = VALUE #(
AgencyID = if_abap_behv=>mk-on
CustomerID = if_abap_behv=>mk-on
BeginDate = if_abap_behv=>mk-on
EndDate = if_abap_behv=>mk-on
BookingFee = if_abap_behv=>mk-on
TotalPrice = if_abap_behv=>mk-on
CurrencyCode = if_abap_behv=>mk-on
Description = if_abap_behv=>mk-on
Status = if_abap_behv=>mk-on
)
) TO lt_data_create.
ENDLOOP.
"---------------------------------------------------
" 5. Create Records Using EML
"---------------------------------------------------
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
CREATE FIELDS (
AgencyID
CustomerID
BeginDate
EndDate
BookingFee
TotalPrice
CurrencyCode
Description
Status
)
WITH lt_data_create
MAPPED DATA(lt_mapped)
REPORTED DATA(lt_reported)
FAILED DATA(lt_failed).
"---------------------------------------------------
" 6. Handle Results and Return Messages
"---------------------------------------------------
IF lt_failed-travel IS NOT INITIAL.
" Report failures
LOOP AT lt_failed-travel INTO DATA(ls_failed).
APPEND VALUE #(
%cid = ls_failed-%cid
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Failed to create record: { ls_failed-%cid }| )
) TO reported-travel.
ENDLOOP.
ELSE.
" Success message
APPEND VALUE #(
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-success
text = |Successfully created { lines( lt_mapped-travel ) } records.| )
) TO reported-travel.
ENDIF.
ENDMETHOD.
ENDCLASS.Project Structure Summary
your-project/
├── src/
│ ├── zae_excel_file_param.ddls.asddls # Abstract entity
│ ├── zi_travel.bdef.asbdef # Behavior definition
│ ├── zbp_i_travel.clas.abap # Behavior implementation
│ └── ...
│
└── webapp/
├── manifest.json
└── ext/
├── controller/
│ └── ExcelHandler.controller.js # Controller extension
└── fragment/
└── FileUploadDialog.fragment.xml # Upload dialogAdditional Resources
Conclusion
This implementation provides a complete solution for Excel-based bulk data operations in Fiori Elements applications. The approach leverages RAP’s static actions for clean separation of concerns and uses standard SAP libraries for reliable Excel handling.


