Java Training Block 12 – Microservices + Docker – Tag 3

Ich nehme derzeit an einer Akademie zum Java Fullstack Software Engineer teil. In den kommenden Wochen möchte ich hier meine Mitschrift, so gut es geht, aufzeichnen und mitteilen. Hier ist das, was ich vom dritten Tag in Block 12 gelernt und behalten habe:

Zusammenfassung vi:

Übung 03 - Anlegen eines MariaDB-Docker-Containers

Anlegen eines Zielordners:

Dort verschieben wir unsere kugbuch.sql Datei hinein:

Diese wurde aus einer bestehenden MariaDB mit einem Dump erstellt. Hier ein Auschnitt aus dem Inhalt:

docker pull mariadb

(Kleiner Exkurs: Wir wollen tree installiert haben. Dafür installieren wir es mit

sudo yum install tree

)

MariaDB ist jetzt da:

Es gibt ein internes Verzeichnis, welches später nach außen gemappt werden sollte: /var/lib/mysql

Entnommen aus: https://hub.docker.com/_/mariadb, dort auf das latest dockerfile gehen:

Übergabe von Umgebungsvariablen in den Container:
Der Parameter -e beim docker run erlaubt es, von außen Umgebungsvariablen mitzugeben. Mit "MYSQL_ROOT_PASSWORD=pass" erzeugen wir ein root-Passort mit dem Inhalt "pass". Würden wir das nicht tun, würde ein Zufallspasswort erzeugt, dass keiner kennt.
Nun kann man über die History den Aufruf und damit das Passwort zurück verfolgen. Dagegen hilft z.B.:
Man kann das Passwort nachher im bestehenden Container ändern.
Oder man versteckt das Passwort über eine Bash-Variablen (MYSQL_ROOT_PASSWORD=$PASSWORD). Dieses Verfahren wird später bei einer Pipeline verwendet.

Für unsere Testzwecke geht das Passwort auch im Klartext:
docker run -d -p 3306:3306 -v /home/linux/docker-space/mariadb-dbms:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=pass --name mariadb mariadb

Befüllung der Mariadb

Wir wechseln in die Bash und dann in die Maria-DB:

[linux@essen2-0005 mariadb-dbms]$ docker exec -it mariadb bash
root@efc54ea96b33:/# mysql -u root -h localhost -p

show databases; :

Einbinden der DB:

source /var/lib/mysql/kugdb.sql

Wir sehen jetzt mit "show databases; " die hinzugefügte kugbd.

Wir sind jetzt schon in der DB drin. Sollten wir wechseln wollen, geht das mit "use kugdb;"

Mit "show tables;" sehen wir die Tabellen.

Mit "select * from kurzundgut;" sehen wir den Inhalt der Tabelle:

Wie wurde die Tabelle erstellt? Das Ergebnis sieht man mit "show create table kug_myisam;"


Uebung 04 - Bauen eine BookServices

Als nächstes wollen wir einen Bookservice bauen auf Basis eines Restfull Services:

Erstellen des Java-Springboot Servers

Wir entzippen das Jarfile und starten es mit IntelliJ:

( Exkurs: Java-Expression:
${…… : ……}
${ENV : Default}
Der Doppelpunkt entspricht einem "oder". Also entweder, wenn die Umgebungsvariable gesetzt ist, nimmst du diese, ansonsten nimmst du das Default.
Zur Erinnerung: Umgebungsvariablen werden beim Java-Aufruf mitgegeben werden: java -dMYSQL_HOST= 192.168.1.15 -jar myapp.jar
Ende Exkurs Java Expression)

Hier der Inhalt für die application.properties:

#spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/kugdb?useSSL=false
#spring.datasource.url=jdbc:mysql://${MYSQL_HOST:10.0.1.20}:3306/kugdb?useSSL=false
#spring.datasource.url=jdbc:mysql://10.0.1.20:3306/kugdb?useSSL=false
# ${MYSQL_HOST:10.0.1.20}
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mariadb://10.91.17.75:3306/kugdb
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=pass

Damit läuft bei uns (der MariaDB Container ist gestartet, die Firewall hat den Port 3306 durchgelassen, der Maven-Nexus-Server hat alle Abhängigkeiten runtergeladen,…) der Spring-Server rudimentär:

Bauen der Packages:
Repository - DAO
Service: model
Controller: jaxrs

Im Ordner model erstellen wir KUGBook.java:

package de.firma.model;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

//JSQL NamedQuery's erzeugen
//Syntax
// @NamedQueries({
// @NamedQuery(name="", query=""),
// @NamedQuery(name="", query=""),
// @NamedQuery(name="", query="")
// })

//SQL-Query : select isbn, titel, autor, erscheinungsjahr, preis from kugtab;
// : select * from kugtab;
// : select k.* from kugtab k; Alias-Schreibweise

