Système d'analyse des populations hypertendues basé sur SpringBoot et Vue.js avec intégration de big data médical

Objectifs du projet

Ce projet consiste à concevoir et développer une plateforme d'analyse dédiée au suivi des patients hypertendus, en s'appuyant sur une architecture frontend-backend séparée combinant SpringBoot et Vue.js. La solution intègre les technologies du big data appliquées au domaine médical pour offrir un ensemble cohérent de fonctionnalités : collecte de données de santé, analyse multidimensionnelle, modélisation prédictive du risque cardiovasculaire, et recommandations thérapeutiques personnalisées.

Les fonctionnalités principales incluent la centralisation des dossiers patients (mesures tensionnelles, traitements médicamenteux, habitudes de vie), la visualisation graphique des tendances, l'évaluation du risque d'complications, la gestion des suivis médicaux, ainsi que l'optimisation de l'allocation des ressources hospitalières. Le système est conçu pour accepter les flux temps réel provenant de dispositifs connectés (montres santé, brassards tensionnels), traiter les comptes rendus médicaux via un module NLP, et construire un graphe de connaissances médicales incorporant les recommandations officielles sur l'hypertension.

Intérêt et portée

Sur le plan technique, ce projet illustre l'application concrète d'une architecture microservices avec séparation des responsabilités entre le backend Java et le frontend JavaScript. Il explore l'intégration de pipelines de traitement de données massives, de modèles d'apprentissage automatique pour la prédiction clinique, ainsi que les problématiques de sécurité et de conformité des données de santé.

Sur le plan clinique, la plateforme adresse les limitations des systèmes traditionnels de suivi de l'hypertension : fragmentation des données, retard d'analyse, et réactivité insuffisante face aux aggravations. L'exploitation des capacités analytiques permet d'identifier les facteurs déterminants dans l'évolution de la maladie, de détecter précocement les patients à haut risque, et de proposer des plans d'intervention adaptés au profil individuel de chaque patient. L'interopérabilité avec les systèmes d'information hospitaliers (SIH) et les plateformes régionales de santé facilite le partage de données et soutient la mise en œuvre du parcours de soins coordonnés.

Pile technologique

Backend : SpringBoot

SpringBoot constitue le socle backend de l'application. Ce framework Java simplifie considérablement la création d'applications Spring autonomes et prêtes pour la producsion grâce à son approche d'autoconfiguration intelligente. Le principe de « convention plutôt que configuration » permet aux développeurs de se concentrer sur la logique métier sans subir le poids des fichiers XML traditionnels.

L'intégration d'un serveur web embarqué (Tomcat par défaut) permet de conditionner l'application en archive JAR exécutable, déployable via une simple commande java -jar. Les modules Starter facilitent l'ajout incrémental de capacités telles que la sécurité (Spring Security), l'accès aux données (Spring Data JPA), ou la mise en cache. Les endpoints Actuator offrent quant à eux une visibilité sur l'état opérationnel de l'application en cours d'exécution.

Frontend : Vue.js

Vue.js est utilisé pour construire l'interface utilisateur. Ce framework JavaScript progressif repose sur un système de liaison de données réactif qui synchronise automatiquement le DOM avec l'état de l'application. Son architecture basée sur des composants favorise la réutilisabilité et la maintenabilité du code.

L'écosystème Vue (Vue Router, Vuex/Pinia, Vue CLI) fournit les outils nécessaires pour structurer une application monopage complète. La communauté active et la documentation abondante en font un choix éprouvé pour des projets de cette envergure.

Code essentiel

Point d'entrée de l'application

package fr.medical.hypertension;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@MapperScan("fr.medical.hypertension.repository")
public class HypertensionAnalysisApp extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.launch(HypertensionAnalysisApp.class, args);
    }

    @Override
    protected SpringApplicationBuilder initialize(SpringApplicationBuilder builder) {
        return builder.sources(HypertensionAnalysisApp.class);
    }
}

Contrôleur de gestion des patients

package fr.medical.hypertension.api;

import fr.medical.hypertension.entity.PatientRecord;
import fr.medical.hypertension.entity.PatientView;
import fr.medical.hypertension.service.PatientService;
import fr.medical.hypertension.service.JwtTokenService;
import fr.medical.hypertension.common.ApiResponse;
import fr.medical.hypertension.common.PageResult;
import fr.medical.hypertension.common.QueryHelper;
import fr.medical.hypertension.config.PublicEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

@RestController
@RequestMapping("/api/patients")
public class PatientController {

    @Autowired
    private PatientService patientService;

    @Autowired
    private JwtTokenService jwtTokenService;

    @PublicEndpoint
    @PostMapping("/authenticate")
    public ApiResponse authenticate(@RequestParam String login,
                                    @RequestParam String secret,
                                    HttpServletRequest req) {
        PatientRecord record = patientService.findOne(
            new EntityWrapper<patientrecord>().eq("login", login)
        );
        if (record == null || !record.getPassword().equals(secret)) {
            return ApiResponse.fail("Identifiants invalides");
        }
        String jwt = jwtTokenService.createToken(record.getPatientId(), login, "patient");
        return ApiResponse.ok().put("token", jwt);
    }

