Deuxième étape : Côté Serveur, un projet Maven multi-modules

1. Introduction

Dans cette section, vous découvrirez l’architecture du back-end utilisée dans le projet.

1.1. Principe général

Le back-end repose sur une architecture API REST. Cette architecture permet une communication structurée entre le front-end et le back-end. Lorsque l’utilisateur interagit avec une fonctionnalité du site nécessitant un traitement côté serveur, une requête HTTP est envoyée vers une route spécifique, associée à un Contrôleur.

1.2. Les "Contrôleurs"

Un Contrôleur agit comme un point d’entrée dans le back-end. Il est responsable de la réception de la requête et la transmettre au composant métier. Il ne doit contenir aucune logique métier.

Un contrôleur ne doit contenir aucun traitement métier. Son seul rôle est de déléguer le travail aux Services appropriés.

1.3. Les "Services"

Les services contiennent l’ensemble de la logique métier. Ils sont responsables de l’exécution des opérations demandées, comme l’accès aux données, la validation, ou la coordination entre plusieurs composants.

L’objectif de cette séparation est d’assurer une conception modulaire, testable et maintenable.

1.4. Principe de responsabilité unique

Chaque composant du back-end doit respecter le principe de Responsabilité Unique (Single Responsibility Principle). Cela signifie qu’un module (par exemple un service ou un contrôleur) doit avoir une seule responsabilité claire.

Le respect de ce principe améliore la lisibilité du code, facilite la maintenance, et limite les effets de bord.

2. Structure du projet

Voici la structure attendue de la partie back-end de votre projet. Il s’agit d’un projet Maven multi-modules.

📁 quizmaker-backend/
 ├── 📁 quizmaker-api/
 ├── 📁 quizmaker-domain/
 └── 📁 quizmaker-spring/

3. Création du projet parent

Pour commencer, nous allons créer et configurer le projet parent :

  1. Tour d’abord, assurez vous que vous êtes bien dans le répertoire quizmaker et donc, à l’extérieur du répertoire quizmaker-backend

  2. Utilisez ensuite l’archétype pom-root pour créer la projet parent :

     mvn archetype:generate \
    -DarchetypeGroupId=org.codehaus.mojo.archetypes \
    -DarchetypeArtifactId=pom-root \
    -DarchetypeVersion=RELEASE \
    -DgroupId=fr.nantes.universite \
    -DartifactId=quizmaker-backend \
    -Dversion=1.0-SNAPSHOT \
    -DinteractiveMode=false

4. Création des sous-modules

Entrez ensuite dans le répertoire du projet parent. Vous allez ensuite y créer les sous-modules du projet.

Nous allons diviser le projet serveur en trois sous-modules différents :

  • quizmaker-api : contient les interfaces communes à tous les sous-modules

  • quizmaker-domain : contient les classes métier de l’application

  • quizmaker-spring : contient les classes qui mettent en œuvre le serveur Websocket de l’application.

  1. Utilisez l’archétype Maven quickstart pour créer les sous-modules. Vous devrez exécuter cette commande trois fois de suite.

    cd quizmaker-backend
    mvn archetype:generate -DgroupId=fr.nantes.universite -DartifactId=quizmaker-api \
        -Dversion=1.0-SNAPSHOT \
        -DpackageName=fr.nantes.universite.quizmaker.common \
        -DarchetypeGroupId=org.apache.maven.archetypes \
        -DarchetypeArtifactId=maven-archetype-quickstart \
        -DarchetypeVersion=RELEASE \
        -DinteractiveMode=false
    
    mvn archetype:generate -DgroupId=fr.nantes.universite -DartifactId=quizmaker-domain \
        -Dversion=1.0-SNAPSHOT \
        -DpackageName=fr.nantes.universite.quizmaker.domain \
        -DarchetypeGroupId=org.apache.maven.archetypes \
        -DarchetypeArtifactId=maven-archetype-quickstart \
        -DarchetypeVersion=RELEASE \
        -DinteractiveMode=false
    
    mvn archetype:generate -DgroupId=fr.nantes.universite -DartifactId=quizmaker-spring \
        -Dversion=1.0-SNAPSHOT \
        -DpackageName=fr.nantes.universite.quizmaker.spring \
        -DarchetypeGroupId=org.apache.maven.archetypes \
        -DarchetypeArtifactId=maven-archetype-quickstart \
        -DarchetypeVersion=RELEASE \
        -DinteractiveMode=false

