8. [TD]: De laag [metier]
Trefwoorden: meerlaagse architectuur, Spring, afhankelijkheidsinjectie.
![]() |
8.1. Support
![]() | ![]() |
De map [support / chap-08] bevat het Eclipse-project van dit hoofdstuk.
8.2. Maven-configuratie
![]() |
Het project [elections-metier-dao-jdbc] zal voortbouwen op het project [elections-dao-jdbc-01]. We gaan de jar van dit laatste project in de lokale Maven-repository installeren:
![]() |
Zodra dit is gebeurd, ziet de Maven-configuratie van het Eclipse-project [elections-metier-dao-jdbc] er als volgt uit:
![]() |
<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>
<!-- voor het installeren van het projectartefact in de lokale Maven-repository -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- regels 21-25: de afhankelijkheid van de JAR van het project [elections-jdbc-01]. We nemen deze regels rechtstreeks over uit het bestand [pom.xml] van het project dat we willen importeren:
<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>
...
- regels 26-37: de afhankelijkheden die nodig zijn voor de tests. Hoewel deze aanwezig zijn in het bestand [pom.xml] van het project [elections-jdbc-01], moeten we ze opnieuw toevoegen omdat ze door hun attribuut [<scope>test</scope>] niet zijn opgenomen in de jar die in de lokale Maven-repository is geplaatst;
8.3. Spring-configuratie
![]() |
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 {
}
- regel 7: we importeren alle beans die zijn gedefinieerd in de laag [DAO];
- regel 8: de cache wordt geactiveerd. De bean [CacheManager] wordt niet opnieuw gedefinieerd, omdat deze al is gedefinieerd in de laag [DAO];
- regel 9: de laag [métier] definieert nieuwe beans in het pakket [elections.metier.service];
8.4. De interface [IElectionsMetier]
![]() |
De laag [metier] zal de in paragraaf 4.2 beschreven interface hebben. We herhalen deze hier:
public interface IElectionsMetier {
public ListeElectorale[] getListesElectorales();
public int getNbSiegesAPourvoir();
public double getSeuilElectoral();
public void recordResultats(ListeElectorale[] listesElectorales);
public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales);
}
8.5. De implementatieklasse [ElectionsMetier]
![]() |
Deze klasse implementeert de interface [IElectionsMetier]. De voorgestelde implementatie zal de volgende structuur hebben:
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 {
// het toegangspunt tot de laag [dao], geïnstantieerd door [Spring]
@SuppressWarnings("unused")
@Autowired
private IElectionsDao electionsDao;
// berekening van het aantal behaalde zetels
@Override
public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales) {
throw new RuntimeException("[calculerSieges] not yet implemented");
}
// concurrerende lijsten
@Override
public ListeElectorale[] getListesElectorales() {
throw new RuntimeException("[getListesElectorales] not yet implemented");
}
// opslag van de resultaten
@Override
public void recordResultats(ListeElectorale[] listesElectorales) {
throw new RuntimeException("[recordResultats] not yet implemented");
}
// aantal te verdelen zetels
@Override
public int getNbSiegesAPourvoir() {
throw new RuntimeException("[getNbSiegesAPourvoir] not yet implemented");
}
// kiesdrempel
@Override
public double getSeuilElectoral() {
throw new RuntimeException("[getSeuilElectoral] not yet implemented");
}
}
- regel 10: de klasse [ElectionsMetier] is een Spring-component;
- regel 11: de klasse [ElectionsMetier] implementeert de interface [IElectionsMetier];
- regels 15-16: Spring-injectie van een verwijzing naar de laag [DAO];
- regels 37 en 44: het aantal te vervullen zetels en de kiesdrempel worden in de cache opgeslagen;
Te doen: schrijf de klasse [ElectionsMetier]. Gebruik daarbij de commentaren waar die aanwezig zijn. Probeer geen uitzonderingen van het type [ElectionsException] die vanuit de laag [DAO] worden doorgegeven, op te vangen (try / catch). We laten ze doorgaan naar de laag [UI]. Omdat de klasse [ElectionsException] een ongecontroleerd uitzonderingstype is, is het niet verplicht om deze af te vangen met een (try / catch).
8.6. De testklasse
![]() |
De testklasse JUnit krijgt de volgende vorm:
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 {
// laag [métier]
@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() {
// de tabel met de 7 kandidatenlijsten (naam, stemmen) wordt aangemaakt
// we berekenen het aantal zetels voor elke lijst
// de resultaten worden gecontroleerd (zetels, stemmen, afgevallen lijsten)
// tijdelijk
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() {
// de tabel met de 7 kandidatenlijsten wordt uit de database opgehaald
// de stemmen worden vastgelegd
// de door elke lijst behaalde zetels worden berekend
// de resultaten worden gecontroleerd (zetels, stemmen, afvallers)
// tijdelijk
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)
// een test schrijven die een uitzondering van het type [ElectionsException] veroorzaakt
public void calculSieges3() {
// er wordt een array aangemaakt met 25 kandidatenlijsten met elk 1 stem
// de 25 lijsten krijgen hetzelfde aantal stemmen (4%)
// berekening van de zetels – normaal gesproken zou er een ElectionsException moeten zijn
// met een kiesdrempel van 5%
// tijdelijk
throw new RuntimeException("[calculSieges3] not yet implemented");
}
/**
* enregistrement des résultats de l'élection
*/
@Test
public void ecritureResultatsElections() {
// we maken de tabel met de 7 kandidatenlijsten
// de stemmen worden vastgelegd
// de behaalde zetels per lijst worden berekend
// de resultaten worden in de database opgeslagen
// de lijsten in de database worden opnieuw gelezen
// de resultaten worden gecontroleerd (zetels, stemmen, uitgesloten kandidaten)
// tijdelijk
throw new RuntimeException("[ecritureResultatsElections] not yet implemented");
}
}
Te doen: schrijf de vier testmethoden met behulp van de commentaren. Houd er rekening mee dat wanneer deze methoden worden uitgevoerd, het veld [electionsMetier] op regel 19 al is geïnitialiseerd. Controleer of de test JUnit slaagt.
8.7. Het archief van de laag [metier] aanmaken
Net zoals bij de laag [DAO] plaatsen we het archief van het project [elections-metier-dao-jdbc] in de lokale Maven-repository:
![]() |
Opmerking: deze handeling kan mislukken als uw Eclipse-project is gekoppeld aan een JRE (Java Runtime Environment) in plaats van een JDK (Java Development Kit). Om dit te controleren, volgt u de stappen in paragraaf 3.1. Als u ontdekt dat u een JRE hebt in plaats van een JDK, koppel uw project dan aan een JDK zoals beschreven in deze paragraaf.
8.8. Conclusion
Laten we nog eens de algemene architectuur van de applicatie [Elections] bekijken die we momenteel aan het bouwen zijn:
![]() |
We hebben de lagen [metier] en [dao] gebouwd. We gaan nu de laag [ui] bouwen. We zullen twee implementaties voor deze laag voorstellen:
- een "console"-implementatie
- een implementatie met grafische interface











