Conception et Développement d'une Mini-application de Tri des Déchets basée sur Spring Boot et Vue.js

Dans le contexte actuel de croissance économique rapide, la gestion efficace des informations environnementales est devenue une priorité. Le passage des méthodes de stockage traditionnelles à des systèmes logiciels centralisés permet d'optimiser le traitement des données massives. Cette application de tri des déchets a été conçue pour offrir une solution automatisée, permettant aux administrateurs de gérer les flux d'informations avec une efficacité accrue.

Architecture Technique et Environnement

Le système repose sur une architecture robuste et moderne utilisant des technologies multiplateformes :

  • Back end : Framework Java Spring Boot pour une configuration simplifiée et une gestion efficace des dépendances.
  • Frontend : Framework Vue.js associé à Uni-app pour garantir une compatibilité optimale sous forme de mini-programme WeChat.
  • Base de données : MySQL 5.7 pour le stockage relationnel des données, garantissant performance et sécurité.
  • Outils de développement : JDK 1.8, Maven 3.3.9, et IntelliJ IDEA ou Eclipse.

Fonctionnalités Principales

L'application est divisée en plusieurs modules destinés aux administrateurs et aux utilisateurs finaux :

  • Gestion administrative : Contrôle des utilisateurs, gestion des catégories de déchets, modération du forum, mise à jour des actualités écologiques et administration des vidéos éducatives.
  • Espace utilisateur : Consultation des guides de tri, accès aux articles de sensibilisation, participation à des quiz interactifs sur l'environnement et soumission de commentaires.
  • Système de Quiz : Un module dédié à l'évaluation des connaissances permettant de tester la sensibilisation des utilisateurs au tri sélectif.

Implémentation du Backend

Voici un exemple de l'implémentation du contrôleur de gestion des médias, permettant le téléchargement et la récupération de fichiers sur le serveur.


@RestController
@RequestMapping("/media")
public class MediaManagerController {

    @Autowired
    private SystemConfigService systemConfigService;

    /**
     * Traitement de l'upload de fichiers
     */
    @PostMapping("/uploadFile")
    @IgnoreAuth
    public ResponseResult processFileUpload(@RequestParam("doc") MultipartFile multipartFile, String category) throws Exception {
        if (multipartFile.isEmpty()) {
            throw new CustomException("Le fichier source ne peut pas être vide.");
        }

        String extension = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf("."));
        File rootDir = new File(ResourceUtils.getURL("classpath:static").getPath());
        if (!rootDir.exists()) {
            rootDir = new File("");
        }

        File storageFolder = new File(rootDir.getAbsolutePath(), "/media_assets/");
        if (!storageFolder.exists()) {
            storageFolder.mkdirs();
        }

        String uniqueName = System.currentTimeMillis() + extension;
        File targetFile = new File(storageFolder.getAbsolutePath() + "/" + uniqueName);
        multipartFile.transferTo(targetFile);

        // Mise à jour de la configuration si le type est spécifique
        if (StringUtils.isNotBlank(category) && "AVATAR".equals(category)) {
            ConfigEntity cfg = new ConfigEntity();
            cfg.setName("last_uploaded_avatar");
            cfg.setValue(uniqueName);
            systemConfigService.insertOrUpdate(cfg);
        }

        return ResponseResult.success().put("fileName", uniqueName);
    }

    /**
     * Méthode de récupération de fichiers
     */
    @GetMapping("/fetch/{name}")
    @IgnoreAuth
    public ResponseEntity<byte[]> getMedia(@PathVariable("name") String name) {
        try {
            File baseDir = new File(ResourceUtils.getURL("classpath:static").getPath());
            File asset = new File(baseDir.getAbsolutePath() + "/media_assets/" + name);
            
            if (asset.exists()) {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
                headers.setContentDispositionFormData("attachment", name);
                return new ResponseEntity<>(FileUtils.readFileToByteArray(asset), headers, HttpStatus.OK);
            }
        } catch (IOException err) {
            err.printStackTrace();
        }
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
}

Le module suivant illustre la gestion des interactions communautaires via un forum de discussion, incluant la gestion des commentaires imbriqués.


@RestController
@RequestMapping("/community")
public class DiscussionController {
    
    @Autowired
    private DiscussionService discussionService;

    /**
     * Récupération paginée des messages du forum
     */
    @RequestMapping("/browse")
    public ResponseResult getDiscussionLogs(@RequestParam Map<String, Object> criteria, DiscussionEntity post, HttpServletRequest req) {
        Object role = req.getSession().getAttribute("role");
        if (!"Admin".equals(role)) {
            post.setAuthorId((Long) req.getSession().getAttribute("userId"));
        }
        
        EntityWrapper<DiscussionEntity> wrapper = new EntityWrapper<>();
        PageUtils pageData = discussionService.queryFilteredPage(criteria, MPUtil.likeOrEq(wrapper, post));

        return ResponseResult.success().put("payload", pageData);
    }

    /**
     * Sauvegarde d'une nouvelle publication
     */
    @PostMapping("/postMessage")
    public ResponseResult publishTopic(@RequestBody DiscussionEntity topic, HttpServletRequest req) {
        topic.setTimestamp(new Date());
        topic.setAuthorId((Long) req.getSession().getAttribute("userId"));
        discussionService.insert(topic);
        return ResponseResult.success("Message publié avec succès");
    }

    /**
     * Structure récursive pour les réponses aux messages
     */
    @GetMapping("/thread/{id}")
    public ResponseResult getFullThread(@PathVariable("id") Long id) {
        DiscussionEntity rootMessage = discussionService.selectById(id);
        fetchNestedReplies(rootMessage);
        return ResponseResult.success().put("data", rootMessage);
    }
    
    private void fetchNestedReplies(DiscussionEntity parent) {
        List<DiscussionEntity> replies = discussionService.selectList(
            new EntityWrapper<DiscussionEntity>().eq("parent_id", parent.getId())
        );
        if (replies != null && !replies.isEmpty()) {
            parent.setReplies(replies);
            for (DiscussionEntity reply : replies) {
                fetchNestedReplies(reply);
            }
        }
    }
}

Validation et Tests

La fiabilité du système a été vérifiée par une série de tests rigoureux. Une approche de test en "boîte noire" a permis de valider les fonctionnalités du point de vue de l'utilisateur final (navigation, soumission de formulaires), tandis que les tests en "boîte blanche" ont servi à vérifier l'intégrité de la logique métier et des flux de données internes. L'accent a été mis sur la sécurité des accès et la robustesse de la base de données face aux requêtes concurrentes.

L'utilisation de Spring Boot a considérablement réduit la complexité de la gestion des ressources, tandis que MySQL a offert une base solide pour la persistance des données, assurant ainsi une solution évolutive et facile à maintenir pour la gestion du tri des déchets.

Étiquettes: Spring Boot Vue.js MySQL Java uni-app

Publié le 20 juin à 05h21