Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
p619793
Active Participant
Recently, in one custom application I had the opportunity of creating a custom app displaying a list of SKUs (articles /materials) using Fiori Elements List report floorplan. The custom app (sample shown below) had a feature of uploading and displaying the images of the articles which was developed using annotation and a redefinition of the data provider class which I thought worth sharing in case if someone needs to implement a similar functionality.


My Preparation:


"Do in Rome SAP as Romans SAPers (SAPients or .. alright, call them however you like) do"

As it seemed to be quite a common requirement and SAP already has it in some of their standard Fiori elements apps, I explored how standard SAP has achieved this. One of the best way to explore standard apps (if one does not have a custom pre-configured SAP on-prem or cloud access) is to spin up a trial SAP solution instance from SAP Cloud Appliance Library on preferred cloud provider (AWS, Azure or GCP).
Note:ABAP examples in this blog post are based on ABAP Programming Model for SAP Fiori, i.e., CDS views with BOPF enabled and subsequent implementation of OData service with Reference data source approach (ABAP 7.51 and above). The OData service is registered on SAP Netweaver Gateway system and consumed by the Fiori app.

Implementation:


The implementation of displaying and uploading is described below in two sections:


  1. Build backend data model




  2. UI coding




1. Build backend data model


The fiori app is developed using Fiori Elements List report template. Since SAP Netweaver Gateway supports media type entity, we need the image data to be provided by the backend as an entity type with ‘Media’ type annotation (m:HasStream="true").

Below is an illustration of the entity data model:



My implementation was based on CDS views, but a code-based implementation of data model in SEGW OData service builder will also do.

The primary entity is bound to the smart table of the list report which allows us to display the fields like article number(matnr), article description [among others] in the fiori list report app. The primary entity Z_C_SKUIMAGEType is associated to the image source entity (Z_I_IMAGEType) which has the ‘mime_type’ property to enable this entity to be represented as stream data over gateway.

 

Alright! Enough of the explanation, let’s get right to the implementation steps.

a. CDS views: Create the CDS views as shown below.


Note: the code snippets are sample only, adapt appropriately to suit your own requirements [e.g., replace/remove <namespace> with your own namespace.]

We are using two CDS views and accordingly two entity types will be generated as illustrated above.

CDS 1 : ZCDS_C_SKUIMAGE

.....

@ObjectModel:
{
updateEnabled: true
}

define view ZCDS_C_SKUIMAGE
as select from z<namespace>_cat_sku as CatalogSku
inner join makt as SKUDesc
on ( CatalogSku.matnr = SKUDesc.matnr )

association [1..*] to ZCDS_I_IMAGE as _Image
on ( CatalogSku.matnr = _Image.CatalogSKU )
{

key CatalogSku.matnr as CatalogSKU,
CatalogSku.ctlg_itm_key as CatalogItmKey,
SKUDesc.maktx as CatalogSKUDesc,
_Image,
//creating URL
concat(replace('/sap/opu/odata/sap/Z<namespace>_IMAGES_SRV/ZCDS_I_IMAGE(CatalogSKU=''matnr'',', 'matnr', CatalogSku.matnr),
replace('image_key=imageKey)/$value', 'imageKey',
cast (_Image.image_key as abap.char( 20 )))) as GetUrl
}
where SKUDesc.spras = $session.system_language
and CatalogSku.inactive = ''

CDS 2: ZCDS_I_IMAGE
....

@ObjectModel:{
createEnabled: true,
updateEnabled: true,
deleteEnabled: true

}

define view ZCDS_I_IMAGE
as select from z<namespace>_cat_sku as Image
{
key Image.matnr as CatalogSKU,
key Image.image_key as image_key,
Image.ctlg_itm_key as CatalogItmKey,
Image.image_name,
Image.mime_type,
@Semantics.imageUrl: true
Image.image_url as ImageUrl,
} where Image.inactive = ''

As can be seen, the second CDS view is based on a transparent table Z<namespace>_cat_sku which stores the information of article image like image_key, mime_type, image_url for materials.



An image key is unique for each image uploaded for an article. One can choose to use GUID or similar approach to make it unique, however to make the subject matter simple, the example just uses a number generated from a number range object.

Also in the first CDS view, we have a logic to populate the property ‘GetUrl’. Do not stress on the exact logic as shown above, the idea is that the property will be bound to the Image column in fiori list report app. Since the image data is served over gateway, we need to have a URL that points to the image media entity with $value OData query option. A sample URL is as below:
"/sap/opu/odata/sap/ZFIAP_SOS_IMAGES_SRV/ZCDS_I_SOS_IMAGE(CatalogSKU='000000000600000106',image_key=0001)/$value".

 

Later, we shall see that the URL above will fetch the actual image content as a stream data as we shall implement some logic in /iwbep/if_mgw_appl_srv_runtime~get_stream method of DPC_EXT class.

b. OData service : Now in SEGW transaction code, import the above CDS entity with association as reference data source to create the OData service. Below is what resulted after generating the objects in SEGW:




