Skip to content

12. [TD]: Implementierung der Schicht [DAO] von TD mit [Spring Data]

Stichworte: mehrschichtige Architektur, Spring, Abhängigkeitsinjektion, API JPA (Java Persistence API), Spring Data.

Wir werden denselben Ansatz wie zuvor verfolgen, um die Schicht [DAO] des TD zu implementieren.

12.1. Support

  • in [1]; der Ordner [support / chap-12] enthält das Eclipse-Projekt zu diesem Kapitel;

12.2. Das Eclipse-Projekt

Das Eclipse-Projekt sieht wie folgt aus:

  
  • [elections.dao.config]: enthält die Konfigurationsklasse des Spring-Projekts;
  • [elections.dao.entities]: enthält die Entitäten JPA sowie die Ausnahmeklasse des Projekts;
  • [elections.dao.repositories]: enthält die Schnittstellen [CrudRepository] für die Tabellen [CONF] und [LISTES];
  • [elections.dao.service]: enthält die Implementierung der Schicht [DAO]. Diese müssen wir schreiben;
  • [elections.dao.console]: enthält eine Testklasse vom Typ [console];
  • [pom.xml]: die Konfigurationsdatei des Maven-Projekts;

Dieses Projekt implementiert die folgende Architektur:

Die Schicht [DAO] sieht nur die von [Spring Data] implementierte Schicht.

12.3. Maven-Konfiguration


Aufgabe: Erstellen Sie die Datei [pom.xml] des Projekts.


12.4. Die Entitäten der Schicht [JPA]

  
  • [ElectionsConfig] ist das Objektmodell, das einer Zeile der Tabelle [CONF] zugeordnet ist;
  • [ListeElectorale] ist das Objektmodell, das einer Zeile der Tabelle [LISTES] zugeordnet ist;
  • [AbstactEntity] ist die übergeordnete Klasse der beiden vorgenannten Klassen. Sie fasst die Felder von [id, version] zusammen, die beiden Klassen gemeinsam sind;
  • [ElectionsException] ist die Ausnahmeklasse des Projekts;

12.4.1. Die Klasse [ElectionsException]

  

Die Klasse [ElectionsException] ist die in Abschnitt 4.3 beschriebene unkontrollierte Ausnahme.

12.4.2. Die Klasse [AbstractEntity]

  

Die Klasse [AbstractEntity] lautet wie folgt:


package elections.dao.entities;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@MappedSuperclass
public abstract class AbstractEntity implements Serializable{
    private static final long serialVersionUID = 1L;

    // Eigenschaften
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    protected Long id;
    @Version
    @Column(name = "VERSION")
    protected Long version;

    // Konstruktoren
    public AbstractEntity() {

    }

    public AbstractEntity(Long id, Long version) {
        this.id = id;
        this.version = version;
    }

    // Neudefinition von [equals] und [hashcode]
    @Override
    public int hashCode() {
        return (id != null ? id.hashCode() : 0);
    }

    @Override
    public boolean equals(Object entity) {
        if (!(entity instanceof AbstractEntity)) {
            return false;
        }
        String class1 = this.getClass().getName();
        String class2 = entity.getClass().getName();
        if (!class2.equals(class1)) {
            return false;
        }
        AbstractEntity other = (AbstractEntity) entity;
        return id != null && this.id == other.id;
    }

    // Signatur jSON
    public String toString() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writeValueAsString(this);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Getter und Setter
...
}

Dies ist die in Abschnitt 11.3.5.2 beschriebene Klasse, jedoch ohne die Filter jSON. Hier bestehen nämlich keine Fremdschlüsselbeziehungen zwischen den Tabellen [CONF] und [LISTES]. Das Vorhandensein einer solchen Beziehung zum Modus [lazy loading] macht jedoch die Filter jSON erforderlich.

12.4.3. Die Klasse [ElectionsConfig]

  

Die Klasse [ElectionsConfig] ist die Entität JPA, die der Tabelle [CONF] zugeordnet ist;


Aufgabe: Erstellen Sie die Klasse [ElectionsConfig].


12.4.4. Die Klasse [ListeElectorale]

  

Die Klasse [ListeElectorale] ist die Entität JPA, die der Tabelle [LISTES] zugeordnet ist;


Aufgabe: Erstellen Sie die Klasse [ListeElectorale].


12.5. Die Schicht [Spring Data]

  

Aufgabe: Schreiben Sie die beiden Schnittstellen von [Spring Data] zur Verwaltung der beiden Tabellen [CONF] und [LISTES];


12.6. Die Schicht [DAO]

  

Die Schnittstelle [IElectionsDao] der Schicht [DAO] lautet wie folgt:


package dao.service;

import dao.entities.ElectionsConfig;
import dao.entities.ListeElectorale;

public interface IElectionsDao {

    // Wahlkonfiguration
    public ElectionsConfig getElectionsConfig();

    // Kandidatenlisten
    public ListeElectorale[] getListesElectorales();

    // Aktualisierung der Kandidatenlisten
    public void setListesElectorales(ListeElectorale[] listesElectorales);
}

