Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Thajunniza
Advisor
Advisor
In this post, I’m going to show how to store media data in SAP HANA DB using SAP Cloud Application Programming Model(CAP) and UI5.

The code is available at GitHub.

Prerequisites:

Need to know how to create a basic CAP project and adding a UI to it using SAP Business Application Studio.

  • Create a CAP project-Media





  • Create an entity for media named 'MediaFile' in data/data-model.cds. Here two annotations are important.

    • @Core.MediaType – It denotes the data element contains media data.

    • @Core.IsMediaType – It denotes the data element contains a MIME type.


    • namespace Media.db;

      entity MediaFile {
      key id : Integer;
      @Core.MediaType : mediaType
      content : LargeBinary;
      @Core.IsMediaType : true
      mediaType : String;
      fileName : String;
      url : String;
      };




  • Create a service in srv->media-service.cds to expose the MediaFile Entity.


using {Media.db as db} from '../db/data-model';


service MediaService @(path : '/media') {
entity MediaFile as projection on db.MediaFile;
};


  • In srv->media-service.js add below logic on the hook handlers

    • On before create handler we will generating the url for the uploaded content which is used to view the content in browser.

    • And we also need to add custom logic in read handler to view the uploaded content in the browser.

    • I have used sequence to generate the ID.




const SequenceHelper = require("./library/SequenceHelper");
const { Readable, PassThrough } = require("stream");
const cds = require('@sap/cds');
cds.env.features.fetch_csrf = true

module.exports = cds.service.impl(async function () {

const {
MediaFile
} = this.entities;


/**
* Handler method called before creating data entry
* for entity Mediafile.
*/
this.before('CREATE', MediaFile, async (req) => {
const db = await cds.connect.to("db");
// Create Constructor for SequenceHelper
// Pass the sequence name and db
const SeqReq = new SequenceHelper({
sequence: "MEDIA_ID",
db: db,
});
//Call method getNextNumber() to fetch the next sequence number
let seq_no = await SeqReq.getNextNumber();
// Assign the sequence number to id element
req.data.id = seq_no;
//Assign the url by appending the id
req.data.url = `/media/MediaFile(${req.data.id})/content`;
});

/**
* Handler method called on reading data entry
* for entity Mediafile.
**/
this.on("READ", MediaFile, async (req, next) => {
if (!req.data.id) {
return next();
}
//Fetch the url from where the req is triggered
const url = req._.req.path;
//If the request url contains keyword "content"
// then read the media content
if (url.includes("content")) {
const id = req.data.id;
var tx = cds.transaction(req);
// Fetch the media obj from database
var mediaObj = await tx.run(
SELECT.one.from("Media.db.MediaFile", ["content", "mediaType"]).where(
"id =",
id
)
);
if (mediaObj.length <= 0) {
req.reject(404, "Media not found for the ID");
return;
}
var decodedMedia = "";
decodedMedia = new Buffer.from(
mediaObj.content.toString().split(";base64,").pop(),
"base64"
);
return _formatResult(decodedMedia, mediaObj.mediaType);
} else return next();
});

function _formatResult(decodedMedia, mediaType) {
const readable = new Readable();
const result = new Array();
readable.push(decodedMedia);
readable.push(null);
return {
value: readable,
'*@odata.mediaContentType': mediaType
}
}

 

UI to upload the file



  • Add a UI application in your CAP project and create OData model for the above cap service.

  • In the View code to add a File uploader ui and a button to trigger file upload action.


 
<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:u="sap.ui.unified" controllerName="com.ta.mediaui.controller.mediaUpload" displayBlock="true">
<Shell id="shell">
<App id="app">
<pages>
<Page id="page" title="{i18n>title}">
<content>
<FlexBox direction="Column" class="sapUiLargeMargin">
<Label text="Attach File" labelFor="fileUploader" required="true"/>
<u:FileUploader id="__fileUploader" tooltip="Upload your file to DB" change="onFileChange"/>
<Button text="Upload" press="onUploadFile" type="Emphasized"/>
<Image ariaDetails="detailsActiveImage" src="media_srv/v2/media/MediaFile(1)/content"
decorative="false"/>
</FlexBox>
</content>
</Page>
</pages>
</App>
</Shell>
</mvc:View>

 

  • In Button Action add the below logic to upload the file in the SAP HANA DB through CAP.

  • As a first step, create an entity without media data using a CREATE request. After creating the entity, you can insert a media property using the UPDATE method.


 
// @ts-nocheck
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageBox"
],
/**
* @param {typeof sap.ui.core.mvc.Controller} Controller
*/
function (Controller, MessageBox) {
"use strict";

return Controller.extend("com.ta.mediaui.controller.mediaUpload", {
onInit: function () {
},

_getBaseURL: function () {
var oBaseUrl = this.getOwnerComponent().getManifestEntry("/sap.app/id").replaceAll(".", "/");
return jQuery.sap.getModulePath(oBaseUrl)
},

/**
* on File Change
*/
onFileChange: function (oEvent) {
var file = oEvent.getParameters("files").files[0];
this.file = file;
},

/**
* On File Upload
*/
onUploadFile: function () {
var oUploadSet = this.byId("__fileUploader");
//Upload image
var reader = new FileReader();
reader.onload = function (oEvent) {
// get an access to the content of the file
this.content = oEvent.currentTarget.result;
this.createfile();
}.bind(this);
reader.readAsDataURL(this.file);

},

/**
* Create Operation to create an entry in CAP
*/
createfile: function () {
var that = this;
// Data for CAP to create entry
var oImageData = {
"content": this.content,
"mediaType": this.file.type,
"fileName": this.file.name
};
var oCAPModel = this.getOwnerComponent().getModel("oCAPModel");
var sURL = "/MediaFile";
//Create call for CAP OData Service
oCAPModel.create(sURL, oImageData, {
success: function (oData, oResponse) {
var id = oData.id;
var sMsg = "File Uploaded Successfully for ID: " + id;
MessageBox.success(sMsg);
},
error: function (jqXHR, textStatus) {

},
});
},


});
});

 

