Conception et mise en œuvre d'un système de gestion de voitures partagées basé sur SpringBoot et Vue

Technologies employées

Framework backend : SpringBoot

Spring Boot permet de créer des appplications autonomes et prêtes pour la production. Il fournit un ensemble de prérequis d'opinion ("opinionated defaults") pour le configuration de Spring et des bibliothèques tierces, ce qui évite une configuration manuelle fastidieuse. Il est conçu pour faciliter le démarrage rapide des projets et permet de se concentrer sur la logique métier plutôt que sur l'infrastructure.

Framework frontend : Vue.js

Vue.js est un framework JavaScript progressif pour la construction d'interfaces utilisateur. Son modèle de programmation basé sur des composants et son système réactif de liaison de données permettent de créer des applications web modernes et réactives. Sa nature progressive permet de l'adopter de manière incrémentielle, que ce soit pour enrichir une partie d'une page existante ou pour développer une application complète (SPA).

Couche de persistence : MyBatis-Plus

MyBatis-Plus est un complément puissant à MyBatis qui fournit des fonctionnalités supplémentaires pour simplifier les opérations CRUD et le développement de la couche d'accès aux données. Il inclut des outils de génération de code, des fonctionnalités avancées de pagination et de requêtes conditionnelles, ainsi qu'une prise en charge optimisée pour les bases de données relationnelles courantes.

Test du système

La phase de test vise à identifier les défauts et les vulnérabilités du système en le soumettant à des scénarios d'utilisation variés. L'objectif est de garantir que le produit final répond aux spécifications fonctionnelles et non fonctionnelles définies et offre une expérience utilisateur fiable.

Objectifs des tests

Les tests constituent une étape cruciale dans le cycle de développement pour assurer la qualité et la robustesse du système. Ils visent à simuler les conditions d'utilisation réelles afin de détecter les problèmes avant la mise en production. Cette démarche permet de valider la conformité aux exigences, d'identifier les écarts par rapport au cahier des charges et d'améliorer la satisfaction de l'utilisateur final.

Tests fonctionnels

Les tests fonctionnels sont réalisés sur les différents modules du système. Ils impliquent une approche de boîte noire, où le système est testé en fonction de ses entrées et sorties sans examen du code interne. Les cas de test sont conçus pour vérifier les fonctionnalités clés, les règles de validation et la gestion des erreurs.

Scénario de test : Authentification

Données d'entrée Résultat attendu Résultat observé Analyse
Identifiant : admin Mot de passe : secret123 Code : valide Connexion réussie Connexion réussie Conforme
Identifiant : admin Mot de passe : mauvais Code : valide Message d'erreur sur le mot de passe Message d'erreur sur le mot de passe Conforme
Identifiant : admin Mot de passe : secret123 Code : invalide Message d'erreur sur le code Message d'erreur sur le code Conforme
Identifiant : (vide) Mot de passe : secret123 Code : valide Champ identifiant obligatoire Champ identifiant obligatoire Conforme

Scénario de test : Gestion des utilisateurs

Action Résultat attendu Résultat observé Analyse
Créer un nouvel utilisateur avec des informations valides Utilisateur ajouté à la liste Utilisateur visible dans la liste Conforme
Modifier les informations d'un utilisateur existant Mise à jour des informations Informations mises à jour dans l'affichage Conforme
Supprimer un utilisateur sélectionné Utilisateur supprimé après confirmation Utilisateur introuvable après suppression Conforme
Tenter de créer un utilisateur sans remplir le champ obligatoire "nom d'utilisateur" Message d'erreur indiquant que le champ est obligatoire Message d'erreur indiquant que le champ est obligatoire Conforme

Conclusion des tests

L'ensemble des tests fonctionnels a été exécuté avec succès, démontrant que les modules principaux du système se comportent conformément aux attentes. Les scénarios d'erreur et les cas limites ont été correctement gérés. Ces résultats valident la solidité de l'implémentation et la qualité de l'expérience utilisateur proposée.

Extrait de code

Voici un exemple de méthode pour gérer l'authentification et de génération de jeton (token) :

