Java Training Block 5 – Tag 2+3 Spring Beans + DAO

Words
1434
Reading
7 min
Listen
Play
5y

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 zweiten und dritten Tag in Block 5 gelernt und behalten habe:

Beans

Dependenci Injection -Abhängig von deinem Leiden erhältst du eine Injektion
Inversion of Controll - Nicht das Programm, sondern der Aufrufer erhält die Kontrolle (In der Spring.xml wird über die Beans gesteuert)

Die Beans werden vom Classloader geladen. Man kann sie über AnnotationConfigApplicationContext aufrufen. Er sucht dann im angegebenen Package:

Wo kommt der Begriff "Beans" her?

  1. Beans tauchten zum ersten mal bei der GUI-Programmierung auf. Sie waren z.B. Knöpfe mit Eigenschaften, also Objekte mit einer graphischen Entsprechung
  2. Später gab es dann Enterprise Java Beans, die sind aber heute auch schon veraltet.
  3. Bean PoJo (Plain old Java Object). Jede Klasse die wir bauen ist ein PoJo. Bean und Pojo sind redundante Begriffe.

Aus Spring-Sicht sind Beans Objekte, die Spring kennt. Sollten neue Objekte hinzukommen, die nicht im Spring-Context liegen, kann man sie hinzufügen mit @Component:

Hier in dem Beispiel  machen wir die Klasse MathServiceImpl zu einer Bean:

Hier werden die Beans über die Spring.xml eingeladen:

@Component bringt die Klassen in die entsprechenden Habitate

Unterschied Framework und BibliotheK:
Ein Framework ist komplizierter und hat laufende, aktive Prozesse. Eine Bibliothek bietet nur passive Prozesse, die man aufrufen muss.
Spring ist ein Framework. Es läuft aber auch in der Java Runtime Environment.

Übung ueb01-kreisrechner-spring:


Wir erstellen wieder einen Kreisrechner, mit einem Interface:
Zusätzlich erstellen wir einen Resourcen-Ordner und fügen dort eine spring.xml ein.
File/Settings/plugins/Spring&Java Tools könnte helfen, wir holen eine leere Vorlage aus einem anderen Projekt:

Leere spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

</beans>

So, bis jetzt machen wir kein Spring. Für die Nutzung brauchen wir die Klasspfad-Implementierung:

final ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml")) 

Das Objekt myLocalKreisRechner benutzt den Spring-Kontext um eine Bohne zu finden, die das Interface KreisRechner.class unterstützt. Wir instanzieren das Objekt in der App.java-Klasse:

Als nächstes erstellen wir eine Bohne im spring.xml. Wir nehmen die konkrete Klasse und nicht das Interface, da wir ja ein echtes Objekt instanziieren wollen:

<bean id="myKreisService" class="de.firma.util.BasicKreisRechner"/>

Somit läuft das Programm schon mal:

Jetzt suchen wir die Bohne nach ihrem Namen:

        KreisRechner myLocalKreisRechner = (KreisRechner) springcontext.getBean("myKreisService");  //Lookup by ID / Name -> BasicKreisRechner

<bean id="myKreisService" class="de.firma.util.BasicKreisRechner"/>

Ich kann jetzt in der Konfigurationsdatei die Beans ändern und bin damit in Inversion of Controll:

In der App gehe ich über das Interface myRechner und danach über die Klasse:

App.java

public class App 
{
    public static void main( String[] args )    {
    final ClassPathXmlApplicationContext springcontext = new ClassPathXmlApplicationContext("spring.xml");

    // KreisRechner  myLocalKreisRechner = new BasicKreisRechner(); // Klassischer Weg

    // lookup by Interface -> KreisRechner
    //KreisRechner  myLocalKreisRechner =  springcontext.getBean(KreisRechner.class);                    // lookup by Interface -> KreisRechner

    // lookup by ID / NAME -> BasicKreisRechner
    KreisRechner myLocalKreisRechner = (KreisRechner) springcontext.getBean("myKreisRechnerBasic");     // lookup by ID / NAME -> BasicKreisRechner

    System.out.println( "Flaeche von 10   : "  + myLocalKreisRechner.flaeche(10.0));
    System.out.println( "Umfang von 10    : "  + myLocalKreisRechner.umfang(10.0));

    System.out.println("----------------------------------------------");
    Rechner myRechner = springcontext.getBean(Rechner.class);

    System.out.println( "Flaeche von 10   : "  + myRechner.flaeche(10.0));
    System.out.println( "Umfang von 10    : "  + myRechner.umfang(10.0));

}

}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!--
    <bean id="myKreisRechner" class="de.firma.util.BasicKreisRechner"/>
    <bean id="myAngstKreisRechner" class="de.firma.util.AngstKreisRechner"/>
    -->
    <bean id="myKreisRechnerBasic" class="de.firma.util.BasicKreisRechner"/>
    <bean id="myKreisRechnerAngst" class="de.firma.util.AngstKreisRechner"/>
