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.












