8. [TD]: A camada [metier]
Palavras-chave: arquitetura multicamadas, Spring, injeção de dependências.
![]() |
8.1. Support
![]() | ![]() |
A pasta [support / chap-08] contém o projeto Eclipse deste capítulo.
8.2. Configuração do Maven
![]() |
O projeto [elections-metier-dao-jdbc] irá basear-se no projeto [elections-dao-jdbc-01]. Vamos instalar o ficheiro JAR deste último projeto no repositório Maven local:
![]() |
Feito isto, a configuração do Maven para o projeto Eclipse [elections-metier-dao-jdbc] é a seguinte:
![]() |
<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>
<!-- para a instalação do artefacto do projeto no repositório local do Maven -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- linhas 21-25: a dependência do ficheiro JAR do projeto [elections-jdbc-01]. Retiramos estas linhas diretamente do ficheiro [pom.xml] do projeto que pretendemos importar:
<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>
...
- linhas 26-37: as dependências necessárias para os testes. Embora estejam presentes no ficheiro [pom.xml] do projeto [elections-jdbc-01], somos obrigados a reintroduzi-las, pois o seu atributo [<scope>test</scope>] faz com que não tenham sido incluídas no ficheiro JAR colocado no repositório Maven local;
8.3. Configuração do Spring
![]() |
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 {
}
- linha 7: importam-se todos os beans definidos na camada [DAO];
- linha 8: ativa-se o cache. Não se redefine o bean [CacheManager], uma vez que já está definido na camada [DAO];
- linha 9: a camada [métier] define novos beans no pacote [elections.metier.service];
8.4. A interface [IElectionsMetier]
![]() |
A camada [metier] terá a interface apresentada no parágrafo 4.2. Recordamos a mesma:
public interface IElectionsMetier {
public ListeElectorale[] getListesElectorales();
public int getNbSiegesAPourvoir();
public double getSeuilElectoral();
public void recordResultats(ListeElectorale[] listesElectorales);
public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales);
}
8.5. A classe de implementação [ElectionsMetier]
![]() |
Esta classe implementa a interface [IElectionsMetier]. A implementação proposta terá a seguinte estrutura:
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 {
// o ponto de acesso à camada [dao] instanciada por [Spring]
@SuppressWarnings("unused")
@Autowired
private IElectionsDao electionsDao;
// cálculo dos lugares obtidos
@Override
public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales) {
throw new RuntimeException("[calculerSieges] not yet implemented");
}
// listas concorrentes
@Override
public ListeElectorale[] getListesElectorales() {
throw new RuntimeException("[getListesElectorales] not yet implemented");
}
// gravação dos resultados
@Override
public void recordResultats(ListeElectorale[] listesElectorales) {
throw new RuntimeException("[recordResultats] not yet implemented");
}
// número de lugares a preencher
@Override
public int getNbSiegesAPourvoir() {
throw new RuntimeException("[getNbSiegesAPourvoir] not yet implemented");
}
// limiar eleitoral
@Override
public double getSeuilElectoral() {
throw new RuntimeException("[getSeuilElectoral] not yet implemented");
}
}
- linha 10: a classe [ElectionsMetier] é um componente Spring;
- linha 11: a classe [ElectionsMetier] implementa a interface [IElectionsMetier];
- linhas 15-16: injeção Spring de uma referência na camada [DAO];
- linhas 37 e 44: o número de lugares a preencher e o limiar eleitoral estão ocultos;
Tarefa a realizar: escreva a classe [ElectionsMetier]. Recorra aos comentários, sempre que existam. Não tente interceptar (try / catch) as exceções do tipo [ElectionsException] que são propagadas a partir da camada [DAO]. Deixá-las-emos subir até à camada [UI]. Como a classe [ElectionsException] é um tipo de exceção não controlada, não há obrigação de a gerir através de um (try / catch).
8.6. A classe de teste
![]() |
A classe de teste JUnit terá a seguinte forma:
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 {
// camada [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() {
// cria-se a tabela das 7 listas de candidatos (nome, votos)
// calculam-se os lugares de cada uma das listas
// verificam-se os resultados (lugares, votos, eliminações)
// temporário
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() {
// recupera-se na base de dados a tabela das 7 listas de candidatos
// fixam-se os votos
// calculam-se os assentos obtidos por cada uma das listas
// verifica-se os resultados (lugares, votos, elimina-se)
// temporário
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)
// escrever um teste que provoque uma exceção do tipo [ElectionsException]
public void calculSieges3() {
// cria-se uma tabela com 25 listas de candidatos, cada uma com 1 voto
// as 25 listas terão o mesmo número de votos (4%)
// cálculo dos lugares — normalmente, deve-se obter um ElectionsException
// com um limiar eleitoral de 5%
// provisório
throw new RuntimeException("[calculSieges3] not yet implemented");
}
/**
* enregistrement des résultats de l'élection
*/
@Test
public void ecritureResultatsElections() {
// cria-se a tabela das 7 listas de candidatos
// definem-se os votos de forma fixa
// calculam-se os lugares obtidos por cada uma das listas
// os resultados são registados na base de dados
// revisam-se as listas na base de dados
// verifica-se os resultados (lugares, votos, elimina-se)
// temporário
throw new RuntimeException("[ecritureResultatsElections] not yet implemented");
}
}
Tarefa a realizar: escreva os quatro métodos de teste com a ajuda dos comentários. Recorde-se que, quando estes métodos forem executados, o campo [electionsMetier] da linha 19 já terá sido inicializado. Verifique se o teste JUnit é bem-sucedido.
8.7. Criação do arquivo da camada [metier]
Tal como foi feito para a camada [DAO], colocamos o arquivo do projeto [elections-metier-dao-jdbc] no repositório Maven local:
![]() |
Nota: esta operação pode falhar se o seu projeto Eclipse estiver associado a um JRE (Java Runtime Environment) em vez de um JDK (Java Development Kit). Para verificar isso, siga as instruções do parágrafo 3.1. Se verificar que tem um JRE em vez de um JDK, associe o seu projeto a um JDK, conforme indicado neste parágrafo.
8.8. Conclusion
Recorde-se a arquitetura geral da aplicação [Elections] que estamos a construir:
![]() |
Já construímos as camadas [metier] e [dao]. Vamos agora construir a camada [ui]. Iremos propor duas implementações para esta camada:
- uma implementação «de consola»
- uma implementação com interface gráfica