//JPQL : select k from KUGBuch k
// - Klasse
// - Objekt
// - List

//@NamedQueries({
// @NamedQuery(name="getAllKUGBooks",
// query="select k from KUGBook k"),
//
// //Liste aller Bücher bei der ich über Parameter das Erscheinungsjahr angeben kann
// @NamedQuery(name = "find kugbuch by year",
// query = "select k from KUGBook k where k.jahr = :year")
//
//})

@Entity
@Table(name="kurzundgut")
public class KUGBook {

// Eigenschaften
@Id
private String isbn;
private String titel;
private String autor;
private int jahr;
private float preis;

//Konstruktoren
public KUGBook() {
    super();
}

public KUGBook(String isbn, String titel, String autor, int jahr, float preis) {
    this();
    this.isbn = isbn;
    this.titel = titel;
    this.autor = autor;
    this.jahr = jahr;
    this.preis = preis;
}

// Getter- und Setter-Methoden
public String getIsbn() {
    return isbn;
}

public void setIsbn(String isbn) {
    this.isbn = isbn;
}

public String getTitel() {
    return titel;
}

public void setTitel(String titel) {
    this.titel = titel;
}

public String getAutor() {
    return autor;
}

public void setAutor(String autor) {
    this.autor = autor;
}

public int getJahr() {
    return jahr;
}

public void setJahr(int jahr) {
    this.jahr = jahr;
}

public double getPreis() {
    return preis;
}

public void setPreis(float preis) {
    this.preis = preis;
}

// Bussines-Logik
@Override
public String toString() {
    return this.isbn +" "+ this.titel +" "+ this.jahr +" "+ this.preis ;
}

}

Jaxrs.BookController.java:

package de.firma.jaxrs;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import de.firma.dao.BookRepository;
import de.firma.model.KUGBook;

@RestController
@RequestMapping(path="/bookservices")
@CrossOrigin(origins = "*")
public class BookController {

@Autowired
private BookRepository repository;

@GetMapping("/count")  
public long count() {
    return repository.count();
}

@GetMapping("/all")  
public List<KUGBook> all() {
    return repository.findAll();
}

// @GetMapping("/isbn")
// public KUGBook isbn(@RequestParam(value="isbn") String isbn) {
// return repository.findByISBN(isbn);
// }

@GetMapping("/titel")
public KUGBook title(@RequestParam(value="titel") String title) {
    return repository.findByTitel(title);
}

}

de.firma.dao.BookRepository.java:

package de.firma.dao;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
//import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import de.firma.model.KUGBook;

@Repository
public interface BookRepository extends JpaRepository<KUGBook,String>{
public KUGBook findByTitel(String title);
public List<KUGBook> findAll();
}

Es funktioniert:

Wir legen jetzt noch eine Readme-Datei an und kopieren folgendes da rein:

Datenbank:

docker run -d -p 3306:3306 -v /home/icke/docker-space/mariadb-dbms:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=pass --name mariadb mariadb

docker exec -it mariadb bash
mysql -u root -h localhost -p

souce /var/lib/mysql/kugdb.sql
use kugdb;
select * from kurzundgut

docker stop mariadb

Docker:

Build eines Image:
docker build -t bookservice.img .
docker images

Build eines Containers
sudo netstat -anp |grep tcp
docker run -d --name bookservice -p8082:8080 bookservice.img

docker ps -a

Test:

curl -v -X GET http://localhost:8080/bookservices/all

Erstellung eines Docker Images

Nun legen wir aus dem IntelliJ-Projekt ein Jar File an:

Wir kopieren das Jar-File aus dem Target-Ordner in unseren Linux-Server (/home/linux/docker-space/bookservice)

Wir erstellen auch ein Dockerfile. Dieses legen wir in in den Readme-Ordner und später auch in den Linux-Ordner. Inhalt:

FROM openjdk:11

WORKDIR /
ADD ueb-04-book-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8080
CMD java -jar app.jar

Wir bauen jetzt das Docker-Image (-t = --tag):

docker build -t bookservice.img .

Und starten können wir den Webservice mit:

docker run -d --name bookservice -p8081:8080 bookservice.img

Wir testen es mit:

 curl -X GET http://localhost:8081/bookservices/all

Zusammenfassung Bookservice:


Installation einer NoSQL MongoDB

Beispiele für NoSQL: Windows Regestry (hierarchische Strukturen), JSON (Document)

Es ist manchmal sinnvoll, die Daten so zu halten, wie sie sind und nicht in relationale DB-Strukturen hin und her zu wandeln.

Wir wollen die Mitarbeiter später im JSON Format halten. Daher ist es sinnvoll eine MongoDB zu verwenden.