    @PublicEndpoint
    @PostMapping("/signup")
    public ApiResponse signup(@RequestBody PatientRecord newPatient) {
        PatientRecord existing = patientService.findOne(
            new EntityWrapper<patientrecord>().eq("login", newPatient.getLogin())
        );
        if (existing != null) {
            return ApiResponse.fail("Ce identifiant est déjà utilisé");
        }
        newPatient.setPatientId(System.currentTimeMillis());
        patientService.persist(newPatient);
        return ApiResponse.ok();
    }

    @PostMapping("/signout")
    public ApiResponse signout(HttpServletRequest req) {
        req.getSession().invalidate();
        return ApiResponse.ok("Déconnexion réussie");
    }

    @GetMapping("/current")
    public ApiResponse currentUser(HttpServletRequest req) {
        Long pid = (Long) req.getSession().getAttribute("patientId");
        PatientRecord record = patientService.findById(pid);
        return ApiResponse.ok().put("data", record);
    }

    @PublicEndpoint
    @PostMapping("/recover-password")
    public ApiResponse recoverPassword(@RequestParam String login) {
        PatientRecord record = patientService.findOne(
            new EntityWrapper<patientrecord>().eq("login", login)
        );
        if (record == null) {
            return ApiResponse.fail("Compte introuvable");
        }
        record.setPassword("default123");
        patientService.modify(record);
        return ApiResponse.ok("Mot de passe réinitialisé à : default123");
    }

    @GetMapping("/dashboard")
    public ApiResponse dashboard(@RequestParam Map<String, Object> filters,
                                 PatientRecord filterParams,
                                 HttpServletRequest req) {
        EntityWrapper<patientrecord> wrapper = new EntityWrapper<>();
        PageResult result = patientService.fetchPage(
            filters,
            QueryHelper.orderBy(QueryHelper.range(QueryHelper.match(wrapper, filterParams), filters), filters)
        );
        return ApiResponse.ok().put("data", result);
    }

    @GetMapping("/{id}")
    public ApiResponse getPatient(@PathVariable Long id) {
        PatientRecord record = patientService.findById(id);
        return ApiResponse.ok().put("data", record);
    }

    @PostMapping("/create")
    @Transactional
    public ApiResponse createPatient(@RequestBody PatientRecord newRecord) {
        int count = patientService.count(
            new EntityWrapper<patientrecord>().eq("login", newRecord.getLogin())
        );
        if (count > 0) {
            return ApiResponse.fail("Identifiant déjà attribué");
        }
        newRecord.setPatientId(System.currentTimeMillis());
        patientService.persist(newRecord);
        return ApiResponse.ok();
    }

    @PutMapping("/modify")
    @Transactional
    public ApiResponse modifyPatient(@RequestBody PatientRecord updatedRecord) {
        int conflictCount = patientService.count(
            new EntityWrapper<patientrecord>()
                .ne("patientId", updatedRecord.getPatientId())
                .eq("login", updatedRecord.getLogin())
        );
        if (conflictCount > 0) {
            return ApiResponse.fail("Identifiant déjà utilisé par un autre patient");
        }
        patientService.modify(updatedRecord);
        return ApiResponse.ok();
    }

    @DeleteMapping("/remove")
    public ApiResponse removePatients(@RequestBody Long[] patientIds) {
        patientService.batchDelete(Arrays.asList(patientIds));
        return ApiResponse.ok();
    }
}
</patientrecord></patientrecord></patientrecord></patientrecord></patientrecord></patientrecord>

Validation du système

La phase de tests vise à détecter les anomalies sous différents angles et à garantir la conformité du système avec les exigences fonctionnelles définies. Les tests boîte noire constituent l'approche principale : ils simulent les parcours utilisateurs réels à travers les différents modules de l'application.

Objectifs des tests

Le processus de validation constitue la dernière étape de contrôle qualité avant la mise en production. Il permet de vérifier la robustesse de l'application face à des scénarios variés : saisies de valeurs limites, champs obligatoires omis, tentatives d'accès non autorisées, et comportements attendus sous charge. L'objectif est de s'assurer que chaque fonction répond correctement aux cas d'usage prévus et de corriger les écarts éventuels avant le déploiement.

Cas de test : authentification

Le module de connexion est validé en vérifiant que seules les combinaisons identifiant/mot de passe correspondant aux enregistrements de la base permettent l'accès. La gestion des rôles est également testée : un compte patient ne peut accéder aux fonctionnalités réservées au personnel médical. En cas d'erreur de saisie, le système renvoie un message explicite à l'utilisateur.

Conclusion des tests

Les résultats obtenus confirment que l'ensemble des modules fonctionnels respecte les spécifications initiales. Les parcours utilisateurs s'enchaînent de manière fluide, les contrôles de validation des données opèrent correctement, et les temps de réponse restent acceptables dans les conditions de charge simulées. Le système est jugé apte au déploiement dans un environnement de production.

Étiquettes: SpringBoot Vue.js Java hypertension big-data

Publié le 30 juillet à 09h47