&lt;bean id="myRechner" class="de.firma.util.SimpleRechner" >
    &lt;constructor-arg ref="myKreisRechnerAngst"/>
&lt;/bean>

</beans>

Spring erzeugt eine Instanz vom Typ Kreisrechner:

Spring erzeugt ein Objekt "myKreisRechnerBasic" (roter Kringel) vom Typ BasicKreisrechner, welches das Interface Kreisrechner beinhaltet. Damit wird das Objekt zum Typ Kreisrechner.

Er registriert sich mit myKreisRechnerBasic, BasicKreisRechner, Kreisrechner in der Springcloudwolke.

Dann kommt die Laufzeitumgebung und sucht myKreisRechnerBasic in der Spring-Cloud.

MyRechner delegiert seine Berecnhung an myKreisRechnerAngst.

Rencher ist ein Interface und braucht eine konkrete Implementierung. SimpleRechner hat sich als Typ Rechner registriert, weil Simplerechner das Interface Rechner implementiert.

(Das war viel Stoff und recht kompliziert für einen Freitag. Ich denke im Beispiel unten (Ueb-kug-entity-dao) wird es evtl. noch mal übersichtlicher was Spring macht).

Tutorials:

  • https://www.tutorialspoint.com/spring/index.htm
  • https://www.javatpoint.com/spring-tutorial
  • https://www.torsten-horn.de/techdocs/jee-spring.htm

Datenzugriff mit Spring

DAO - Data Access Object

Wir haben Daten/Dokumente. Diese wollen wir speichern, verändern,… Dasgeht über das Interface DAOIF. Dieses beinhaltet verschiedene Klassen, je nach Speicher-art.

Um das ganze Dynamisch zu konfigurieren, verwenden wir Spring:

Zur Erinnerung:

Das KUGBook ist eine Entity-Klasse, da sie Daten beinhaltet.
In Boundery ist eine Schnittstelle nach draußen (außerhalb des Java-Systems, IO-Datenaustausch)

Neues Projekt: Ueb-kug-entity-dao

Mit neuen Packages: de.firma.entity und de.firma.dao
Wir erstellen die Klasse KugBook im Entity Package und das Interface KugBookDAO im dao Package.

Der KugBookController sieht so aus:

Ein Bean ist immer eine konkrete Implementierung und kein Interface.

Wir wollen das Ganze aber jetzt flexibel halten und ändern in der Spring.xml und in der App und in KuGController folgendes:

Zuerst nehmen wir aus dem Controller den Springcontext raus (weil der Aufruf jetzt von Spring erfolgen soll und nicht von App.java):

Es geht auch über die Setter Methoden (eine der beiden unteren beans muss ich auskommentieren):

Jetzt sezten wir die Values in spring.xml

Spring + Datenbanken

Java-Datenbanken:

- https://db.apache.org/derby/                                  // Derby

- http://hsqldb.org/                                                  // HSQLDB 

- https://www.h2database.com/html/main.html          //  H2

Klassisch würden wir eine Datenbank so einbinden:

Hier mit Spring organisieren wir das aber über die spring.xml.

Zuerst brauchen wir einen Treiber. Den laden wir mit der pom.xml:

    <dependency>
      <groupId>org.hsqldb</groupId>
      <artifactId>hsqldb</artifactId>
      <version>2.6.1</version>
    </dependency>

Dann brauchen wir eine URL. Diese lautet in unserem Fall:

jdbc:hsqldb:file:kugdb

Username ist "sa" und passwort ist bei uns leer.

 Die spring.xml sieht dann so aus:

Wir fügen in der spring.xml zwei Werte in die bean "dbStore" ein:

          init-method="postConstruct"

          destroy-method="preDestroy">

 Wir fügen die zwei Methoden jeweils in KugBookDAO und KugBookFile ein:

Wir füllen den Inhalt der Konstruktoren wie folgt:

KugBookDAOFile.java

package de.firma.dao;