MongoDB- Links:
https://hub.docker.com/_/mongo (Docker HUB)
https://spring.io/guides/gs/accessing-data-mongodb/
https://spring.io/guides/gs/accessing-mongodb-data-rest/
https://www.tutorialspoint.com/mongodb/index.htm
https://developer.mongodb.com/community/forums/

Image laden:

docker pull mongo
docker run -d -p 27017-27019:27017-27019 --name mongodb mongo

Wir starten den Mongo-DB-Client um Daten zu importieren:

docker exec -it mongodb bash
mongo

Anlegen einer Datenbank:

use CustomerDB

Bauen einer Variablen Customer mit einem Array von Objekten:

var customer=
[
    { "id":1, "firstName":"Homer", "lastName":"Simpsons", "adress":"742 Evergreen Terrace ", "zip":"62769", "place":"Springfield", "age":42, "parent":["Abe","Mona"],    "hair":"none",  "icon":"01_homer_simpson.jpg", "enabled":true },
    { "id":2, "firstName":"Marge", "lastName":"Simpsons", "adress":"742 Evergreen Terrace ", "zip":"62769", "place":"Springfield", "age":35, "parent":["Jacqueline"],    "hair":"blond", "icon":"02_marge_simpson.jpg", "enabled":true },
    { "id":3, "firstName":"Bart",  "lastName":"Simpsons", "adress":"742 Evergreen Terrace ", "zip":"62769", "place":"Springfield", "age":9,  "parent":["Homer","Marge"], "hair":"blond", "icon":"03_bart_simpson.jpg",  "enabled":true },
    { "id":4, "firstName":"Lisa",  "lastName":"Simpsons", "adress":"742 Evergreen Terrace ", "zip":"62769", "place":"Springfield", "age":10, "parent":["Homer","Marge"], "hair":"blond", "icon":"04_lisa_simpson.jpg",  "enabled":true },
    { "id":5, "firstName":"Maggie","lastName":"Simpsons", "adress":"742 Evergreen Terrace ", "zip":"62769", "place":"Springfield", "age":2,  "parent":["Homer","Marge"], "hair":"black", "icon":"05_maggie_simpson.jpg","enabled":true }
];

Einfügen dieser Variable in die CustomerDB:

db.Customer.insert(customer);

Querie-Beispiele:

db.Customer.find({});                                  // Find All
db.Customer.find({"firstName" : "Homer"});              // Find Homer
db.Customer.find({"enabled" : true});                   // Find  Simpsons   

db.Customer.countDocuments({});
db.Customer.countDocuments({"enabled" : true});

System-Befehle:

db.adminCommand( { listDatabases: 1 } );
show dbs;
db.getCollectionInfos();
use CustomerDB;
db.Customer.find({});
db.dropDatabase();

Der Zugriff kann auch graphisch erfolgen:

NoSQL-Booster https://nosqlbooster.com/


Übung 05 - Bauen eines SpringBoot Customer Services

Wir starten das Jar-File mit IntelliJ, fügen den Ordner Readme und das obige Bildchen hinzu und erstellen die Packages dao, jaxrs und model:

de.firma.model.Customer.java:

package de.firma.model;

import org.springframework.data.annotation.Id;
//import org.springframework.data.mongodb.core.mapping.Document;

