SAP Java Entwicklung in der Cloud Platform lernen – Teil 2

SAP Java Entwicklung in der Cloud Platform lernen – Teil 2

Java Entwicklung in der SAP Cloud Platform – Teil 2

Lernen Sie mit dem Team der CloudDNA, alles über SAP Java Entwicklung in der SAP Cloud Platform. Wir erklären Ihnen alles was sie darüber wissen müssen.

Zugriff auf SAP HANA in der NEO Umgebung- Java Entwicklung

Im ersten Teil der Blogserie habe ich Sie in die Java Entwicklung auf Basis des Spring Frameworks eingeführt. Anhand eines einfachen RestControllers wurden die Grundlagen gezeigt.

Was wäre eine Applikation ohne Zugriff auf eine Datenbank. Im SAP Cloud Kontext ist es natürlich naheliegend dass SAP HANA als Datenbank verwendet wird. In diesem Teil der Blogserie zeige ich Ihnen wie Sie auf die Datenbank in der NEO Umgebung zugreifen können.

JNDI – Die gelben Seiten- Java Entwicklung

Der Zugriff auf die HANA Datenbank erfolgt über JNDI, aus meiner Sicht eine der spannendsten Technologien im Java Umfeld. Sie werden es kennenlernen und gerne damit arbeiten. Mit einem JNDI Lookup können Sie von der Laufzeitumgebung verwaltete Resourcen laden. Die Idee dahinter ist sehr einfach – die Laufzeitumgebung kümmert sich um das Instanzieren der benötigten Klassen und stellt diese der Applikation bereit.

Damit die hier vorgestellte Applikation JNDI unterstützt müssen Sie einige Tätigkeiten durchführen. Im ersten Schritt ist es erforderlich dass Sie im Verzeichnis src > main eine Unterverzeichnis namens webapp und darin in Unterverzeichnis namens WEB-INF anlegen. Nun müssen Sie im Verzeichnis src > main > webapp > WEB-INF eine Datei namens web.xml anlegen.

Verzeichnisstruktur

Verzeichnisstruktur für web.xml

Jene Resourcen die mittels JNDI verwaltet werden, müssen Sie  in der Datei web.xml als Resource Reference (resource-ref) anführen. Darin sollten Sie den Name (res-ref-name) definieren, unter dem die Resource angesprochen wird. Sowie die dahinterliegende Java Klasse (res-type) auf die typisiert wird.

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 version="3.0">
   <resource-ref>
     <res-ref-name>jdbc/DefaultDB</res-ref-name>
     <res-type>javax.sql.DataSource</res-type>
   </resource-ref>
</web-app>

Spring Data Dependency deklarieren

Damit haben Sie den ersten Schritt bereits erledigt. Nachdem wir den Zugriff auf die Datenbank nicht mittels SQL Kommandos selbst implementieren, sondern auf Spring Data zurückgreifen, müssen Sie im pom.xml noch eine entsprechende Dependency definieren.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Nachdem Spring Data eine Vielzahl an Datenbanken unterstützt, müssen Sie der Laufzeitumgebung mitteilen welche Datenbank verwendet werden soll. Das passiert über die Datei application.properties. Falls diese noch nicht existiert müssen Sie diese im Verzeichnis src > main > resources anlegen. Der vollqualifizierte Klassenname des HANA Treibers lautet com.sap.db.jdbc.Driver

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.HANAColumnStoreDialect
spring.jpa.properties.hibernate.connection.pool_size = 10
spring.datasource.driverClassName=com.sap.db.jdbc.Driver

@Configuration- SAP Java Entwicklung

Spring @Configuration-Annotation ist Teil des Spring Core Frameworks. Die Spring-Annotation weist Sie darauf hin, dass die Klasse über eine @Bean-Definitionsmethoden verfügt. Der Spring-Container kann dadurch die Klasse verarbeiten und Spring Beans zur Laufzeit generieren, die Sie in der Anwendung verwenden können.

Für die Verwendung im Neo Stack müssen Sie die Datasource mittels JNDI laden. Dazu sollten Sie eine entsprechende Klasse erstellen. In der nachfolgenden Code-Snippet wird die vollständige Klasse dargestellt.

Neo Datasource Configuration

package at.clouddna.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
@Profile({"neo"})
public class NeoConfig 
{	
	@Bean(destroyMethod="")
	public DataSource jndiDataSource() throws IllegalArgumentException, SQLException
	{
		JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
		DataSource ds = dataSourceLookup.getDataSource("java:comp/env/jdbc/DefaultDB");
		return ds;
	}
}

Der JNDI-Lookup zielt auf den Namen java:comp/env/jdbc/DefaultDB ab. Der Prefix java:comp/env/ ist in der SAP Cloud Platform immer derselbe. Der dahinter definierte Name jdbc/DefaultDB entspricht dem res-ref-name in der web.xml

Entwicklung einer Entity-Klasse

Die Verwendung von Spring-Data ermöglicht Ihnen eine sehr effiziente Entwicklung der Persistenzschicht. Spring-Data basiert auf dem Hibernate Framework. Sobald wir eine Klasse anlegen und diese mit der Annotation @Entity versehen, wird auf der darunterliegenden Datenbank eine zugehörige Tabelle angelegt. Im nachfolgende Code-Snippet zeige ich Ihnen eine einfach User Klasse.

User.java

package at.clouddna.demo.model;

import javax.persistence.*;

@Entity
public class User {