5. Vérification de la structure du projet

Après la création des quatre sous-modules, la structure de votre projet doit ressembler à la structure suivante :

📂 quizmaker-backend
├── 📄 pom.xml (1)
├── 📂 quizmaker-api (2)
|   └── 📄 pom.xml
├── 📂 quizmaker-domain (3)
|   └── 📄 pom.xml
├── 📂 quizmaker-spring (4)
|   └── 📄 pom.xml
1 Le fichier POM parent, contenant les propriétés communes des sous-modules.
2 Un module API, contenant les interfaces et classes abstraites, qui seront utilisées par les autres modules.
3 Un module Domain, contenant le ou les composants métier (un module peut contenir des sous-modules).
4 Un module Spring, responsable de la communication entre les clients utilisant le protocole websockets et le composant métier.
Utilisez Maven pour vérifier que votre projet est correctement configuré.
  1. Exécutez la commande suivante :

    mvn validate

La sortie de la commande doit montrer que la production a réussit, comme sur le listing suivant :

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for quizmaker-backend 1.0-SNAPSHOT:
[INFO]
[INFO] quizmaker-backend .................................. SUCCESS [  0.000 s]
[INFO] quizmaker-api ...................................... SUCCESS [  0.000 s]
[INFO] quizmaker-domain ................................... SUCCESS [  0.000 s]
[INFO] quizmaker-spring ................................... SUCCESS [  0.000 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.063 s
[INFO] Finished at: 2025-11-12T13:52:51+01:00
[INFO] ------------------------------------------------------------------------

6. Configuration de JUnit

Dans certains cas, en fonction de l’archetype utilisé par Maven, la génération automatisée configure par défaut une dépendance vers JUnit 4, alors que nous souhaitons utiliser JUnit 5. Si c’est votre cas, vous devez effectuer les changements demandés dans cette section.
Configuration du module parent
  1. Éditez le fichier pom.xml du projet parent et vérifiez que la dépenfance déclarée est bien la suivante{nbs)}:

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.junit</groupId>
                <artifactId>junit-bom</artifactId>
                <version>5.13.4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
Les dépendances déclarées à l’intérieur de la balise <dependencyManagement> ne sont pas vraiment ajoutés au projet, elles permettent juste d’assurer que les projets enfants utiliseront la même version : celle configurée dans le projet parent.
Configuration des sous-modules
  1. Éditez manuellement le pom.xml de chaque sous-module et vérifiez que la dépendance déclarée est bien la suivante :

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <scope>test</scope>
</dependency>
  1. Si Maven a ajouté une balise appelée <dependencyManagement> aux sous-modules, déplacez son contenu vers le module parent. En principe, les fichiers pom.xml des sous-modules ne doivent pas contenir cette balise.

Correction des classes de test des imports JUnit
  1. Dans chacun de vos modules, ouvrez les fichiers à l’intérieur du dossier src/test/java/, puis remplacez le code :

import static org.junit.Assert.assertTrue;
import org.junit.Test;

par :

import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;

7. Dépendance entre modules

Le projet QuizMaker suit une règle simple :

il n’y a pas de cycle de dépendances entre les modules.

Toutes les modifications que vous allez réaliser ne pourront pas violer cette règles. Elle doit être respecté, impérativement.

Dépendance entre modules
package server {
    package API {}
    package Domain { }
    package "Spring" as sockets { }

    Domain ..> API
    sockets ..> API
    sockets ..> Domain
}
  • Ajoutez d’une dépendance au module API dans le module Domain.

Fichier quizmaker-domain/pom.xml
<project>
    <!-- (...) -->
    <dependencies>
        <!-- (Other dependencies) -->
        <dependency>
            <groupId>fr.nantes.universite</groupId>
            <artifactId>quizmaker-api</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>
Assurez-vous de bien utiliser la propriété project.version comme version de la dépendance. Cela permet de dire à Maven d’utiliser le module API en développement et ne pas le chercher sur le référentiel.
  • Ajout de dépendances aux modules API et Domain dans le module Spring.

Fichier quizmaker-spring/pom.xml
<project>
    <!-- (...) -->
    <dependencies>
        <!-- (Other dependencies) -->
        <dependency>
            <groupId>fr.nantes.universite</groupId>
            <artifactId>quizmaker-api</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>fr.nantes.universite</groupId>
            <artifactId>quizmaker-domain</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>