//@Entity // geht nicht weil Anbindung an JPA fehlt
//@Table(name="kunden") // geht nicht weil Anbindung an JPA fehlt
//@Document(collection="kunden")
public class Customer {

@Id
private int id;
private String firstName;
private String lastName;
private String adress;
private String zip;
private String place;
private int age;
private String[] parent;
private String hair;
private String icon;
private boolean enabled;

public Customer() {
    super();
}

public Customer(int id, String firstName, String lastName, String adress, String zip, String place, int age,
        String[] parent, String hair, String icon, boolean enabled) {
    super();
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    this.adress = adress;
    this.zip = zip;
    this.place = place;
    this.age = age;
    this.parent = parent;
    this.hair = hair;
    this.icon = icon;
    this.enabled = enabled;
}

public int getId() {
    return id;
}

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

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getAdress() {
    return adress;
}

public void setAdress(String adress) {
    this.adress = adress;
}

public String getZip() {
    return zip;
}

public void setZip(String zip) {
    this.zip = zip;
}

public String getPlace() {
    return place;
}

public void setPlace(String place) {
    this.place = place;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public String[] getParent() {
    return parent;
}

public void setParent(String[] parent) {
    this.parent = parent;
}

public String getHair() {
    return hair;
}

public void setHair(String hair) {
    this.hair = hair;
}

public String getIcon() {
    return icon;
}

public void setIcon(String icon) {
    this.icon = icon;
}

public boolean isEnabled() {
    return enabled;
}

public void setEnabled(boolean enabled) {
    this.enabled = enabled;
}

@Override
public String toString() {
    return String.format("Customer [id=%i, firstName='%s', lastName= '%s']", id, firstName,lastName);
}

}

de.firma.dao.CustomerRepository:

package de.firma.dao;

import java.util.List;

import org.springframework.data.mongodb.repository.MongoRepository;
import de.firma.model.Customer;

public interface CustomerRepository extends MongoRepository<Customer,Integer>{
public Customer findById(int id);
public List<Customer> findByFirstName(String firstName);
public List<Customer> findByLastName(String lastName);

}

de.firma.jaxrs.CustomerController:

package de.firma.jaxrs;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import de.firma.dao.CustomerRepository;
import de.firma.model.Customer;

@RestController
@RequestMapping(path="/customerservices")
@CrossOrigin(origins = "*")
public class CustomerController {

@Autowired
private CustomerRepository repository;

@GetMapping("/init")
public void init() {
    // !!!!Temporäres repository erzeugen !!!!
    
    // Collection (Tabelle) löschen 
    repository.deleteAll();
    
    // Collection mit Dokumenten (Datensätzen) füllen 
    Customer Homer = repository.save(new Customer(1, "Homer","Simpsons","742 Evergreen Terrace","627692","Springfield",42 ,null,"none","01_homer_simpson.jpg",true));
    Customer Marge = repository.save(new Customer(2, "Marge","Simpsons","742 Evergreen Terrace","627692","Springfield",35 ,null,"none","02_marge_simpson.jpg",true));
    Customer Bart = repository.save(new Customer(3, "Bart","Simpsons","742 Evergreen Terrace","627692","Springfield",9 ,null,"none","03_bart_simpson.jpg",true));
    Customer Lisa = repository.save(new Customer(4, "Lisa","Simpsons","742 Evergreen Terrace","627692","Springfield",10 ,null,"none","04_lisa_simpson.jpg",true));
    Customer Maggie = repository.save(new Customer(5, "Maggie","Simpsons","742 Evergreen Terrace","627692","Springfield",2 ,null,"none","05_maggie_simpson.jpg",true));
}

@GetMapping("/count")
public long count() {
    return repository.count();
}

// all , id , firstname ,firstname

@GetMapping("/all")
public List&lt;Customer> all() {
    return repository.findAll();
}

@GetMapping("/id")
public Customer id(@RequestParam(value="id",defaultValue= "1") int id) {
    return repository.findById(id);
}

@GetMapping("/firstname")
public List&lt;Customer> firstname(@RequestParam(value="name",defaultValue= "Homer") String name) {
    return repository.findByFirstName(name);
}

@GetMapping("/lastname")
public List&lt;Customer> lastname(@RequestParam(value="name",defaultValue= "Simpsons") String name) {
    return repository.findByLastName(name);
}

}

application.properties:

server.port=8080

#spring.data.mongodb.host=10.91.17.3
spring.data.mongodb.host=10.91.17.75
spring.data.mongodb.port=27017
spring.data.mongodb.database=CustomerDB
#spring.data.mongodb.username=
#spring.data.mongodb.password=******

Dockerfile:

FROM openjdk:11
WORKDIR /
ADD ueb-05-customer-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8080
CMD java -jar app.jar

readme.md:

Call:  curl -v -X GET http://localhost:8080/customerservices/init
Call:  curl -v -X GET http://localhost:8080/customerservices/count

Docker:

Build eines Image:
docker build -t customerservice.img .
docker images

Build eines Containers
docker run -d --name customerservice -p8080:8080 customerservice.img

Call: curl -v -X GET http://localhost:8080/customerservices/init
Call: curl -v -X GET http://localhost:8080/customerservices/count
Call: curl -v -X GET http://localhost:8080/customerservices/all
Call: curl -v -X GET http://localhost:8080/customerservices/id?id=4
Call: curl -v -X GET http://localhost:8080/customerservices/firstname?name=Lisa
Call: curl -v -X GET http://localhost:8080/customerservices/lastname?name=Simpsons

Wir exportieren wieder das jar-File und kopieren es zu unserem Linux-Docker Server.

Dort bauen wir den Docker Container wie im readme.md beschrieben zusammen.

Es läuft!

Mit dem curl ... init Befehl erstellen wir in der Mongo-DB die Datensätze (warum -> siehe den Customer-Controller).
Mit dem curl ... /all Befehl sehen wir alle erstellen Datensätze:

————————————————-

Disclaimer

Alles was ich mitschrieb und verstanden habe ist ohne Gewähr. Die Bilder stammen teilweise aus dem Internet und wir haben keine Urheberansprüche darauf.

Besten Dank an unseren sehr empfehlenswerten

Trainer: Hans-Joachim Blanke blanke@4point.de

In den nächsten Tagen geht es weiter, so: stay tuned!

Achim Mertens

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now
Logo
Center