    @Column(nullable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;

    private String firstname;
    private String lastname;

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getFirstname() {
        return this.firstname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getLastname() {
        return this.lastname;
    }
}

CRUD Methoden

Das geniale an Spring-Data ist die Out-of-the-box Verfügbarkeit von CRUD Methoden. Dazu müssen sie lediglich ein Interface erstellen, dass vom JpaRespository erbt. Dies wird für die User Entity im nachfolgenden Code-Snippet dargestellt.

package at.clouddna.demo.repository;

import at.clouddna.demo.model.User;

public interface IUserRepository extends JpaRepository<User, Long> {

}

Das Respository können Sie  nun direkt im Controller verwenden, indem über Autowiring darauf zugegriffen wird. Mein Unternehmen sieht davon jedoch ab. Wir erstellen für jede Entity-Klasse immer ein zugehöriges DTO (Data Transfer Object) und erstellen zusätzlich eine Serivce-Klasse, die mit der @Service Annotation versehen wird, welche die Verwendung des Repository kapselt. Die Service-Klasse kann im Controller über die @Autowired Annotation injiziert werden.

Selbstverständlich zeige ich Ihnen wie das funktioniert.

ServiceBase Klasse und Model Mapper

Das Mapping der Entity-Klasse auf das DTO und umgekehrt führen wir nicht manuell sondern mittels ModelMapper durch. Den Modelmapper müssen Sie ins pom.xml als Dependency aufnehmen.

<dependency>
   <groupId>org.modelmapper</groupId>
   <artifactId>modelmapper</artifactId>
   <version>2.3.5</version>
</dependency>

ServiceBase.java

package at.clouddna.codegenerator.service.da;

import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public abstract class ServiceBase {

    private ModelMapper modelMapper;

    public ServiceBase(){
        this.modelMapper = new ModelMapper();
        this.modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STANDARD);
    }

    public <D, T> D map(T entity, Class<D> outClass) {
        return modelMapper.map(entity, outClass);
    }

    public <D, T> List<D> mapAll(Collection<T> entityList, Class<D> outCLass) {
        return entityList.stream()
                .map(entity -> map(entity, outCLass))
                .collect(Collectors.toList());
    }

    protected void writeToFile(String fileName, String content) throws IOException {
        FileOutputStream outputStream = new FileOutputStream(fileName);
        byte[] strToBytes = content.getBytes();
        outputStream.write(strToBytes);
        outputStream.close();
    }

    protected void writeToFile(String fileName, byte[] content) throws IOException {
        FileOutputStream outputStream = new FileOutputStream(fileName);
        outputStream.write(content);
        outputStream.close();
    }
}

Service Klasse

Die Service Klasse erbt von der ServiceBase Klasse und kapselt den Zugriff auf die Datenbank. Nachfolgendes Code-Snippet zeigt die UserService Klasse. Wichtig ist das Sie dabei die Klasse mit der Annotation @Service versehen. Dadurch können sie diese im Controller mittels Autowiring verwenden.

UserService.java

package at.clouddna.demo.service;

import at.clouddna.demo.dto.UserDto;
import at.clouddna.demo.model.User;
import at.clouddna.demo.respository.IUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class UserService extends ServiceBase {

    @Autowired
    private IUserRepository repository;

    public UserDto create(UserDto userDto) {
        return map(repository.save(map(userDto, User.class)), UserDto.class);
    }

    public UserDto update(UserDto userDto) {
        return map(repository.save(map(userDto, User.class)), UserDto.class);
    }

    public boolean delete(Long id) {
        repository.deleteById(id);
        return true;
    }

    public UserDto findById(Long id) {
        Optional<User> userOptional = repository.findById(id);
        if(!userOptional.isPresent()) {
            return null;
        }
        return map(userOptional.get(), UserDto.class);
    }

    public List<UserDto> findAll() {
        return mapAll(repository.findAll(), UserDto.class);
    }
}

RestController

Abschließend zeige ich Ihnen wie der zuvor entwickelte Service im RestController vollumfänglich für alle CRUD-Methoden verwendet werden kann. Sie werden überrascht sein wie einfach das möglich ist!

UserController.java

package at.clouddna.demo.controller;

import at.clouddna.demo.dto.UserDto;
import at.clouddna.demo.model.User;
import at.clouddna.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public ResponseEntity getAll() {
        return ResponseEntity.ok(userService.findAll());
    }

    @GetMapping("/{id}")
    public ResponseEntity getById(@PathVariable("id") Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }

    @PostMapping
    public ResponseEntity create(@RequestBody UserDto body) {
        return ResponseEntity.ok(userService.create(body));
    }

