Kategorien
-
Neueste Beiträge
- [ABAP] Prüfen, ob ein bestimmer Festwert in einer Domäne vorhanden ist
- [SAP] Drucker für Benutzer festlegen
- [SAP Fiori] Fiori Launchpad erweitern, Systeminformationen im Launchpad anzeigen
- [SAP Gateway] ODATA V4 Service für anonymen Zugriff einrichten
- [ABAP] Varianten eines Reports lesen
- Warum Krebspatienten so viel Gewicht verlieren
- [SAP Fiori] ABAP RESTful Application Programming Model (RAP)
- [SAP] Events und Typkoppelungen
- [SAP Gateway] Daten versenden über einen eventbasierten Aufruf einer OData-Funktion
- [ABAP] SE80: Tricks für den ABAP-Editor
[ABAP] Application Telemetry with Prometheus / Prometheus client for ABAP
[ABAP] Logon Charset ermitteln
TRY. DATA(lv_logon_charset) = ||. cl_http_utility=>get_logon_charset( IMPORTING id = lv_logon_charset ). WRITE: / lv_logon_charset. CATCH cx_root INTO DATA(e_txt). WRITE: / e_txt->get_text( ). ENDTRY.
[ABAP] JSON parsen und in Node-Table wandeln
* Quelle: https://github.com/i042416/KnowlegeRepository/blob/master/ABAP/SmallApp/011_ZCL_JERRY_TOOL.abap CLASS lcl_json_parser DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ty_node, type TYPE string, prefix TYPE string, name TYPE string, nsuri TYPE string, value TYPE string, value_raw TYPE xstring, END OF ty_node. TYPES: ty_it_node TYPE STANDARD TABLE OF ty_node WITH DEFAULT KEY. CONSTANTS: co_open_element TYPE string VALUE 'OPEN'. CONSTANTS: co_close_element TYPE string VALUE 'CLOSE'. CONSTANTS: co_attribute TYPE string VALUE 'ATTRIBUTE'. CONSTANTS: co_value TYPE string VALUE 'VALUE'. CLASS-METHODS: convert_json_to_node_table IMPORTING iv_json TYPE string RETURNING VALUE(rv_it_nodes) TYPE ty_it_node RAISING cx_sxml_parse_error. ENDCLASS. CLASS lcl_json_parser IMPLEMENTATION. METHOD convert_json_to_node_table. * JSON nach XSTRING (UTF-8) konvertieren DATA(o_json) = cl_abap_codepage=>convert_to( iv_json ). * XSTRING einlesen und nach XML parsen DATA(o_reader) = cl_sxml_string_reader=>create( o_json ). TRY. * erste Node holen DATA(o_node) = o_reader->read_next_node( ). * solange es Nodes gibt WHILE o_node IS BOUND. * Node-Typen prüfen CASE o_node->type. * Öffnen-Node WHEN if_sxml_node=>co_nt_element_open. DATA(op) = CAST if_sxml_open_element( o_node ). APPEND VALUE #( type = co_open_element prefix = op->prefix name = op->qname-name nsuri = op->qname-namespace ) TO rv_it_nodes. * Attribute LOOP AT op->get_attributes( ) ASSIGNING FIELD-SYMBOL(<a>). APPEND VALUE #( type = co_attribute prefix = <a>->prefix name = <a>->qname-name nsuri = <a>->qname-namespace value = COND #( WHEN <a>->value_type = if_sxml_value=>co_vt_text THEN <a>->get_value( ) ) value_raw = COND #( WHEN <a>->value_type = if_sxml_value=>co_vt_raw THEN <a>->get_value_raw( ) ) ) TO rv_it_nodes. ENDLOOP. * Schließen-Node WHEN if_sxml_node=>co_nt_element_close. DATA(cl) = CAST if_sxml_close_element( o_node ). APPEND VALUE #( type = co_close_element prefix = cl->prefix name = cl->qname-name nsuri = cl->qname-namespace ) TO rv_it_nodes. * Wert-Node WHEN if_sxml_node=>co_nt_value. DATA(val) = CAST if_sxml_value_node( o_node ). APPEND VALUE #( type = co_value value = COND #( WHEN val->value_type = if_sxml_value=>co_vt_text THEN val->get_value( ) ) value_raw = COND #( WHEN val->value_type = if_sxml_value=>co_vt_raw THEN val->get_value_raw( ) ) ) TO rv_it_nodes. * Andere Nodetypen WHEN OTHERS. ENDCASE. * nächste Node o_node = o_reader->read_next_node( ). ENDWHILE. CATCH cx_root INTO DATA(e_txt). RAISE EXCEPTION TYPE cx_sxml_parse_error EXPORTING error_text = e_txt->get_text( ). ENDTRY. ENDMETHOD. ENDCLASS. START-OF-SELECTION. TRY. * JSON-Beispiele * DATA(lv_json) = CONV string( '{"success":"true","msg":"Ok.","matnr":"0000001234"}' ). DATA(lv_json) = CONV string( '{"VALUES":[{"NAME":"Horst","TITLE":"Herr","AGE":30},{"NAME":"Jutta","TITLE":"Frau","AGE":35},{"NAME":"Ingo","TITLE":"Herr","AGE":31}]}' ). * JSON -> Nodetable DATA(it_node_values) = lcl_json_parser=>convert_json_to_node_table( lv_json ). * Datenausgabe cl_demo_output=>write_data( lv_json ). cl_demo_output=>write_data( it_node_values ). cl_demo_output=>display( ). CATCH cx_root INTO DATA(e_txt). WRITE: / e_txt->get_text( ). ENDTRY.
[ABAP] Eventhandling für die Klasse cl_gui_picture
* Demoprogramm: SAP_PICTURE_DEMO * Eventhandlerklasse CLASS lcl_events DEFINITION. PUBLIC SECTION. CLASS-METHODS: on_picture_dblclick FOR EVENT picture_dblclick OF cl_gui_picture IMPORTING mouse_pos_x mouse_pos_y sender. CLASS-METHODS: on_create_context_menu FOR EVENT context_menu OF cl_gui_picture IMPORTING sender. CLASS-METHODS: on_context_menu_selection FOR EVENT context_menu_selected OF cl_gui_picture IMPORTING fcode sender. ENDCLASS. CLASS lcl_events IMPLEMENTATION. METHOD on_picture_dblclick. MESSAGE |{ mouse_pos_x }{ mouse_pos_y }| TYPE 'I'. ENDMETHOD. METHOD on_create_context_menu. DATA(o_menu) = NEW cl_ctmenu( ). o_menu->add_function( fcode = 'FUNC1' text = 'Normal' ). o_menu->add_function( fcode = 'FUNC2' text = 'Center' ). sender->display_context_menu( context_menu = o_menu ). ENDMETHOD. METHOD on_context_menu_selection. CASE fcode. WHEN 'FUNC1'. sender->set_display_mode( display_mode = cl_gui_picture=>display_mode_normal ). WHEN 'FUNC2'. sender->set_display_mode( display_mode = cl_gui_picture=>display_mode_fit_center ). ENDCASE. ENDMETHOD. ENDCLASS. * Docking-Container für Bilddarstellung DATA: o_dock TYPE REF TO cl_gui_docking_container. * URL zur Google-API für die Erstellung des QR-Codes PARAMETERS: p_url TYPE swk_url DEFAULT 'http://chart.apis.google.com/chart?chs=200x200&cht=qr&chld=|1&chl=viele%20lustige%20Zeichen/chart.png' LOWER CASE. AT SELECTION-SCREEN OUTPUT. IF NOT o_dock IS BOUND. * Dockingcontainer erzeugen o_dock = NEW #( repid = sy-repid dynnr = sy-dynnr side = cl_gui_docking_container=>dock_at_bottom ratio = 30 ). * Bild über die URL laden und anzeigen DATA(o_pic) = NEW cl_gui_picture( parent = o_dock ). o_pic->set_display_mode( display_mode = cl_gui_picture=>display_mode_fit_center ). TRY. * Eventhandler registrieren DATA: it_events TYPE cntl_simple_events. it_events = VALUE #( ( eventid = cl_gui_picture=>eventid_picture_dblclick appl_event = abap_true ) ( eventid = cl_gui_picture=>eventid_context_menu appl_event = abap_true ) ( eventid = cl_gui_picture=>eventid_context_menu_selected appl_event = abap_true ) ). o_pic->set_registered_events( events = it_events ). SET HANDLER lcl_events=>on_picture_dblclick FOR o_pic. SET HANDLER lcl_events=>on_create_context_menu FOR o_pic. SET HANDLER lcl_events=>on_context_menu_selection FOR o_pic. * Bild laden o_pic->load_picture_from_url_async( p_url ). CATCH cx_root INTO DATA(e). MESSAGE e->get_text( ) TYPE 'S' DISPLAY LIKE 'E'. ENDTRY. ENDIF.
[ABAP] Google-API: QR-Code generieren und Bild herunterladen/speichern
* Dateiname der Bilddatei zum hochladen PARAMETERS: p_fname TYPE file_table-filename OBLIGATORY. START-OF-SELECTION. * URL zur Google-API für die Erstellung des QR-Codes DATA(lv_url) = |http://chart.apis.google.com/chart?chs=200x200&cht=qr&chld=\|1&chl=viele%20lustige%20Zeichen/chart.png|. TRY. DATA: o_client TYPE REF TO if_http_client. * Client-Objekt erzeugen cl_http_client=>create_by_url( EXPORTING url = lv_url IMPORTING client = o_client ). IF sy-subrc = 0. * HTTP GET senden o_client->send( ). * Response lesen o_client->receive( ). DATA: lv_http_status TYPE i. DATA: lv_status_text TYPE string. * HTTP Return Code holen o_client->response->get_status( IMPORTING code = lv_http_status reason = lv_status_text ). * Wenn Status 200 (Ok) IF lv_http_status = 200. * Binärdaten (QR-Code) auslesen DATA(lv_xdata) = o_client->response->get_data( ). o_client->close( ). * xstring -> solix DATA(it_img_conv_data) = cl_bcs_convert=>xstring_to_solix( iv_xstring = lv_xdata ). WRITE: / |{ p_fname }.png|. * Image lokal speichern cl_gui_frontend_services=>gui_download( EXPORTING filename = |{ p_fname }.png| filetype = 'BIN' bin_filesize = xstrlen( lv_xdata ) CHANGING data_tab = it_img_conv_data ). ENDIF. ENDIF. CATCH cx_root INTO DATA(e_txt). WRITE: / e_txt->get_text( ). ENDTRY.
[SAP] Endlosschleife in einem laufenden ABAP-Programm debuggen
SM50
- Eintrag mit dem betreffenden Programm in der Tabelle markieren
- Menü -> Administration -> Programm -> Debugging
[ABAP] JSON -> Struktur
Variante 1 (/ui2/cl_json)
* ABAP Zieldatentyp TYPES: BEGIN OF ty_abap, param1 TYPE char64, param2 TYPE char64, END OF ty_abap. * JSON-Quelldaten DATA: lv_json_response TYPE string VALUE '{"param1":123,"param2":321}'. DATA: ls_abap TYPE ty_abap. TRY. * JSON->ABAP /ui2/cl_json=>deserialize( EXPORTING json = lv_json_response pretty_name = /ui2/cl_json=>pretty_mode-camel_case CHANGING data = ls_abap ). cl_demo_output=>write_data( lv_json_response ). cl_demo_output=>write_data( ls_abap ). cl_demo_output=>display( ). CATCH cx_root INTO DATA(e_txt). MESSAGE e_txt->get_text( ) TYPE 'S' DISPLAY LIKE 'E'. ENDTRY.
Variante 2 (cl_fdt_json)
* ABAP Zieldatentyp TYPES: BEGIN OF ty_abap, success TYPE string, msg TYPE string, matnr TYPE matnr, END OF ty_abap. * JSON-Quelldaten DATA: lv_json_response TYPE string VALUE '{"success":true,"msg":"Ok.","matnr":0000001234}'. DATA: ls_abap TYPE ty_abap. cl_fdt_json=>json_to_data( EXPORTING iv_json = lv_json_response CHANGING ca_data = ls_abap ). cl_demo_output=>write_data( lv_json_response ). cl_demo_output=>write_data( ls_abap ). cl_demo_output=>display( ).
VAriante 3 (cl_clb_parse_json)
* ABAP Zieldatentyp TYPES: BEGIN OF ty_abap, success TYPE string, msg TYPE string, matnr TYPE matnr, END OF ty_abap. TRY. * JSON-Quelldaten DATA(lv_json_response) = CONV string( '{"success":"true","msg":"Ok.","matnr":"0000001234"}' ). * JSON nach XSTRING (UTF-8) konvertieren DATA(lvx_string) = cl_abap_codepage=>convert_to( lv_json_response ). * XSTRING nach string wandeln DATA(lv_utf8) = cl_clb_tools=>xstring_to_string( lvx_string ). * JSON->ABAP DATA(o_json) = NEW cl_clb_parse_json( ). DATA: ls_abap TYPE ty_abap. o_json->json_to_data( EXPORTING iv_json = lv_utf8 CHANGING c_data = ls_abap ). cl_demo_output=>write_data( lv_json_response ). cl_demo_output=>write_data( ls_abap ). cl_demo_output=>display( ). CATCH cx_root INTO DATA(e_txt). MESSAGE e_txt->get_text( ) TYPE 'S' DISPLAY LIKE 'E'. ENDTRY.
[ABAP] Einfacher REST-Service (ohne OData)
Piyush Philip auf sap.com hat eine simple Möglichkeit beschrieben, wie man in ABAP einen REST-Service mit den entsprechenden CRUD-Methoden implementieren kann. Dazu ist im Wesentlichen nur eine eigene Handler-Klasse zu implementieren, die von IF_HTTP_EXTENSION
erbt. Diese Handler-Klasse wird von einem Service des ICF gerufen.
- SE80 -> Neue Klasse anlegen
- In der Klasse im Reiter
Interfaces
: vom InterfaceIF_HTTP_EXTENSION
erben - die Interface-Methode
IF_HTTP_EXTENSION~HANDLE_REQUEST
implementieren (implementiert nur REST, kein OData-Sevice!)METHOD if_http_extension~handle_request. * Typen TYPES: BEGIN OF ty_json_request, param1 TYPE char64, param2 TYPE char64, END OF ty_json_request. TYPES: BEGIN OF ty_json_response, success TYPE string, msg TYPE string, operation TYPE string, END OF ty_json_response. * Variablen DATA: rv_response TYPE ty_json_response. DATA: it_path_info TYPE stringtab. DATA: it_query_strings TYPE stringtab. * Header Fields auslesen DATA: it_header_fields TYPE tihttpnvp. server->request->get_header_fields( CHANGING fields = it_header_fields ). * Request Methode (POST, GET, PUT, DELETE ...) DATA(lv_request_method) = server->request->get_header_field( name = '~request_method' ). * URL Pathinfo DATA(lv_path_info) = server->request->get_header_field( name = '~path_info' ). * erstes '/' entfernen SHIFT lv_path_info LEFT BY 1 PLACES. SPLIT lv_path_info AT '/' INTO TABLE it_path_info. * URL Parameter (Query Strings) für Auswertung DATA(lv_query_string) = server->request->get_header_field( name = '~query_string' ). SPLIT lv_query_string AT '&' INTO TABLE it_query_strings. * Request Methoden behandeln CASE lv_request_method. * C (Create) WHEN 'POST'. * Beispiel: per Request übermittelte JSON-Daten auslesen und behandeln * Content-Typ auslesen DATA(lv_request_content_type) = server->request->get_content_type( ). * Wenn Content-Typ JSON IF lv_request_content_type CP if_rest_media_type=>gc_appl_json. * JSON-Daten auslesen und nach ABAP-Typ konvertieren -> Parameternamen müssen übereinstimmen, sonst HTTP 500! DATA(lv_request_cdata) = server->request->get_cdata( ). DATA: lv_request_abap TYPE ty_json_request. TRY. /ui2/cl_json=>deserialize( EXPORTING json = lv_request_cdata pretty_name = /ui2/cl_json=>pretty_mode-camel_case CHANGING data = lv_request_abap ). CATCH cx_root INTO DATA(e_txt). MESSAGE e_txt->get_text( ) TYPE 'S' DISPLAY LIKE 'E'. ENDTRY. rv_response = VALUE #( success = 'true' msg = lv_request_abap-param1 && ' | ' && lv_request_abap-param2 operation = lv_request_method ). ELSE. rv_response = VALUE #( success = 'false' msg = 'Request content type must be application/json' operation = lv_request_method ). ENDIF. * R (Read) WHEN 'GET'. DATA(lv_param) = server->request->get_form_field( 'param' ). rv_response = VALUE #( success = 'true' msg = lv_param operation = lv_request_method ). * U (Update) WHEN 'PUT'. rv_response = VALUE #( success = 'true' msg = '' operation = lv_request_method ). * D (Delete) WHEN 'DELETE'. rv_response = VALUE #( success = 'true' msg = '' operation = lv_request_method ). * unerlaubte Methoden abfangen WHEN OTHERS. * Fehlercode 405 zurückgeben server->response->set_status( code = cl_rest_status_code=>gc_client_error_meth_not_allwd reason = 'method not allowed' ). server->response->set_content_type( if_rest_media_type=>gc_appl_json ). server->response->set_header_field( name = if_http_header_fields=>allow value = 'POST,GET,PUT,DELETE' ). rv_response = VALUE #( success = 'false' msg = 'error' operation = lv_request_method ). ENDCASE. * wenn erfolgreich, dann Wert zurückgeben IF rv_response-success = 'true'. * HTTP-Status 200 server->response->set_status( code = cl_rest_status_code=>gc_success_ok reason = 'Ok.' ). * application/json server->response->set_content_type( if_rest_media_type=>gc_appl_json ). * Service-Response als JSON zurückgeben server->response->set_cdata( data = /ui2/cl_json=>serialize( data = rv_response pretty_name = /ui2/cl_json=>pretty_mode-camel_case ) ). ENDIF. ENDMETHOD.
- SICF -> neue ICF-Node (Sub-Element) unterhalb
default_host -> sap -> bc
als neuen unabhängigen Service anlegen - in der Handlerliste des Service die erstellte Klasse als “Handler” angeben
- auf die neue ICF-Node rechtsklicken ->
Service aktivieren
- auf die neue ICF-Node rechtsklicken ->
Service testen
- URL aus Browserfenster kopieren (
http://domain.de/sap/bc/servicename?sap-client=900
) - im Browser mir einem Rest-Plugin (FireFox-Prugin:
Rested
) testen
Links
- https://blogs.sap.com/2018/10/31/a-simple-rest-web-service-from-ecc-called-from-a-html5-screen/
- https://blogs.sap.com/2012/12/07/building-a-crud-application-with-sapui5-and-icf-restjson-service-part-1/
- https://blogs.sap.com/2013/01/24/developing-a-rest-api-in-abap/
- https://medium.com/pacroy/developing-apis-in-abap-just-rest-not-odata-d91cf899f7d3
- https://blogs.sap.com/2013/05/16/usage-of-the-abap-rest-library-sapbasis-740/
- https://www.linkedin.com/pulse/create-json-rest-service-from-sap-back-end-louis-rossi-mundecke
- REST Interfaces and Classes
- The GET Method
- The POST Method
- The PUT Method
- The DELETE Method
[SAP Gateway] Einfacher REST-Webservice / CRUD-Applikation
Links
- https://blogs.sap.com/2018/10/31/a-simple-rest-web-service-from-ecc-called-from-a-html5-screen/
- https://blogs.sap.com/2012/12/07/building-a-crud-application-with-sapui5-and-icf-restjson-service-part-1/
- https://blogs.sap.com/2012/12/07/building-a-crud-application-with-sapui5-and-icf-restjson-service-part-2/
- https://blogs.sap.com/2012/12/07/building-a-crud-application-with-sapui5-and-icf-restjson-service-part-3/
- https://blogs.sap.com/2014/03/29/developing-ui5-applications-on-legacy-systems/