8. Validation des changements

Pour éviter d’ajouter accidentellement des fichiers indésirables ou inutiles sur git, nous allons ajouter une fichier .gitignore à votre projet.

  1. Créez un fichier appelé .gitignore à la racine de votre projet.

  2. Ajoutez à ce fichier les fichiers et/ou patterns que vous souhaites ignorer.

    • Si vous ne savez pas exactement ce que vous devez ajouter à ce fichier, copiez le contenu de ce fichier :

wget -O .gitignore https://gitlab.univ-nantes.fr/naomod/defaults/-/raw/main/ignore-files/maven-java-ignore

Validons maintenant vos changements.

  1. Exécutez les commandes suivantes pour valider vos changements :

git stage .
git commit -m "QuizMaker Server: initial commit"
git push

9. Configuration du module Parent

Configurez la version du JDK, ainsi que l’encodage des fichiers source dans le projet parent. Ces propriétés seront "héritées" par les sous-modules.

  1. Ajoutez les propriétés suivantes au fichier pom.xml du projet parent :

<properties>
    <maven.compiler.release>17</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>3.3.2</spring-boot.version>
</properties>
  1. Ajoutez également la dépendance suivante à la partie gestion de dépendances :

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

Cette dépendance assure que les autres dépendances demandées par Spring Boot aient des versions compatibles.

10. Configuration du module Spring

Le module quizmaker-spring dépend de différents artefacts et utilise des plugins

  1. Commencez par définir les propriétés suivantes :

    <properties>
        <openapi.generator.version>7.3.0</openapi.generator.version>
        <openapi.output.dir>${project.build.directory}/generated-sources</openapi.output.dir>
    </properties>
  1. Ajoutez les dépendances suivantes au fichier pom.xml du module quizmaker-spring :

    <dependencies>
        <dependency>
            <groupId>fr.universite.nantes</groupId>
            <artifactId>quizmaker-api</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>fr.universite.nantes</groupId>
            <artifactId>quizmaker-domain</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- Spring -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <!-- DB drivers -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- Swagger UI -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.5.0</version>
        </dependency>

        <!-- ⚠️ Fix: JsonNullable utilisé par le code généré -->
        <dependency>
            <groupId>org.openapitools</groupId>
            <artifactId>jackson-databind-nullable</artifactId>
            <version>0.2.6</version>
        </dependency>

        <!-- Tests -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
        </dependency>
    </dependencies>
  1. Ajoutez ensuite les plugins suivants à ce même fichier pom.xml :

    <build>
        <plugins>
            <!-- OpenAPI Generator -->
            <plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <version>${openapi.generator.version}</version>
                <executions>
                    <execution>
                        <id>generate-openapi-spring</id>
                        <phase>generate-sources</phase>
                        <goals><goal>generate</goal></goals>
                        <configuration>
                            <inputSpec>${project.basedir}/src/main/resources/openapi/openapi.yaml</inputSpec>
                            <generatorName>spring</generatorName>
                            <apiPackage>fr.universite.nantes.quizmaker.api</apiPackage>
                            <modelPackage>fr.universite.nantes.quizmaker.api.model</modelPackage>
                            <outputDir>${openapi.output.dir}</outputDir>
                            <configOptions>
                                <interfaceOnly>true</interfaceOnly>
                                <useTags>true</useTags>
                                <useSpringBoot3>true</useSpringBoot3>
                                <useJakartaEe>true</useJakartaEe>
                                <dateLibrary>java8</dateLibrary>
                                <performBeanValidation>true</performBeanValidation>
                            </configOptions>
                            <skipValidateSpec>false</skipValidateSpec>
                            <generateAliasAsModel>true</generateAliasAsModel>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- Ajouter le bon répertoire des sources générées -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>3.5.0</version>
                <executions>
                    <execution>
                        <id>add-openapi-sources</id>
                        <phase>generate-sources</phase>
                        <goals><goal>add-source</goal></goals>
                        <configuration>
                            <!-- NOTE: le générateur crée '.../generated-sources/openapi/src/main/java' -->
                            <sources>
                                <source>${openapi.output.dir}/openapi/src/main/java</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- Spring Boot -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>

        </plugins>
    </build>

11. Conclusion

Vérifiez que la configuration du projet est toujours correcte.

mvn validate
git stage .
git commit -m "QuizMaker Server: configuration des modules"
git push