    @PutMapping("/{id}")
    public ResponseEntity update(@PathVariable("id") Long id,
                                 @RequestBody UserDto body) {
        body.setId(id);
        return ResponseEntity.ok(userService.update(body));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity delete(@PathVariable("id") Long id) {
        return ResponseEntity.ok(userService.delete(id));
    }
}

Fazit zur SAP Java Entwicklung in der Cloud Platform

Ich hoffe dass ich Ihnen in diesem Teil die Java Entwicklung in der SAP Cloud Platform schmackhaft gemacht habe. Wie Sie hoffentlich erkannt haben handelt es sich um kein Hexenwerk und keine Weltraumwissenschaft. Einen Tipp möchte ich Ihnen noch mitgeben – achten Sie bereits in der Planung des Projekts darauf dass alles sauber strukturiert ist und Sie jeweils ein eigenes Paket für Entity, DTO, Repository, Service und Controller definieren.

FAQ und Fakten über  SAP Java Entwicklung

 

Was bringt mir die  Verwendung von Spring- Data?

Die Verwendung von Spring-Data ermöglicht Ihnen eine sehr effiziente Entwicklung der Persistenzschicht. Spring-Data basiert auf dem Hibernate Framework. Sobald wir eine Klasse anlegen und diese mit der Annotation @Entity versehen, wird auf der darunterliegenden Datenbank eine zugehörige Tabelle angelegt.

Welche Technologie kann ich im Java Umfeld verwenden ?

Der Zugriff auf die HANA Datenbank erfolgt über JNDI, aus meiner Sicht eine der spannendsten Technologien im Java Umfeld. Mit einem JNDI Lookup können Sie von der Laufzeitumgebung verwaltete Resourcen laden. Die Idee dahinter ist sehr einfach – die Laufzeitumgebung kümmert sich um das Instanzieren der benötigten Klassen und stellt diese der Applikation bereit.

SAP Java Entwicklung in der Cloud Platform – Teil 1

SAP Java Entwicklung in der Cloud Platform – Teil 1

Java Entwicklung in der SAP Cloud Platform – Teil 1

In dieser Blogreihe zeige ich Ihnen wie die Java Entwicklung für die SAP Cloud Plaform auf Basis von Spring Boot durchgeführt wird. Spring Boot ist das defacto Standard Framework wenn es um die Entwicklung von Java Applikationen in der Cloud / bei Software-as-a-Service geht.

Zur Entwicklung mit Spring Boot gibt es eine Vielzahl an Resourcen im Internet, jedoch blieben die SAP Cloud Platform Spezifika dabei meist auf der Strecke. SAP bietet im Neo Stack der SAP Cloud Platform  ein SDK an, dass Ihnen die Verwendung von SAP-eigenen Funktionalitäten in Java ermöglicht. Dieser Blog fokusiert sich auf die allgemeinen Entwickleraufgaben in der Entwicklung von Java Applikationen. Dabei zeigen wir den Aufbau der pom.xml, ausserdem gehen wir darauf ein wie sein einen einfachen RestController implementierien.

Folgende Inhalte werde ich in zukünftigen Blogs zeigen:

  • Wie greife ich auf HANA DB mittels JNDI ein?
  • Zugriff auf Destinations mittels JNDI
  • Das zugreifen auf Tenant Informationen mittels JNDI
  • Der Zugriff auf User Informationen

Aufbau der pom.xml

Die pom.xml beinhaltet alle relevanten Informationen die für den Build der Applikation erforderlich sind.

Parent-Java Entwicklung

Nachdem wir auf Spring Boot setzen müssen wir dies als parent definieren

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.1.RELEASE</version>
  <relativePath />
</parent>

Properties – Java Entwicklung

In den properties können Sie die Java Version sowie die Version des SAP Cloud SDK definieren.

<properties>
  <java.version>1.8</java.version>
  <sap.cloud.sdk.version>3.107.18</sap.cloud.sdk.version>
</properties>

Dependencies- Java Entwicklung

In den dependencies können Sie die Abhängigkeiten definieren. Dabei wird u.a. auf SpringBoot Starter Web verwiesen und auch auf das SAP Cloud SDK. Beim SAP Cloud SDK ist es wichtig, dass Sie auf die in den properties definierte Version verlinken. Ausserdem sollten Sie den scope auf den Wert provided setzen. Damit wird diese Abhängigkeit nicht in das WAR file gepackt und auf als dem Server bereitgestellt betrachtet.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId> 
</dependency>

<dependency> 
  <groupId>com.sap.cloud</groupId>
  <artifactId>neo-java-web-api</artifactId>
  <version>${sap.cloud.sdk.version}</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.6</version>
</dependency>

Profile anlegen- Java Entwicklung

In diesem Beispiel der Java Entwicklung werden wir für das Deployment auf den Neo Stack ein eigenes Profil angelegen. Darin definieren sie, dass bestimmte Abhängigkeiten vom Server bereitgestellt werden und diese nicht in das WAR file eingebettet werden. Andernfalls würde der Start der Applikation fehlschlagen.

<profile>
  <id>neo</id>
  <activation>
    <activeByDefault>true</activeByDefault>
  </activation>
  <properties>
    <packaging.type>war</packaging.type>
  </properties> 
  <dependencies> 
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <scope>provided</scope>
    </dependency>  
  </dependencies>
</profile>

Build Plugins

Abschließend müssen Sie im Build noch das Spring Boot Maven Plugin definieren.

<plugins>
  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
  </plugin>
</plugins>

Build der Applikation für die SAP Cloud Platform

Sie können den Build der Applikation über die CommandLine mit folgenden Befehl durchführen.

mvn clean package -Pneo

Damit Sie die Applikation innerhalb vom Tomcat erfolgreich starten können, müssen Sie die configure Methode aus dem SpringBootServletInitializer redefinieren. Dies kann entweder direkt in der Hauptklasse der Applikation erfolgen oder in einer eigenen Klasse. Ich persönlich bevorzuge an dieser Stelle die Verwendung einer eigenen Klasse.

package at.clouddna.demo;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(DocmgmtApplication.class);
  }
}

Implementierung eines einfachen Rest Controllers

Damit ein Funktionstest durchgeführt werden kann, implementiere ich immer eine Ping Methode in einem eigenen Controller.

package at.clouddna.docmgmt.controller; 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 
import org.springframework.http.ResponseEntity; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RestController; 