c. Redefine MPC_EXT class: Once the runtime artefacts are generated from SEGW tcode, redefine method DEFINE of MPC_EXT class.
METHOD define.

super->define( ).

DATA:
lr_entity TYPE REF TO /iwbep/if_mgw_odata_entity_typ,
lr_property TYPE REF TO /iwbep/if_mgw_odata_property.

lr_entity = model->get_entity_type( iv_entity_name = 'ZCDS_I_IMAGEType' ).

* specifying mimetype property of media set
IF lr_entity IS BOUND.
* setting a data object as media type means that it gets a special semantic by having a url * and allows streaming etc.
lr_entity->set_is_media( ).
lr_property = lr_entity->get_property( iv_property_name = 'mime_type' ).
lr_property->set_as_content_type( ).


ENDIF.

ENDMETHOD.

d. Redefine DPC_EXT class GET_STREAM method: Redefine method /iwbep/if_mgw_appl_srv_runtime~get_stream of DPC_EXT class and add some logic to get the image file content.


METHOD /iwbep/if_mgw_appl_srv_runtime~get_stream.

DATA: ls_key TYPE /iwbep/s_mgw_name_value_pair,
...
lv_matnr TYPE matnr,
ls_image TYPE z<namespace>_cat_sku,
ls_lheader TYPE ihttpnvp,
ls_stream TYPE ty_s_media_resource,
lv_filename TYPE string,
lt_tab TYPE solix_tab,
ls_tab TYPE solix,
lv_leng TYPE i,
lv_buffer TYPE xstring,
lv_imageurl TYPE zzimage_url.

CASE iv_entity_name.
WHEN 'ZCDS_I_IMAGEType'.

*----------IMPORTANT READING -------------------------------------------*
*Get the key field values of the entity and retrive the image file path
*For simplification, we are showing the image storage is in
*application server directory, but adapt to your own chosen storage type
*(content repository etc.)
*-----------------------------------------------------------------------*
...

CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT'
EXPORTING
input = ls_key-value
IMPORTING
output = lv_matnr
EXCEPTIONS
length_error = 1
OTHERS = 2.
IF sy-subrc <> 0.
CLEAR lv_matnr.
ENDIF.
* Get the image details from catalog AKu table
SELECT SINGLE * FROM z<namespace>_cat_sku
INTO ls_image
WHERE matnr = lv_matnr.
IF sy-subrc = 0.
* Open the application server file and read the file contents
OPEN DATASET ls_image-image_url FOR INPUT IN BINARY MODE.
IF sy-subrc = 0.
DO.
READ DATASET ls_image-image_url INTO ls_tab.
IF sy-subrc = 0.
APPEND ls_tab TO lt_tab.
CLEAR ls_tab.
ELSE.
EXIT.
ENDIF.
ENDDO.
CLOSE DATASET ls_image-image_url.
ENDIF.
ENDIF.

* Convert the binary file content to rawstring
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
EXPORTING
input_length = ls_image-file_size
IMPORTING
buffer = lv_buffer
TABLES
binary_tab = lt_tab
EXCEPTIONS
failed = 1
OTHERS = 2.
IF sy-subrc = 0.
* Pass the rawstring data to image stream
ls_stream-value = lv_buffer.
ls_stream-mime_type = ls_image-mime_type.

lv_filename = ls_image-image_name.
lv_filename = escape( val = lv_filename
format = cl_abap_format=>e_url ).
ls_lheader-name = 'Content-Disposition'.
ls_lheader-value = |inline; filename="{ lv_filename }"|.
set_header( is_header = ls_lheader ).

copy_data_to_ref( EXPORTING is_data = ls_stream
CHANGING cr_data = er_stream ).

ENDIF.
ENDIF.

WHEN OTHERS.
ENDCASE.

e. Test OData service in GW client:


Once registered in gateway system, test your OData service, gateway client (/IWFND/GW_CLIENT tcode)

 

2. UI coding:


Create the list report app using template in SAP Web IDE and apply appropriate annotations to include the columns as per requirement.

For image column, add annotation "UI.IsImageUrl" to property 'GetUrl' which is bound to the Image column. Example annotations shown below:
<Annotations Target="Z<namespace>_IMAGES_SRV.ZCDS_C_SKUIMAGEType">
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="GetUrl"/>
<Annotation Term="UI.Importance" EnumMember="UI.ImportanceType/High"/>
<PropertyValue Property="Label" String="{@i18n&gt;IMAGE}"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="CatalogSKU"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="CatalogSKUDesc"/>
</Record>
</Collection>
</Annotation>
<Annotations Target="Z<namespace>_IMAGES_SRV.ZCDS_C_SKUIMAGEType/GetUrl">
<Annotation Term="UI.IsImageUrl"/>
</Annotations>

Run the app, the image will be rendered nicely!

Following are a few snaps of the backend service GET requests from 'Network' tab of developer's tool of chrome browser.






Conclusion:


In this blog post, we saw how to display image in a column of a fiori list report using media type entity and UI annotation. In the next part, we shall discuss how to upload image for each row in the list report on click of the button in another column.
5 Comments
Labels in this area