Système dynamique de requête de table en Java

Conception d’un système de requêtes dynamiques pour tables SQL en Java

Dans les applications modernes, la capacité à générer des requêtes SQL dynamiquement selon des critères variés est essentielle. Ce mécanisme permet une flexibilité accrue dans l’interrogasion des données, sans nécessiter de modifications manuelles du code pour chaque type de filtre.

Ce guide explique comment concevoir un tel système en utilisant Java, avec une architecture claire et sécurisée contre les injections SQL.

Architecture fondamentale Le processus repose sur plusieurs étapes :

  • Modélisation de la structure de base de données.
  • Mise en place d’une entité Java correspondante.
  • Réception des paramètres de recherche via une couche API ou front-end.
  • Construction dynamique de la requête SQL en fonction des critères fournis.
  • Exécution sécurisée de la requête et retour des résultats.

Exemple pratique : Recherche d'utilisateurs

1. Structure de la table utilisateur

CREATE TABLE Utilisateur (
    id INT PRIMARY KEY AUTO_INCREMENT,
    nom VARCHAR(50),
    courriel VARCHAR(50),
    age INT
);

2. Classe Java représentant l'entité

package com.example.model;

public class Utilisateur {
    private int identifiant;
    private String nom;
    private String courriel;
    private int age;

    // Accesseurs (getters) et mutateurs (setters)
    public int getIdentifiant() { return identifiant; }
    public void setIdentifiant(int identifiant) { this.identifiant = identifiant; }

    public String getNom() { return nom; }
    public void setNom(String nom) { this.nom = nom; }

    public String getCourriel() { return courriel; }
    public void setCourriel(String courriel) { this.courriel = courriel; }

    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

3. DTO de requête dynamique

package com.example.dto;

public class FiltreUtilisateur {
    private String nomPartiel;
    private String courrielPartiel;
    private Integer ageMinimum;
    private Integer ageMaximum;

    // Getters et setters
    public String getNomPartiel() { return nomPartiel; }
    public void setNomPartiel(String nomPartiel) { this.nomPartiel = nomPartiel; }

    public String getCourrielPartiel() { return courrielPartiel; }
    public void setCourrielPartiel(String courrielPartiel) { this.courrielPartiel = courrielPartiel; }

    public Integer getAgeMinimum() { return ageMinimum; }
    public void setAgeMinimum(Integer ageMinimum) { this.ageMinimum = ageMinimum; }

    public Integer getAgeMaximum() { return ageMaximum; }
    public void setAgeMaximum(Integer ageMaximum) { this.ageMaximum = ageMaximum; }
}

4. Service de requête dynamique

package com.example.service;

import com.example.dto.FiltreUtilisateur;
import com.example.model.Utilisateur;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class ServiceUtilisateur {

    private Connection obtenirConnexion() throws Exception {
        String url = "jdbc:mysql://localhost:3306/monapp";
        String user = "admin";
        String pwd = "securepass";
        return DriverManager.getConnection(url, user, pwd);
    }

    public List<Utilisateur> rechercher(FiltreUtilisateur filtres) {
        List<Utilisateur> resultat = new ArrayList<>();
        StringBuilder requete = new StringBuilder("SELECT * FROM Utilisateur WHERE 1=1");

        if (filtres.getNomPartiel() != null && !filtres.getNomPartiel().isEmpty()) {
            requete.append(" AND nom LIKE ?");
        }
        if (filtres.getCourrielPartiel() != null && !filtres.getCourrielPartiel().isEmpty()) {
            requete.append(" AND courriel LIKE ?");
        }
        if (filtres.getAgeMinimum() != null) {
            requete.append(" AND age >= ?");
        }
        if (filtres.getAgeMaximum() != null) {
            requete.append(" AND age <= ?");
        }

        try (Connection connexion = obtenirConnexion();
             PreparedStatement instruction = connexion.prepareStatement(requete.toString())) {

            int indice = 1;
            if (filtres.getNomPartiel() != null && !filtres.getNomPartiel().isEmpty()) {
                instruction.setString(indice++, "%" + filtres.getNomPartiel() + "%");
            }
            if (filtres.getCourrielPartiel() != null && !filtres.getCourrielPartiel().isEmpty()) {
                instruction.setString(indice++, "%" + filtres.getCourrielPartiel() + "%");
            }
            if (filtres.getAgeMinimum() != null) {
                instruction.setInt(indice++, filtres.getAgeMinimum());
            }
            if (filtres.getAgeMaximum() != null) {
                instruction.setInt(indice++, filtres.getAgeMaximum());
            }

            ResultSet resultatRs = instruction.executeQuery();
            while (resultatRs.next()) {
                Utilisateur user = new Utilisateur();
                user.setIdentifiant(resultatRs.getInt("id"));
                user.setNom(resultatRs.getString("nom"));
                user.setCourriel(resultatRs.getString("courriel"));
                user.setAge(resultatRs.getInt("age"));
                resultat.add(user);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return resultat;
    }
}

5. Contrôleur d’interaction

package com.example.controller;

import com.example.dto.FiltreUtilisateur;
import com.example.service.ServiceUtilisateur;
import java.util.List;

public class ControleurUtilisateur {

    private final ServiceUtilisateur service = new ServiceUtilisateur();

    public void traiterRequete(FiltreUtilisateur filtres) {
        List<Utilisateur> resultats = service.rechercher(filtres);
        resultats.forEach(u -> System.out.println(
            "ID: " + u.getIdentifiant() +
            ", Nom: " + u.getNom() +
            ", Email: " + u.getCourriel() +
            ", Âge: " + u.getAge()
        ));
    }

    public static void main(String[] args) {
        ControleurUtilisateur controleur = new ControleurUtilisateur();
        FiltreUtilisateur filtres = new FiltreUtilisateur();
        filtres.setNomPartiel("Jean");
        filtres.setAgeMinimum(30);
        filtres.setAgeMaximum(50);
        controleur.traiterRequete(filtres);
    }
}

Cette approche garantit une construction de requête sécurisée, évitant les failles d'injection SQL grâce à l'utilisation de PreparedStatement. Elle offre également une grande extensibilité pour intégrer de nouveaux filtres sans refonte complète du code.

Étiquettes: Java JDBC MySQL requête dynamique Sécurité SQL

Publié le 17 septembre à 04h12