@RestController 
@RequestMapping({ "/ping" }) 
public class PingController { 
  private static final Logger logger = LoggerFactory.getLogger(PingController.class); 

  @GetMapping
  public ResponseEntity<?> ping() { 
    logger.debug("ping called"); 
    return ResponseEntity.ok("Hello World"); 
  }
}

Damit sind wir mit einer einfachen Applikation bereits fertig. Beim Deployment über das SAP Cloud Platform Cockpit sollten Sie darauf achten, dass die Runtime Java Web Tomcat 8 ausgewählt wird und dass das Profile als JVM Parameter wie folgt übergeben wird.

-Dspring.profiles.active=neo

Den Ping Controller können Sie direkt aus dem Browser heraus testen, da die entsprechende Methode über einen HTTP GET Request aufgerufen wird.

Nach dem Ping gehts weiter zum 2. Teil unseres Blogserie über SAP Java Entwicklung.

 

 

Git Tutorial | Git lernen | Git einfach erklärt Teil 1

Git Tutorial | Git lernen | Git einfach erklärt Teil 1

Einführung in die Welt von Git

Herzlich willkommen bei unserem mehrteiligen CloudDNA SAP GIT Tutorial zeigt Ihnen warum das Arbeiten mit GIT für Ihre Entwickler (fast)  unumgänglich ist. SAP und GIT galt lange Zeit als Widerspruch. Doch die Zeiten ändern sich und damit auch die Anforderungen und potentielle Lösungen. Mit GIT setzten Sie definitiv auf das richtige Pferd.

Die folgenden Informationen werden auch, jedoch um einiges ausführlicher, in unseren offiziell bei der SAP im Schulungskatalog gelisteten Kursen HOUI5, HOFIO und WDECPS behandelt.

 

Inhalt CloudDNA SAP GIT Tutorial Serie

Wir zeigen Ihnen in unserem CloudDNA SAP GIT Tutorial folgende Inhalte:

  • 1. Teil: Einführung in die Welt von Git
  • 2. Teil: Begrifflichkeiten und die wichtigsten Funktionen
  • 3. Teil: SAPUI5-Entwicklung mit Hilfe von Git
    • Exkurs: LDAP-Anbindung und Git-Server-Anbindung an die SAP Cloud Platform

Zielsetzung dieses GIT Tutorials

Dieses Git Tutorial macht dich zum Git Profi

Unser Ziel ist es, dass Sie nach unseren Tutorials die unten stehende Grafik interpretieren und mit GIT Ihre SAPUI5, SAP Fiori und ABAP-Entwicklungen optimieren können.

GIT Branching

Wichtig

Seitdem GitHub die Namenskonventionen umgestellt hat, heißt der Strang, der automatisch angelegt wird, nicht mehr „master“ bzw. „origin/master“, sondern „main“ und „origin/main“. Da die SAP WebIDE diese Änderung noch nicht erkennt, muss man das entweder in der WebIDE mitgeben oder in GitHub übersteuern.

Das CloudDNA GIT Tutorial als Einführung in die GIT-Welt

Ein gutes Git Tutorial muss sich erst einmal mit grundlegenden Informationen beschäftigen. Zunächst beschäftigen wir uns mit einigen W-Fragen.

Was ist Git ?

Kurz zusammengefasst ist Git eine Software für die verteilte Verwaltung von Dateien und die damit verbunden Aktionen. Durch Versionierungen kann man Änderungen verfolgen und nachvollziehen.

Wo verwende ich Git?

Mittlerweile gibt es verschiedene Plattformen und damit auch Anbieter für Git-Software. Zu den bekanntesten zählen GitHub (Microsoft) oder Bitbucket (Atlassian).

Abhängig von den Complianceanforderungen ihres Unternehmens ergeben sich unterschiedliche Nutzungsmodelle. Man kann sich entweder bei diesen Anbietern in der Cloud platzieren, aber es besteht auch die Möglichkeit, Git auf einem eigenen Server zu installieren. Hierbei muss man beachten, dass man alle Vorteile einer Cloud-Lösung verliert. Man ist selber für Backups, Updates usw. verantwortlich.

In unseren Beispielen werden wir uns mit GitHub und einem lokalen Git-Server auseinandersetzen.

Warum Git?

Viele Entwickler kennen das Problem, wenn man gemeinsam an einem Projekt oder gar in einem Projekt am selben File arbeiten möchte, welche sich am Server befinden. Jetzt muss man sich einerseits mit den verschiedenen Versionen und/oder mit Konflikten auseinandersetzen.

GIT nimmt Ihnen all diese Probleme ab und hilft Ihnen mit einfachen Funktionen, Änderungen mit anderen Entwicklern zu teilen. GIT verwaltet Ihre Sourcen und erkennt auch gleichzeitig Konflikte, damit Sie keine Änderungen von anderen Entwicklern überschreiben.

Womit kann ich Git kombinieren?

Mit Build Pipelines kann man sicherstellen, dass die Versionen unserer Programme am Git immer ausführbar und getestet sind. Git kann man mit verschiedensten Programmen kombinieren, um Continuous Integration und Delivery (Jenkins) zu erzielen. Man kann die Verbindung von einzelnen Programmversionen im Git mit unseren Entwicklungspaketen und User Storys im SCRUM-Umfeld (Jira) herstellen.

Das waren nur einige Beispiele von dem, was alles an Kombinationen und Möglichkeiten mit Git möglich sind.

Zusammenfassung CloudDNA SAP GIT Tutorial (Teil 1)