Aufgabe: Schreiben Sie die Implementierung [ElectionsDaoJpa] der Schnittstelle [IElectionsDao].


12.7. Konfiguration des Spring-Projekts

  

Die Klasse [DaoConfig] konfiguriert das Spring-Projekt.


Aufgabe: Schreiben Sie die Klasse [DaoConfig]


12.8. Die Windel [console]

  

Die Klasse [Main] ist die folgende ausführbare Klasse:


package dao.console;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import dao.config.AppConfig;
import dao.entities.ElectionsConfig;
import dao.entities.ListeElectorale;
import dao.service.IElectionsDao;

public class Main {

    // Datenquelle
    private static IElectionsDao dao;

    public static void main(String[] args) {
        // Abruf des Spring-Kontexts
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        // Abruf der Datenquelle
        dao = ctx.getBean(IElectionsDao.class);
        // Inhalt der beiden Tabellen
        ElectionsConfig electionsConfig = dao.getElectionsConfig();
        ListeElectorale[] listes = dao.getListesElectorales();
        // Anzeige
        System.out.println(String.format("Nombre de sièges à pourvoir : %d", electionsConfig.getNbSiegesAPourvoir()));
        System.out.println(String.format("Seuil électoral : %5.2f", electionsConfig.getSeuilElectoral()));
        System.out.println("Listes candidates----------------");
        for (ListeElectorale liste : listes) {
            System.out.println(liste);
        }
        // Schließen des Spring-Kontexts
        ctx.close();
    }

}

Die Klasse [Test01] ist ein Test der Klasse JUnit:


package dao.tests;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import dao.config.AppConfig;
import dao.entities.ElectionsConfig;
import dao.entities.ListeElectorale;
import dao.service.IElectionsDao;

@SpringApplicationConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Test01 {

    // Schicht [DAO]
    @Autowired
    private IElectionsDao electionsDao;

    @Before
    public void init() {
        // Die Tabelle wird bereinigt [LISTES]
        // Wahllisten
        ListeElectorale[] listes = electionsDao.getListesElectorales();
        // Stimmen und Sitze werden auf 0 gesetzt und „false“ entfernt
        int voix = 0;
        int sièges = 0;
        boolean elimine = false;
        for (ListeElectorale liste : listes) {
            liste.setVoix(voix);
            liste.setSieges(sièges);
            liste.setElimine(elimine);
        }
        // Diese Daten werden mithilfe der Schicht dauerhaft gespeichert [dao]
        electionsDao.setListesElectorales(listes);
    }

    @Test
    public void testElections01() {
        System.out.println("testElections01-------------------------------------");
        // Abruf der Wahlkonfiguration
        ElectionsConfig electionsConfig = electionsDao.getElectionsConfig();
        int nbSiegesAPourvoir = electionsConfig.getNbSiegesAPourvoir();
        double seuilElectoral = electionsConfig.getSeuilElectoral();
        Assert.assertEquals(6, nbSiegesAPourvoir);
        Assert.assertEquals(0.05, seuilElectoral, 1E-6);

        // Wahllisten
        ListeElectorale[] listes = electionsDao.getListesElectorales();
        // Anzeige der ausgelesenen Werte
        System.out.println("Nombre de sièges à pourvoir : " + nbSiegesAPourvoir);
        System.out.println("Seuil électoral : " + seuilElectoral);
        System.out.println("Listes en compétition ---------------------");
        for (int i = 0; i < listes.length; i++) {
            System.out.println(listes[i]);
        }

        // Stimmen und Sitze werden den Listen zugewiesen
        int voix = 0;
        int sièges = 0;
        boolean elimine = false;
        for (ListeElectorale liste : listes) {
            liste.setVoix(voix);
            liste.setSieges(sièges);
            liste.setElimine(elimine);
            voix += 10;
            sièges += 1;
            elimine = !elimine;
        }

        // Diese Daten werden mithilfe der Schicht [dao] dauerhaft gespeichert
        electionsDao.setListesElectorales(listes);

        // Die Daten werden erneut ausgelesen
        ListeElectorale[] listesElectorales2 = electionsDao.getListesElectorales();
        // Die gelesenen Daten werden überprüft
        Assert.assertEquals(7, listesElectorales2.length);
        voix = 0;
        sièges = 0;
        elimine = false;
        for (ListeElectorale liste : listes) {
            Assert.assertEquals(voix, liste.getVoix());
            Assert.assertEquals(sièges, liste.getSieges());
            Assert.assertEquals(elimine, liste.isElimine());
            voix += 10;
            sièges += 1;
            elimine = !elimine;
        }
        System.out.println("Listes en compétition ---------------------");
        for (int i = 0; i < listes.length; i++) {
            System.out.println(listes[i]);
        }
    }
}

Aufgabe: Führen Sie die Tests [console] und [JUnit] auf Ihrer Schicht [DAO] durch.


12.9. Erstellung des Maven-Archivs des Projekts

Erstellen Sie das Maven-Archiv des Projekts gemäß dem Beispiel in Abschnitt 11.3.12.