Results:



  • UI Screen to upload the document.I have uploaded a pdf called dummy.pdf




 




  • The data stored in CAP





  • Media file in browser



 

 Conclusion:


From this blog we are able to understand how SAP Cloud Application Programming Model(CAP) provides out-of-the-box support for serving media and other binary data.

However, you can use it to make much more elaborate changes to your applications.

I would love to hear from you! Please leave your feedback below.
18 Comments
vishalkumar1305
Explorer
0 Kudos
Hello Thajunniza,

Will this also work incase of jpg/photo media file ?

Regards,

Vishal Kumar
Thajunniza
Advisor
Advisor
Hi Vishal,

Yes its works for image as well.

 

Regards,

Thaj
0 Kudos
Hello Thajunniza,

For me its oCapmodel.create or update is not a function.

Regards,

Siddhant Kumar
Thajunniza
Advisor
Advisor
0 Kudos
Have you defined the oCapmodel in manifest.json
0 Kudos
Hi thajunniza14,

 

yes i have defined in oCapmodel in manifest json thank you.

 

But PUT request is giving error while updating file.

The error is Method PATCH not allowed for PRIMITIVE.PROPERTY.

 

 
Ajit_K_Panda
Product and Topic Expert
Product and Topic Expert
0 Kudos
Hi Thajunniza,

Thanks for writing the blog. it is helpful. Small Request, It would be best if you can provide a git hub  repo for this. or can you provide the sample code for sequence helper.

Best Regards, Ajit

Hi Thajunniza,

Is there any tuitorial for working with action method accepting a LargeBinary data?

@path:'test'

service TestService{

entity Books as projection on db.Books;
action uploadPdf(file:LargeBinary) returns String;
}
divyeaggarwal
Explorer
Hi @thajunniza14

I have tried this code but the issue is, when i am reading the pdf again, its returning me blank pdf.

can you help me on that?

regards

divye
iperez-sofos
Participant
0 Kudos

Excellent post, Thajunniza. It has given me many ideas and references.

Personally, I am writing my first SAP Fiori Element app that works/interacts with files. I need the app to download a PDF report that I generate on the backend side (SAP CAP), and save it in a location selected by the user. Any suggestions (I don't know, for example, which SAPUI5 control to use to allow the user to select the save location).

Thajunniza
Advisor
Advisor
0 Kudos

Thank Issac for your valuable comments.

Since JavaScript doesn't have access to the filesystem and is dependent on browser settings, I don't believe it is conceivable.

The browser setting "Ask where to save before download" is therefore available. Every browser, including Chrome and Firefox, has this setting. The user can select where the file should be saved if that option is enabled. Additionally, the user is able to save the file on the remote file server path if he has mounted it as requested and has the necessary access rights.

AakashN24
Participant
0 Kudos
What is the maximum file size we can upload in cap ?
0 Kudos
Hi,

 

Nice blog.

Thanks,

Harish
harshal1998
Discoverer
0 Kudos
Hi Thajunniza,

Thanks for writing the blog. it is helpful. Small Request,can you provide the sample code for sequence helper.
Thajunniza
Advisor
Advisor
0 Kudos

Hi Jogdand,

I have updated the blog with git url.Please refer.

GitHub

Regards,

Thaj

Thajunniza
Advisor
Advisor
0 Kudos
Hi Ajit,

I have updated the blog with git url.Please refer.

GitHub

Regards,

Thaj
Hi Thajunniza,

Git hub link says "Page not found" could you please help.

Regards,

Rashmi
0 Kudos
What parameters need to be changed in case of Excel upload?
yadavsi
Member
0 Kudos
Hi Thajunniza,

While I was following this blog, I am facing 406 Not Reachable (Missing format for representation kind 'ENTITY') issue. Any Solution for this ?