In diesem ersten Teil des CloudDNA GIT Tutorial haben wir Ihnen die grundlegenden Informationen gezeigt. Sie wissen nun, was GIT darstellt und warum Sie GIT verwenden sollten. Durch einen kurzen Einblick in die Kombinationsmöglichkeiten wissen Sie auch, wie umfangreich das Thema rund um Git werden kann.

Im zweiten Teil der CloudDNA GIT Tutorial zeigen wir Ihnen die wichtigsten Begrifflichkeiten und Funktionen im Git-Umfeld. Damit kommen Sie dem gemeinsamen Ziel, die oben stehende Grafik interpretieren zu können und im Anschluss GIT auch im SAP-Umfeld verwenden zu können, ein großes Stück näher.

 

Unsere Empfehlung ist das Git Tutorial Teil 1 – Teil 3 chronologisch durchzuarbeiten. Falls Sie sich beim Teil 2 Git Funktionen und Begriffe um Git Umfeld schon auskennen, hab wir Ihnen den Teil3 weiter unten verlinkt. Teil 3 befasst sich mit den Themen Git Repositories anlegen und wie das Conflict Handling funktioniert. Wir wünschen viel Spass bei lesen und vorallem beim ausprobieren.

TEil 3 GIT Tutorial

Lernen Sie mit diesem Git Tutorial wie GIT Repositories angelegt und in der SAP WebIDE verwendet werden. Wir erklären ihnen ausserdem mit dieser Git Anleitung wie Konflikte gelöst werden können.

Git und SAPUi5

Sind Sie auf der Suche nach SAP Cloud Consulting oder ganz allgemein SAP Beratung in Österreich, Deutschland oder der Schweiz? Dann sind Sie bei uns genau richtig! Wir bringen sie sicher in die Cloud und kümmern uns um ihr SAP Szenarien. Wir lassen sie nicht hängen- we deliver !

Über den Autor

Daniel Krancz

Daniel Krancz

SAP-Consultant / Software-Developer

Ich bin SAP-Berater und -Entwickler im SAPUI5/Fiori- und OData-Umfeld. Seit 2019 bin ich offiziell als externer Trainer bei SAP gelistet und halte Kurse (UX, S4, …) über SAP-Webentwicklungen und Cloud-Implementierungen im In- und Ausland. Seit 2021 bin ich SAP Press Autor beim Rheinwerk Verlag im Bereich SAP Mobile.

RestModel für SAP UI5 einfach erklärt

RestModel für SAP UI5 einfach erklärt

RestModel für SAPUI5 kennenlernen

Herzlich willkommen bei unserem Blog zum Thema RestModel für SAPUI5.

Zuerst beantworten wir Ihnen die gängigsten W-Fragen! Wenn Sie noch weitere Fragen zum Thema RestModel für SAPUi5 haben hinterlassen einfache ein Nachricht!

Was? RestModel in SAPUI5?

Sie fragen sich vielleicht: RestModel in SAPUI5? Verwenden wir nicht normalerweise OData oder laden uns Daten in ein JSONModel?

Nun, mit dem RestModel für SAPUI5 lassen sich ganz leicht RESTful-Webservices konsumieren.

 

Inhaltsverzeichnis

  • Warum RestModel im SAPUI5?
  • Wie benutzen Sie das RestModel im SAPIU5?
  • Wie heissen die CRUD- Basics im Restmodel für SAPUI5?
  • Schmankler für Restmodel im SAPUI5
  • Ist das RestModel Open-Source?

Warum RestModel im SAPUI5?

Es gibt immer wieder die Anforderung, UI5 Apps zu bauen, die keinen OData-Service als Backend-Service benutzen. Jedoch ist das SAPUI5 Framework darauf ausgelegt, mit OData zu kommunizieren. Dies merken Sie direkt an der tollen Integration der ODataV2(OData in seiner reinsten Form) und ODataV4(es ist noch Luft nach oben)-Models.

Jetzt kann es jedoch sein, dass überhaupt kein OData-Service zur Verfügung steht, sondern nur ein RESTful-Webservice. Standartmäßig können Sie dieses Problem folgendermaßen lösen:

  • JSONModel.loadData(……)
    • Mit der .loadData-Methode des JSONModels könnte man einen GET-Request auf eine externe Ressource abschicken.
  • $.ajax(….)
    • Per ajax und jQuery lassen sich asynchrone Requests per Javascript losschicken. Im Grunde verwenden die bekannten UI5-Models im Hintergrund ajax-Calls.

Jedoch sind beide Lösungen nicht immer die optimalsten, vor allem da zB. das JSONModel eher als client-seitiges Model darauf ausgelegt ist, lokale Daten zu speichern.

Deshalb entwickeln wir ein RestModel auf Basis des HTTP-Clients axios.

Bei uns findet es auch Anwendung in unserem CloudDNA OData-Plugin.

Wie benutzen Sie das RestModel für SAPUI5?

Das RestModel benutzt den axios-Client, um HTTP-Calls gegen einen RESTful-Webservice abzuschicken. Axios ist ein HTTP-Client für Browser und node.js, der von Matt Zabriskie als Open-Source Projekt unter der MIT-Lizenz angeboten wird. 

Das RestModel kann nun auf den bereits umfangreichen axios-Client aufbauen und schneidert die Funktionalitäten auf UI5-Ansprüche zu. So z.B. das Mapping von Destinations auf selbstdefinierbare Zugriffspunkte in der neo-app.json.

