:: Enseignements :: ESIPE :: E4INFO :: 2023-2024 :: Java Avancé ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) |
Projet du premier semestre INFO2 - 2023
|
Exercice 1 - WebCell
Le but du projet
Web est d'écrire un tableur sous forme d'application Web.
Contrairement à un tableur classique, un tableau dans l'application devra avoir un titre pour chaque colonne,
et le type des valeurs d'une colonne sera toujours le même.
L'application
Web est composée d'un
back-end écrit en Java offrant
différents services REST permettant de créer, modifier et visualiser des tableaux de données.
L’application doit permettre...
-
De créer un nouveau tableau à partir d'un fichier au format CSV.
À partir de ce fichier, il faudra en déduire le nombre de colonnes, le titre de chaque colonne,
le type de valeurs de chaque colonne puis le nombre de lignes et les valeurs de chaque ligne.
Les valeurs peuvent être de 3 types différents
- Un nombre : une suite de chiffre (2,5 milliards au maximum) et optionnellement un point ;
- Une formule : une chaîne de caractères qui commence par "=", qui contient des opérations +, -, *, /, % et
COUNT, SUM, AVERAGE,
les parenthèses, et des références sur une cellule (par exemple, A4) ou un intervalle de cellules
(par exemple, D3:D11) qui représente les valeurs entre les cases D3 et D11 ;
- Une chaîne de caractères.
La détermination du type d'une colonne est faite de la façon suivante, si la colonne ne contient que des nombres,
le type est "nombre", si la colonne ne contient que des formules, le type est "formule", sinon le type est
"chaîne de caractères".
En terme de volumétrie, vous devez gérer des tableaux d'une centaine de milliers de lignes et d'une centaine
de colonnes.
-
D'afficher un tableau avec en en-tête, le titre de chaque colonne. L'application affichera au maximum 50 lignes,
mais est muni d'une barre de défilement verticale (scrollbar) à droite du tableau qui permet d'afficher la
portion de 50 lignes du tableau que l'on souhaite afficher. Pour les formules, l'affichage devra afficher
le résultat du calcul de la formule.
Si une cellule d'un tableau est changée en utilisant un navigateur, tous les navigateurs qui affichent
le même tableau doivent se mettre à jour (sans que l'on fasse un refresh à la main !).
-
D'ajouter des lignes à la fin des lignes avec à un bouton + situé en bas à gauche du tableau
D'ajouter une colonne à la fin des colonnes avec un bouton en haut à droite du tableau.
Dans le cas d'une colonne, l'utilisateur devra aussi indiquer un titre.
D'éditer une cellule, en validant que la valeur est bien compatible avec le type de la colonne.
Lors de l'édition d'une cellule contenant une formule au lieu de voir le résultat de la formule,
l'application devra afficher la formule elle-même.
-
De stocker en base de données tous les tableaux créés (avec une table de base de données par tableau).
-
D'afficher une page avec tous les tableaux créés (c'est la page par défaut), sachant qu'un tableau est défini
par un nom (modifiable), une date de création et une date de dernière modification.
Au niveau de l'affichage, on devra pouvoir trier les tableaux en fonction de leur nom, et des dates.
Optionnellement, on doit pouvoir faire une recherche en tapant un mot (une suite de lettres),
dans ce cas, l'affichage n'affichera que les tableaux dont le nom contient le mot (sans avoir besoin d'appuyer
sur ENTRER). Vous utiliserez pour cela les capacités de recherche de la base de données.
En termes d'interface graphique, votre application doit être composée de deux écrans.
-
La première page sert d'écran d'accueil. Elle affiche l'ensemble des tableaux créés.
-
La seconde page affiche un tableau, avec son nom, ses titres de colonnes, ses boutons pour ajouter
des lignes et des colonnes et éventuellement une barre de défilement (scrollbar).
Pour représenter une formule, vous devrez définir vos propres classes dans un package spécifique.
Vous devrez aussi détecter les cycles pour éviter de partir en boucle infinie (si A1 dépend de B2
et B2 dépend de A1).
S'il y a beaucoup de lignes pour un tableau, vous ne devez pas transférer toutes les lignes
au navigateur, mais uniquement celles nécessaires à l'affichage.
De plus, le calcul des formules doit être effectué sur le serveur et pas en JavaScript dans le navigateur.
Si votre application n'est pas capable d'analyser, d'exécuter et d'afficher correctement les formules,
vous serez très sévèrement punis : être capable d'assurer que votre application calcule les formules correctement est
un objectif important.
Pour cela, on vous demande d'avoir des (plein !) tests unitaires (utilisant JUnit 5) qui montrent que votre
gestion des formules fonctionne de façon satisfaisante.
Technologies à utiliser
-
Vous devez utiliser Maven comme outil de build et IntelliJ comme IDE,
et la version 21 de Java.
-
Pour tester vos services REST, vous pouvez utiliser
Postman
ou tout autres clients capables de faire des requêtes REST.
-
Les test unitaires Java doivent être effectués avec JUnit 5.10.0, vous pouvez vous référer au
guide d'utilisation.
Chaque classe classe Java doit avoir une classe de test correspondante (pour au moins 80%) du projet.
-
Pour la sérialisation/dé-sérialisation JSON des requêtes, vous utiliserez une API de parsing JSON
Jackson 2.15.2
-
Pour parser un fichier CSV, vous utiliserez au choix,
Apache Commons CSV 1.10.0 ou
Open CSV 5.8.
Pour implanter les différents services REST, votre application doit utiliser une des technos
(c'est moi qui choisi pas vous) ci-dessous.
Attention à bien faire la différence entre les versions AOT ou JVM et les versions
synchrone et asynchrone (reactive) des APIs !
Pour Spring, Quarkus et Micronaut, vous configurerez le serveur pour qu'il utilise des threads virtuelles.
Pour l'API REST, les entrées et les sorties JSON doivent utiliser des records si possible.
Pour la mapping Object / Relational, i.e voir une ligne d'une table de BDD comme un objet Java.
Il y a deux implantations, une à base d'Hibernate qui peut être utilisée directement soit par
l'intermédiaire de la spécification JPA (Jakarta Persistence API). Et une à base de JDBI.
Attention, l'ancienne version de la Jakarta Persistence API s'appelle la Java Persistence API,
les deux ont le même acronyme JPA. On veut la nouvelle version donc la version Jakarta.
Pour le
front-end web, vous avez besoin d'un framework graphique
Note : le front-end doit être "buildé" aussi en utilisant
Maven (un seul POM pour front et le back),
vous aurez peut-être besoin de plugin Maven spécifique pour cela.
Note2: vous avez besoin de
npm pour la partie build, mais pas à l'exécution !
Vous pouvez de plus, utiliser une librairie spéciale pour la gestion de l'affichage du tableau pourvu quelle
soit adaptée à votre framework (pas de react-grid si vous devez utiliser svelte).
Attention: lors du déploiement, vous ne devez pas utiliser nodejs comme serveur Web, car vous avez
déjà un serveur Web qui sert l'API donc il peut aussi servir les pages statiques de votre librarie JS.
Bien sûr, pour le build, vous pouvez utiliser nodejs et npm pour construire votre application web.
Pour vous aidez à avoir de belles pages, vous allez aussi utiliser une bibliothèque qui vous aide
pour la partie CSS
L'application a besoin d'une base de données, mais vu le volume de données, pas forcément d'une
"vrai" base de données, nous utiliserons donc des bases de données
embedded.
L'intérêt d'une BDD
embedded est qu'elle est prête à l'emploi directement à partir d'un jar.
Il y a deux façons d'accéder à une BDD en Java, en utilisant le
Driver JDBC ou le
DataSource JDBC.
On vous demande d'utiliser le
DataSource car la gestion des connections à la BD est automatique.
Dans le cas où vous utilisez JPA / Hibernate, il vous faut aussi ajouter une dépendence sur Dialect correspondant
à votre base de donnees car chaque base de données parle un SQL un petit peu différent.
Attention, ces BDDs
embedded peuvent être utilisées aussi comme des BDDs classiques extérieurs
à l'application, ce n'est pas ce qui nous intéresse ici, on veut la version
embedded !
Et on ne veut pas que la base de donnée disparaisse quand on quitte l'application !
REST API documentation
Nous allons documenter l'API REST de votre
back-end en utilisant le format Open API 3.
Note : il y a deux façons d'utiliser Open API, soit on l'utilise comme un générateur qui génère le squelette
de l'API, soit dans l'autre sens, on extrait les valeurs des classes Java. On va utiliser la seconde version,
comme cela, la documentation de l'API sera toujours à jour avec le code.
Sécurité :
-
Pas de HTTPS pour ce projet (c'est mal) mais c'est pour vous aider à débugger !
-
Les entrées des services web au niveau de l'URL ou de la partie JSON doivent être validées
et les sorties doivent être "escapées" pour éviter les injections de code.
-
Il n'est pas demandé d'identifier les utilisateurs, optionnellement, vous pouvez le faire,
mais dans ce cas, vous devez utiliser des tokens JWT
et la librarie de votre choix.
-
Vous ne devriez pas avoir besoin de requêtes
CORS !
Sinon, cela veut dire que l'API REST et votre application JavaScript ne sont pas servis
par le même serveur.
-
Il n'y a aucune raison que le login/mdp de la BDD soit en dur dans votre code !
Binômes avec les technos qui doivent être utilisées
Binome | SERVER | FRONT | PERSISTENCE | UI | DB
AINOUZ KHATIR | Micronaut | svelte | Jdbi | bulma | derby
ALPHONSE RODDIER | Spring | reactjs | JPA (Jakarta) | bootstrap | h2
BAIET GIBOZ | Helidon 3 MP reactive | vuejs | JPA (Jakarta) | bulma | hypersql
BENOIT GUILLET | Micronaut | reactjs | JPA (Jakarta) | bulma | sqlite
BERRADI LEMAIRE | Helidon 3 MP | reactjs | JPA (Jakarta) | bootstrap | h2
BOUKHEDRA QABIL | Micronaut | angular | JPA (Jakarta) | bootstrap | hypersql
BOURDELAT SELLAM | Spring | angular | JPA (Jakarta) | tailwind | sqlite
DJEBLOUN MEYNE | Micronaut reactive | vuejs | JPA (Jakarta) | tailwind | sqlite
DUCOUDRÉ SOUSSI | Helidon 4 SE | solidjs | DB Client | bootstrap | sqlite
DUVAL OUSAID | Helidon 4 MP | svelte | JPA (Jakarta) | bootstrap | derby
ESTEVES KNISS | Quarkus AOT | solidjs | Hibernate with panache | bulma | derby
FICHE | Spring reactive | svelte | JPA (Jakarta) | tailwind | hypersql
JAAYARADJE NGUYEN | Quarkus reactive | reactjs | JPA (Jakarta) | tailwind | sqlite
MLYNARZ VINCENT | Quarkus | vuejs | JPA (Jakarta) | bootstrap | hypersql
PANIZZI PASQUIER | Quarkus | angular | JPA (Jakarta) | bootstrap | h2
PHAM LE NGOC BICH VIRY | Micronaut | angular | JPA (Jakarta) | tailwind | h2
Calendrier des rendus.
Soutenance intermédiaire (bêta) : 18 octobre 2023
Toutes les parties de l'architecture doivent être présentes et communiquer entre elles.
Votre API REST doit être visible en utilisant Swagger (le frontend graphique OpenAPI).
Il peut y avoir des bugs, ce n'est pas grave, mais on doit avoir la majorité de l'affichage qui marche.
Soutenance finale : 27 novembre 2023
Tout doit marcher parfaitement, les docs utilisateur et de développement doivent être présentes.
Pour vous aider, si vous ne respectez pas les indications de "sudden death" suivantes,
votre projet sera considéré comme mort et noté 0.
Pour la partie Java, le programme doit être écrit en utilisant correctement les différents concepts
vus lors du cours de Java Avancé (sous-typage, polymorphisme, pattern matching, lambdas, classes internes,
exceptions, types paramétrés, collections, entrées/sorties).
-
Une des technologies que votre projet utilise n'est pas celle requise pour votre binôme
-
Vous avez la même API REST qu'un projet d'un autre binôme.
-
Il ne doit pas y avoir de warnings lorsque l'on compile avec javac -Xlint:all.
-
Dans un module, les packages d'implantation ne doivent pas être exportés et
requires transitive doit être utilisé là où c'est nécessaire.
-
Il ne doit pas y avoir de raw types, de @SuppressWarning non justifié, de cast non justifié.
-
Le principe d'encapsulation et la programmation par contrat doivent être respectées.
-
Il ne doit pas y avoir de champs ou méthodes protected.
-
Il ne doit pas y avoir d'instanceof/if...else sur des types là où il est possible
d'utiliser le polymorphisme ou le pattern matching.
-
Chaque interface devra être nécessaire.
Une interface possède 0 ou 1 méthode (sinon justifiée).
-
Aucune classe abstraite ne doit être publique ou utilisée comme un type.
-
Chaque méthode devra être appelée (pas de code mort).
-
Aucune méthode ne doit faire plus de 10 lignes sans une vraie justification.
-
Il est interdit d'utiliser des champs static typés par un objet (pas de variables globales),
seules les constantes (static final) de type primitif sont autorisées (et utiliser l'injection de dépendance SVP).
-
Le fichier POM.xml ne doit pas contenir de dépendances non listées dans ce document
où ayant une autre version que la version demandée (à part les dépendances de dépendances).
© Université de Marne-la-Vallée