import de.firma.entity.KugBook;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class KugBookDAOFile implements KugBookDAO{
// Eigenschaften
private String fileName;
List<KugBook> list;

//Konstruktoren

public KugBookDAOFile(String fileName) {
    this.fileName = fileName;
}


//Setter

public void setFileName(String fileName) {
    this.fileName = fileName;
}


//LifeCycle-Methoden
public void postConstruct() {
    System.out.println("KugBookDAOFile");

    // Daten aus CSV-Datei einlesen
    this.list = new ArrayList&lt;KugBook>();
    String line;
    String fieldarray[] = new String[5];

    try {
        // Puffer für die Datei einrichten
        BufferedReader br = new BufferedReader(new FileReader("data/"+this.fileName));

        // Zeilenweise einlesen der Datei
        while ((line = br.readLine()) != null) {
            if (line.length() != 0) {
                // Spitten des CSV-Datensatzes beim Pipe-Zeichens
                fieldarray = line.split("\\|");

                if (fieldarray.length == 5) {
                    String sqlstmt;
                    // Preis korrektur Dezimelkomma zum Dezimalpunkt
                    fieldarray[3] = fieldarray[3].replace(',', '.');

                    this.list.add(new KugBook(fieldarray[4],fieldarray[0],fieldarray[1],Integer.parseInt(fieldarray[2]),Double.parseDouble(fieldarray[3])));
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println(list.size());

}

public void preDestroy(){
}

// Business Methoden

@Override
public KugBook getById(String isbn) {
    return null;
}

@Override
public List&lt;KugBook> getall() {
    return null;
}

@Override
public void save(KugBook kugBook) throws DAOException {

}

@Override
public void update(KugBook kugBook) {

}

@Override
public void delete(KugBook kugBook) {

}

}

KugBookDAODB.java

package de.firma.dao;

import de.firma.entity.KugBook;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class KugBookDAODB implements KugBookDAO{
//Eigenschaften
private String driver;
private String url;
private String user;
private String pass;
List<KugBook> list;
//Konstruktoren

public KugBookDAODB(String driver, String url, String user, String pass) {
    this.driver = driver;
    this.url = url;
    this.user = user;
    this.pass = pass;
}


//Setter

public void setDriver(String driver) {
    this.driver = driver;
}

public void setUrl(String url) {
    this.url = url;
}

public void setUser(String user) {
    this.user = user;
}

public void setPass(String pass) {
    this.pass = pass;
}

//LifeCycle-Methoden

public void postConstruct() {
this.list = new ArrayList<KugBook>();
System.out.println("KugBookDAODB");

    Connection con=null;
    try {
        // Versuch: Laden des Treibers
        Class.forName(this.driver);

        // Versuch: Aufbau der Verbindung zur Datenbank
        con = DriverManager.getConnection (this.url, this.user, this.pass);

        // SQL-Statement an die Datenbank senden
        // Datenbankcontainer erzeugen
        Statement stmt = con.createStatement();

        // Datenbankcontainer ausfüren
        ResultSet rs = stmt.executeQuery ("SELECT * FROM kugtab");

        while(rs.next()) {
            String titel = rs.getString("titel");
            String autor = rs.getString("autor");
            int    jahr  = rs.getInt("jahr");
            float  preis = rs.getFloat("preis");
            String isbn  = rs.getString("isbn");
            this.list.add(new KugBook(isbn,titel,autor,jahr,preis));
        }
        // Verbindung zur Datenbank trennen
        con.close ();
    }
    catch (SQLException e) {
        System.err.println (e);
    }
    catch (ClassNotFoundException e) {
        System.err.println (e);
    }
    System.out.println(list.size());
}

public void preDestroy(){
}

// Business Methoden

@Override
public KugBook getById(String isbn) {
    return null;
}

@Override
public List&lt;KugBook> getall() {
    return null;
}

@Override
public void save(KugBook kugBook) throws DAOException {

}

@Override
public void update(KugBook kugBook) {

}

@Override
public void delete(KugBook kugBook) {

}

}

——————


Disclaimer

Alles was ich mitschrieb und verstanden habe ist ohne Gewähr.

Besten Dank an unseren sehr empfehlenswerten

Trainer: Hans-Joachim Blanke [email protected]

In den nächsten Tagen und Wochen geht’s weiter, so: stay tuned!

Gruß, Achim Mertens

Java Training Block 5 – Tag 2+3 Spring Beans + DAO | Ecency