Folgende Funktionen stehen zur Verfügung:

Wie heissen die CRUD – Basics im RestModel?

  • create – POST um Daten wegzuschicken,
  • read – GET um sich Daten zu holen
  • update – PUT um Daten zu verändern
  • remove – DELETE um Daten zu löschen

Die CRUD-Funktionen des RestModels ähneln sich syntaktisch den ODataModel-CRUD-Funktionen. Dies wurde aus einem speziellen Grund so gewählt: Die Verwendung des RestModels soll sich gewohnt anfühlen.

So könnnen Sie  zB. ein RestModel-Read folgendermaßen absenden:



this._oModel.read("/Customer", {
     success: function (oData) {
         oCodeEditor.setValue(JSON.stringify(oData, null, "\t"));
     }.bind(this)
});

Dies sieht im 1. Moment aus wie ein Read des ODataModels.
Jedoch steht hier eine Instanz des RestModels dahinter.


this._oModel = new RestModel({
    url: "&lt;myservice.com/api&gt;",
});

Mit dieser RestModel-Instanz und dem dahinterliegenden axios können Sie jetzt in gewohnter ODataModel-Manier Rest-Calls absetzen. So werden die CRUD-Methoden plus Parameter und Header unterstützt.

Das Resultat eines Requests lässt sich entweder über Callback-Funktionen oder auch per Promise abarbeiten. Somit ist man nicht mehr auf Success- und Error-Callback gebunden, sondern kann auf das Javascript Promise-Konzept zugreifen. Die zurückgelieferten Daten können z.B. in ein JSONModel geladen werden und an die View gebunden werden.

Zusätzlich – Die ‚Schmankerl‘

  • bearerTokenLogin – Speichern eines Bearer-Tokens
  • setXCSRFTokenHandling – Cross-Site-Ressource-Forging Handling
  • ….

Das RestModel bietet noch weitere nützliche Features an. So gibt es zB. die Unterstützung eines Bearer-Token Logins, sofern der Webservice diesen anbietet.

Ebenfalls kann das X-CSRF-Token gespeichert und als Request-Header für alle weiteren Requests gesetzt werden.  Dies kennen Sie als UI5-Entwickler besonders aus dem File-Upload Gebiet.

Open-Source?

Das RestModel ist natürlich Open-Source und kann auf github geklont werden. Dort wird es immer mit neuen Updates versorgt und korrigiert.

So kommen in Zukunft neue Features hinzu, wie zB. die Speicherung der angeforderten Daten per Model, so dass ein Binding betrieben werden kann und Daten per View geladen werden können.

Ebenfalls würden wir uns über die Mitarbeit anderer Entwickler an diesem Open-Source-Projekt freuen, um das bestmögliche aus dem RestModel herauszuholen.

Alles klar

Getreu unserem Leitfaden

-Von Entwickler – Für Entwickler-

 

sollte das RestModel besonders Entwickler in UI5-Umfeld nützlich sein.

Wer also auf REST-Services zugreifen möchte und mit den ODataModel-Methoden vertraut ist, für den ist das RestModel interessant und sicherlich eine Erleichterung bei REST-Calls.

Einen detailierteren Einblick mit Dokumentation gibt es auf der github-Repository-Seite des RestModels.

Wir freuen uns über konstruktive Kritik und Anregungen und falls Fragen bestehen, zögern Sie nicht und kommentieren Sie unterhalb laughing

 

UI5 Media Entity Journey | OData- Part 4

UI5 Media Entity Journey | OData- Part 4

UI5 Media Entity Journey Teil 4

In dieser 4-Teiligen Blogreihe erfahren Sie alles nötige, um Media-Entity-Handling in SAP UI5 laut gängigen Best-Practice-Erfahrungen zu implementieren.

Einen tieferen Einblick in verschiedenste Themen gibt es in unseren Kursen. Sie werden über die offiziell training.sap.com . Melden Sie sich bitten zuerst an, danach wählen sie Österreich und Deutschland aus um alle Termine zu sehen.

 Falls sie noch mehr darüber wissen wollen, bieten wir diesen  Blog interessante Trainings:

  • HOUI5 – Hands-on Foundation zur Entwicklung von SAPUI5 Applikationen
  • HOFIO – Hands-on Deep Dive zur Entwicklung von SAP Fiori Oberflächen
  • WDECPS – SAP Cloud Platform Security Eine ganzheitliche Betrachtung

Inhalt UI5 Media Entity Journey :

Im vierten Teil der Blogserie erweitern wir die UploadCollection um eine Download-Funktion.

Schritt 4 – File Download

Nachdem wir nun die Upload-Funktionalität fertig haben, möchten wir unsere Files auch downloaden können. Deshalb müssen wir noch ein paar Änderungen vornehmen.

