8. [TD]: Die [Business]-Schicht
Stichworte: mehrschichtige Architektur, Spring, Dependency Injection.
![]() |
8.1. Support
![]() | ![]() |
Der Ordner [support / chap-08] enthält das Eclipse-Projekt für dieses Kapitel.
8.2. Maven-Konfiguration
![]() |
Das Projekt [elections-metier-dao-jdbc] basiert auf dem Projekt [elections-dao-jdbc-01]. Wir werden die JAR-Datei aus dem letztgenannten Projekt in das lokale Maven-Repository installieren:
![]() |
Sobald dies erledigt ist, sieht die Maven-Konfiguration für das Eclipse-Projekt [elections-metier-dao-jdbc] wie folgt aus:
![]() |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st.elections</groupId>
<artifactId>elections-metier-dao-jdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.7.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- DAO -->
<dependency>
<groupId>istia.st.elections</groupId>
<artifactId>elections-dao-jdbc-01</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- plugins -->
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>config.AppConfig</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<!-- to install the project artifact in the local Maven repository -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- Zeilen 21–25: die Abhängigkeit von der JAR-Datei des Projekts [elections-jdbc-01]. Kopieren Sie diese Zeilen direkt in die Datei [pom.xml] des Projekts, das Sie importieren möchten:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st.elections</groupId>
<artifactId>elections-dao-jdbc-01</artifactId>
<version>0.0.1-SNAPSHOT</version>
...
- Zeilen 26–37: die für das Testen erforderlichen Abhängigkeiten. Obwohl sie in der [pom.xml]-Datei des [elections-jdbc-01]-Projekts vorhanden sind, müssen wir sie hier einfügen, da sie aufgrund ihres Attributs [<scope>test</scope>] nicht in die JAR-Datei aufgenommen wurden, die im lokalen Maven-Repository abgelegt wurde;
8.3. Spring-Konfiguration
![]() |
package elections.metier.config;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
@Import({ elections.dao.config.AppConfig.class })
@EnableCaching
@ComponentScan(basePackages = { "elections.metier.service" })
public class MetierConfig {
}
- Zeile 7: Wir importieren alle in der [DAO]-Schicht definierten Beans;
- Zeile 8: Wir aktivieren den Cache. Wir definieren die [CacheManager]-Bean nicht neu, da sie bereits in der [DAO]-Schicht definiert ist;
- Zeile 9: Die [business]-Schicht definiert neue Beans im Paket [elections.business.service];
8.4. Die Schnittstelle [ IElectionsMetier]
![]() |
Die [Geschäfts-]Schicht verfügt über die in Abschnitt 4.2 vorgestellte Schnittstelle. Hier zur Erinnerung:
public interface IElectionsMetier {
public ListeElectorale[] getListesElectorales();
public int getNbSiegesAPourvoir();
public double getSeuilElectoral();
public void recordResultats(ListeElectorale[] listesElectorales);
public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales);
}
8.5. Die Implementierungsklasse [ ElectionsMetier]
![]() |
Diese Klasse implementiert die Schnittstelle [IElectionsMetier]. Die vorgeschlagene Implementierung wird folgende Struktur aufweisen:
package elections.metier.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import elections.dao.entities.ListeElectorale;
import elections.dao.service.IElectionsDao;
@Component
public class ElectionsMetier implements IElectionsMetier {
// the access point to the [dao] layer instantiated by [Spring]
@SuppressWarnings("unused")
@Autowired
private IElectionsDao electionsDao;
// calculation of seats obtained
@Override
public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales) {
throw new RuntimeException("[calculerSieges] not yet implemented");
}
// competing lists
@Override
public ListeElectorale[] getListesElectorales() {
throw new RuntimeException("[getListesElectorales] not yet implemented");
}
// saving results
@Override
public void recordResultats(ListeElectorale[] listesElectorales) {
throw new RuntimeException("[recordResultats] not yet implemented");
}
// number of seats to be filled
@Override
public int getNbSiegesAPourvoir() {
throw new RuntimeException("[getNbSiegesAPourvoir] not yet implemented");
}
// electoral threshold
@Override
public double getSeuilElectoral() {
throw new RuntimeException("[getSeuilElectoral] not yet implemented");
}
}
- Zeile 10: Die Klasse [ElectionsMetier] ist eine Spring-Komponente;
- Zeile 11: Die Klasse [ElectionsMetier] implementiert die Schnittstelle [IElectionsMetier];
- Zeilen 15–16: Spring-Injektion einer Referenz auf die [DAO]-Schicht;
- Zeilen 37 und 44: Die Anzahl der zu besetzenden Sitze und die Wahlhürde werden zwischengespeichert;
Aufgabe: Schreiben Sie die Klasse [ElectionsMetier]. Nutzen Sie die vorhandenen Kommentare. Wir werden nicht versuchen, [ElectionsException]-Ausnahmen abzufangen (try/catch), die von der [DAO]-Schicht weitergeleitet werden. Wir lassen sie bis zur [UI]-Schicht weiterlaufen. Da die Klasse [ElectionsException] ein nicht überprüfter Ausnahmetyp ist, besteht keine Notwendigkeit, sie mit einem try/catch-Block zu behandeln.
8.6. Die Testklasse
![]() |
Die JUnit-Testklasse hat folgende Form:
package tests;
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.ElectionsException;
import metier.service.IElectionsMetier;
@SpringApplicationConfiguration(classes = MetierConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Test01 {
// business] layer
@Autowired
static private IElectionsMetier electionsMetier;
/**
* vérification 1 : méthode de calcul des sièges on fixe en dur les listes
*/
@Test
public void calculSieges1() {
// create a table of the 7 candidate lists (name, vote)
// the seats for each list are calculated
// we check the results (seats, votes, eliminates)
// temporary
throw new RuntimeException("[calculSieges1] not yet implemented");
}
/**
* vérification 2 : méthode de calcul des sièges on demande les listes à la
* couche [metier] puis on fixe en dur les voix
*/
@Test
public void calculSieges2() {
// the table of 7 candidate lists is retrieved as a base
// the voices are hard-fixed
// the seats obtained by each list are calculated
// we check the results (seats, votes, eliminates)
// temporary
throw new RuntimeException("[calculSieges2] not yet implemented");
}
/**
* vérification 3 méthode de calcul des sièges on provoque une exception
*/
@Test(expected = ElectionsException.class)
// write a test that causes an exception of type [ElectionsException]
public void calculSieges3() {
// create a table of 25 candidate lists, each with 1 vote
// all 25 lists will have the same number of votes (4%)
// calculation of seats - normally there should be a ElectionsException
// with an electoral threshold of 5%
// temporary
throw new RuntimeException("[calculSieges3] not yet implemented");
}
/**
* enregistrement des résultats de l'élection
*/
@Test
public void ecritureResultatsElections() {
// create the table of 7 candidate lists
// the voices are hard-fixed
// the seats obtained by each list are calculated
// results are entered into the database
// reread lists in base
// we check the results (seats, votes, eliminates)
// temporary
throw new RuntimeException("[ecritureResultatsElections] not yet implemented");
}
}
Aufgabe: Schreiben Sie die vier Testmethoden anhand der Kommentare als Leitfaden. Beachten Sie, dass bei Ausführung dieser Methoden das Feld [electionsMetier] in Zeile 19 bereits initialisiert ist. Überprüfen Sie, ob der JUnit-Test erfolgreich ist.
8.7. Erstellen des [business]-Layer-Archivs
Wie bereits bei der [DAO]-Schicht legen wir das Projektarchiv [elections-metier-dao-jdbc] im lokalen Maven-Repository ab:
![]() |
Hinweis: Dieser Vorgang schlägt möglicherweise fehl, wenn Ihr Eclipse-Projekt mit einer JRE (Java Runtime Environment) statt mit einem JDK (Java Development Kit) verknüpft ist. Befolgen Sie zur Überprüfung die Anweisungen in Abschnitt 3.1. Wenn Sie feststellen, dass Sie eine JRE und kein JDK verwenden, verknüpfen Sie Ihr Projekt wie in diesem Abschnitt beschrieben mit einem JDK.
8.8. Fazit
Lassen Sie uns die allgemeine Architektur der [Elections]-Anwendung, die wir erstellen, noch einmal betrachten:
![]() |
Wir haben die [Business]- und die [DAO]-Schicht erstellt. Nun werden wir die [UI]-Schicht erstellen. Wir schlagen zwei Implementierungen für diese Schicht vor:
- eine „Konsolen“-Implementierung
- eine grafische Benutzeroberfläche