@IgnoreAuth
@PostMapping(value = "/connexion")
public R seConnecter(String identifiant, String motDePasse, String codeVerification, HttpServletRequest requete) {
   UtilisateurEntity utilisateur = serviceUtilisateur.selectOne(new EntityWrapper<UtilisateurEntity>().eq("identifiant", identifiant));
   if(utilisateur == null || !utilisateur.getMotDePasse().equals(motDePasse)) {
      return R.error("Identifiants incorrects");
   }
   String jeton = serviceJeton.genererJeton(utilisateur.getId(), identifiant, "utilisateurs", utilisateur.getRole());
   return R.ok().put("jeton", jeton);
}

@Override
public String genererJeton(Long idUtilisateur, String identifiant, String nomTable, String role) {
    JetonEntity entiteJeton = this.selectOne(new EntityWrapper<JetonEntity>().eq("id_utilisateur", idUtilisateur).eq("role", role));
    String nouveauJeton = UtilitaireCommun.chaineAleatoire(32);
    Calendar calendrier = Calendar.getInstance();
    calendrier.add(Calendar.HOUR_OF_DAY, 1);
    if(entiteJeton != null) {
        entiteJeton.setJeton(nouveauJeton);
        entiteJeton.setDateExpiration(calendrier.getTime());
        this.updateById(entiteJeton);
    } else {
        this.insert(new JetonEntity(idUtilisateur, identifiant, nomTable, role, nouveauJeton, calendrier.getTime()));
    }
    return nouveauJeton;
}

Un intercepteur pour vérifier l'autorisation via le jeton :

@Component
public class IntercepteurAutorisation implements HandlerInterceptor {

    public static final String EN_TETE_JETON = "Jeton";

    @Autowired
    private ServiceJeton serviceJeton;

    @Override
    public boolean preHandle(HttpServletRequest requete, HttpServletResponse reponse, Object handler) throws Exception {
        reponse.setHeader("Access-Control-Allow-Origin", requete.getHeader("Origin"));
        reponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        reponse.setHeader("Access-Control-Allow-Headers", "Origin, Jeton, Content-Type, Accept");

        if (requete.getMethod().equals(RequestMethod.OPTIONS.name())) {
            reponse.setStatus(HttpStatus.OK.value());
            return false;
        }

        IgnoreAuth annotation;
        if (handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
        } else {
            return true;
        }

        String jeton = requete.getHeader(EN_TETE_JETON);

        if(annotation != null) {
            return true;
        }

        JetonEntity entiteJeton = null;
        if(StringUtils.isNotBlank(jeton)) {
            entiteJeton = serviceJeton.obtenirEntiteParJeton(jeton);
        }

        if(entiteJeton != null) {
            requete.getSession().setAttribute("utilisateurId", entiteJeton.getIdUtilisateur());
            requete.getSession().setAttribute("role", entiteJeton.getRole());
            return true;
        }

        reponse.setCharacterEncoding("UTF-8");
        reponse.setContentType("application/json; charset=utf-8");
        PrintWriter ecrivain = reponse.getWriter();
        ecrivain.print("{\"code\":401, \"msg\":\"Veuillez vous connecter\"}");
        ecrivain.close();
        return false;
    }
}

Structure de base de données

-- Table pour stocker les jetons d'authentification
DROP TABLE IF EXISTS `jeton_auth`;
CREATE TABLE `jeton_auth` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Clé primaire',
  `id_utilisateur` bigint(20) NOT NULL COMMENT 'Identifiant de l''utilisateur',
  `nom_utilisateur` varchar(100) NOT NULL COMMENT 'Nom de l''utilisateur',
  `nom_table` varchar(100) DEFAULT NULL COMMENT 'Table source',
  `role` varchar(100) DEFAULT NULL COMMENT 'Rôle de l''utilisateur',
  `jeton` varchar(200) NOT NULL COMMENT 'Valeur du jeton',
  `date_creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
  `date_expiration` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date d''expiration',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Table des jetons d''authentification';

-- Exemples d'enregistrements
INSERT INTO `jeton_auth` VALUES (1, 1001, 'conducteur01', 'utilisateurs', 'conducteur', 'abc123xyz789def456ghi012jkl345mno', '2023-05-10 09:00:00', '2023-05-10 17:00:00');
INSERT INTO `jeton_auth` VALUES (2, 1002, 'admin_systeme', 'utilisateurs', 'administrateur', 'pqr678stu901vwx234yza567bcd890efg', '2023-05-10 10:15:00', '2023-05-11 10:15:00');

Étiquettes: SpringBoot Vue.js MyBatis-Plus Java MySQL

Publié le 4 juin à 22h37