Hilfreiche Links:

    View anpassen

    Um die UploadCollection Downloadfähig zu machen, müssen wir ein paar Anpassungen machen.

    1. Zuerst den List-Modus der UploadCollection auf MultiSelect umstellen.
      1. Wenn wir den Modus auf MultiSelect ändern, können wir danach mehrere Items, die heruntergeladen werden sollen, auswählen.
    2. Toolbar einfügen.
      1. Zunächst erweitern wir die Standart-Toolbar der UploadCollection um einen Button. Danach können wir damit die selektierten Items herunterladen. Dieser soll, sofern keine Items ausgewählt sind, disabled sein.
    3. Das UploadCollectionItem erweitern.
      1. Die Property url des UploadCollectionItems wird mit einer formattierten URL befüllt, die auf den URL-Parameter $value des jeweiligen Files zeigt.

    <UploadCollection id=“main_uploadcollection“ items=“{/FileSet}“ beforeUploadStarts=“onBeforeUploadStarts“ change=“onUploadChange“

    mode=“MultiSelect“ selectionChange=“onUploadSelectionChange“>

    <toolbar>

    <OverflowToolbar>

    <ToolbarSpacer/>

    <Button id=“main_downloadbtn“ text=“{i18n>btn.download}“ press=“onDownloadPress“ type=“Transparent“ enabled=“false“/>

    <UploadCollectionToolbarPlaceholder/>

    </OverflowToolbar>

    </toolbar>

    <items>

    <UploadCollectionItem url=“{path: ‚Fileid‘, formatter: ‚.formatUrl‘}“ documentId=“{Fileid}“ fileName=“{Filename}“ mimeType=“{Mimetype}“

    enableEdit=“false“ enableDelete=“false“ visibleDelete=“false“ visibleEdit=“false“/>

    </items>

    </UploadCollection>

    Controller bearbeiten

    Bevor es richtig losgeht programmieren wir den Formatter aus, den wir im url-Parameter verwenden. Dieser Formatter gibt einen String zurück, der die URL unseres Models plus URI unseres Files plus dem URL-Parameter $value beinhaltet. Mit dieser URL kann das File heruntergeladen werden.

    Anschließend benötigen wir noch den Eventhandler für den Button. Dieser Handler sucht sich alle selektierten UploadCollectionItems heraus und übergibt diese an die downloadItem-Funktion der UploadCollection.

    Zu guter Letzt fehlt noch der SelectionChange-Eventhandler. Dieser bewirkt das aktivieren und deaktivieren des Download-Buttons wenn Items bzw. keine Items ausgewählt wurden.

    formatUrl: function (sFileid) {

                                                let sUrl = this.getView().getModel().sServiceUrl;

                                                sUrl += „/“ + this.getView().getModel().createKey(„FileSet“, {

                                                               Fileid: sFileid

                                                });

                                                sUrl += „/$value“;

                                                return sUrl;

                                  },

     

                                  onDownloadPress: function (oEvent) {

                                                let oUploadCollection = this.getView().byId(„main_uploadcollection“),

                                                               aSelectedItems = oUploadCollection.getSelectedItems();

                                                for (var i = 0; i < aSelectedItems.length; i++) {

                                                               oUploadCollection.downloadItem(aSelectedItems[i], true);

                                                }

                                  },

     

                                  onUploadSelectionChange: function (oEvent) {

                                                let oUploadCollection = oEvent.getSource(),

                                                               oButton = this.getView().byId(„main_downloadbtn“);

                                                if (oUploadCollection.getSelectedItems().length > 0) {

                                                               oButton.setEnabled(true);

                                                } else {

                                                               oButton.setEnabled(false);

                                                }

                                  },

    Testen

    Wenn nun alle Änderungen korrekt übernommen wurden, können danach die Files entweder einzeln per Klick auf den Namen oder per Mehrfachselektion heruntergeladen werden.

    Zusammenfassung

    Wir sind fertig!wink

    Im letzen Schritt haben wir unser UploadCollection-Projekt fertig gemacht , nun können Files rauf- und runterladen.

    Nochmals alles von Anfang an:

    1. Wir erstellen uns DDIC-Objekte zur Speicherung und zum Anzeigen von unseren Files.
    2. Danach konfigurieren wir einen OData-Service mit einer MediaEntity und redefinieren die STREAM-Methoden.
    3. Ausserdem erstellen wir eine UI5-App und binden die UploadCollection ein und laden Files per OData-Service hoch.
    4. Wir laden Files per downloadItems-Funktion der UploadCollection herunter.

    Ich bedanke mich für das Lesen unseres Blogs über MediaHandling mit der UploadCollection. Es würde mich freuen, wenn man sich wieder auf einem neuen Blog sieht.

    Falls Fragen zu diesen einzelnen Schritten auftreten, können sie gerne in den Kommentaren gestellt werden.

     

     

    Die UI5-Media-Entity Journey – Part 3

    Die UI5-Media-Entity Journey – Part 3

    In dieser 4-Teiligen Blogreihe erfahren Sie alles nötige, um Media-Entity-Handling in SAP UI5 laut gängigen Best-Practice-Erfahrungen zu implementieren.

    Einen tieferen Einblick in verschiedenste Themen gibt es in unseren Kursen bei Die Entdecker, die offiziell über training.sap.com angeboten werden.

    Für diesen Blog interessante Trainings:

    • HOUI5 – Hands-on Foundation zur Entwicklung von SAPUI5 Applikationen
    • HOFIO – Hands-on Deep Dive zur Entwicklung von SAP Fiori Oberflächen
    • WDECPS – SAP Cloud Platform Security Eine ganzheitliche Betrachtung

    Inhalt

    Im dritten Teil der Blogserie erstellen wir eine SAPUI5-App und integrieren die sap.m.UploadCollection.

    Schritt 3 – File Upload

    Wir erstellen nun eine SAPUI5 Applikation über die SAP WebIDE. Des weiteren binden wir den OData-Service ein, den wir in Schritt 2 erstellt haben, um Files zu speichern und anzuzeigen,

    Hilfreiche Links:

     

    Voraussetzungen

    • Zugang zur SAP Web IDE
    • Ein korrekt eingerichteter Cloud Connector mit dazugehöriger Destination in der SAP CP

    App erstellen

    Wir wechseln in die SAP WebIDE und legen per Create Project from Template ein neues SAPUI5 Projekt an.

    Nennen wir sie ZDemoFile im Namespace at.demo.file und benutzen als Default-View eine View mit dem Namen Main.

    Da wir nur eine View anzeigen und keine Navigation haben, benötigen wir nicht eine weitere View als Navigationscontainer.

    Im i18n.properties-File kann noch der Titel der Page angepasst werden.

    OData-Service hinzufügen

    Sobald die App nun erstellt ist, kann per rechtsklick ein neuer OData-Service hinzugefügt werden. Hier bitte die Voraussetzungen oben beachten.

    Wir suchen, sobald wir die richtige Destination ausgewählt haben, unseren Service und setzen diesen als Default-Model für unsere App.

    UploadCollection implementieren

    Als 1. Schritt implementieren wir die UploadCollection samt UploadCollectionItem.

    Diese beiden Controls befinden sich im sap.m.-Standartnamensraum und können daher ohne Alias definiert werden.

     Wir definieren folgende Properties für die Upload Collection:

    • items=“{/FileSet}“
      • Zeigt auf unser EntitySet.
    • beforeUploadStarts=“onBeforeUploadStarts“
      • Eventhandler für das Event welches aufgerufen wird, bevor der Upload beginnt.
    • change=“onUploadChange“
      • Eventhandler, der zieht sobald ein File zum Upload ausgewählt wird.

    Und für das UploadCollectionItem

    • documentId=“{Fileid}“
    • fileName=“{Filename}“
    • mimeType=““{Mimetype}

    <UploadCollection id=“main_uploadcollection“ items=“{/FileSet}“ beforeUploadStarts=“onBeforeUploadStarts“ change=“onUploadChange“><UploadCollection id=“main_uploadcollection“ items=“{/FileSet}“ beforeUploadStarts=“onBeforeUploadStarts“ change=“onUploadChange“> <items> <UploadCollectionItem documentId=“{Fileid}“ fileName=“{Filename}“ mimeType=“{Mimetype}“ enableEdit=“false“ enableDelete=“false“ visibleDelete=“false“ visibleEdit=“false“/> </items> </UploadCollection>

    Sobald die App nun gestartet wird, sehen wir das in Schritt 2 hochgeladene File.

    Controller bearbeiten

    Wir wechseln nun in den Main-Controller.

    Dort implementieren wir die beiden Eventhandler uns setzten die Upload-URL für die UploadCollection.

    Zuerst speichern wir uns in der onInit-Funktion unsere UploadCollection und setzen die Upload-URL. Diese setzt sich aus der Service-URL unseres Models und dem Entity-Set FileSet zusammen.

    In der onUploadChange-Funktion behandeln wir den XCSRF-Header. Dieser ist für Cross-Site-Resource-Forging zuständig und muss gesetzt werden. Das ODataModel bietet mit der Funktion getSecurityToke() die Möglichkeit, sich ein solches XCSRF-Token zu generieren lassen. Dass muss anschließend noch als HeaderParameter gesetzt werden.

    In der onBeforeUploadStart-Funktion muss der Slug-Header gesetzt werden. Den Filenamen bekommen wir über das Event-Objekt heraus.

    sap.ui.define([

                   „sap/ui/core/mvc/Controller“,

                   „sap/m/UploadCollectionParameter“

    ], function (Controller, UploadCollectionParameter) {

                   „use strict“;

     

                   return Controller.extend(„at.demo.file.ZDemoFile.controller.Main“, {

                                  oFileUploader: null,

     

                                  onInit: function () {

                                                this.oFileUploader = this.getView().byId(„main_uploadcollection“);

                                                 this.oFileUploader.setUploadUrl(this.getView().getModel().sServiceUrl + „/FileSet“);

                                  },

     

                                  onUploadChange: function (oEvent) {

                                                let oCSRFHeader = new UploadCollectionParameter({

                                                               name: „x-csrf-token“,

                                                               value: this.getView().getModel().getSecurityToken()

                                                });

     

                                                this.oFileUploader.removeAllHeaderParameters();

                                                this.oFileUploader.addHeaderParameter(oCSRFHeader);

                                  },

     

                                  onBeforeUploadStarts: function (oEvent) {

                                                let oHeaderSlug = new UploadCollectionParameter({

                                                               name: „slug“,

                                                               value: oEvent.getParameter(„fileName“)

                                                });

     

                                                oEvent.getParameters().addHeaderParameter(oHeaderSlug);

                                  },

                   });

    });

    .

    Upload testen

    Sobald nun der Controller passt, kann die Upload-Funktionalität getestet werden.

    Mit Hilfe des Hochladen-Buttons kann jetzt einen Daten geuploadet werden. Die UploadCollection zeigt anschließend das hochgeladene File in der Liste an. Solle es nicht angezeigt werden, kann dem mit einem Refresh auf das Model oder die Items-Aggregation abhilfe geschafft werden. 

    Zusammenfassung

    Alles klapptwink

    In diesem Schritt haben wir die Upload-Funktion für unsere Media-Entity implementiert. Aber nur der Upload führt noch nicht zum Ziel, denn wir möchten ja auch downloaden können.

    Dies geschieht in Schritt 4, wo wir die UploadCollection um die Download-Funktion erweitern.

    Falls Fragen zu diesen einzelnen Schritten auftreten, können sie gerne in den Kommentaren gestellt werden.