Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Swing - Coder un explorateur de bases de données SQL

KSqlQueryTable - Lister le contenu d'une requête SQL Appliquer un « look'n feel »



Accès rapide :
Présentation de l'application DatabaseExplorer
Une boite de dialogue pour configurer les informations de connexion à la base de données.
On intègre les composants graphiques requis dans une fenêtre

Présentation de l'application DatabaseExplorer

Il s'agit donc d'une application Java/Swing permettant de se connecter à une base de données et d'afficher les données stockées dans les tables de la base de données. Bien entendu, il s'agit d'un prototype et il vous appartient de poursuivre le développement de l'application. Voici une capture d'écran de l'application.

Le code que je vais vous présenter s'appuie sur des composants présentés dans des tutoriels précédents. En voici la liste, si vous souhaitez avoir accès à tous les codes.
vous pouvez télécharger le projet contenant les codes présentés, en activant ce lien.

Une boite de dialogue pour configurer les informations de connexion à la base de données.

Il s'agit d'une boîte de dialogue permettant de saisir les quatre informations nécessaires à une connexion JDBC : le nom du driver, l'URL de connexion, le login et le mot de passe. Voici une capture d'écran de cette boîte de dialogue.

Et voici maintenant le code de cette boîte de dialogue.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 
 126 
 127 
 128 
 129 
 130 
package fr.koor.databaseexplorer;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import fr.koor.swing.KLink;

public class ConnectionDialog extends JDialog {

    private static final long serialVersionUID = 2243410969753026214L;
    private static final String CONF_FILENAME = "conf.properties";

    private Properties props = new Properties();
    
    private JTextField txtDriverClassName = new JTextField();
    private JTextField txtUrl = new JTextField();
    private JTextField txtLogin = new JTextField();
    private JTextField txtPassword = new JTextField();
    
    
    public ConnectionDialog( MainWindow owner ) {
        super( owner, "Choice your database",  true );
        
        // --- Changement des données précédemment éditées ---
        try ( FileInputStream fis = new FileInputStream( CONF_FILENAME ) ) {
            props.load( fis );
            txtDriverClassName.setText( props.getProperty( "jdbc.driver.class" ) );
            txtUrl.setText( props.getProperty( "jdbc.url" ) );
            txtLogin.setText( props.getProperty( "jdbc.login" ) );
            txtPassword.setText( props.getProperty( "jdbc.password" ) );
        } catch ( Exception exception ) {
            exception.printStackTrace();
        }
        
        // --- Récupération du content pane ---
        JPanel contentPane = (JPanel) getContentPane();
        
        // --- Création de la partie centrale ---
        JPanel pnlConnectionInformations = new JPanel( new GridLayout( 5, 2, 10, 10 ) );
        pnlConnectionInformations.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) );
        
        pnlConnectionInformations.add( new JLabel( "Driver class name: " ) );
        pnlConnectionInformations.add( txtDriverClassName );
        pnlConnectionInformations.add( new JLabel( "URL: " ) );
        pnlConnectionInformations.add( txtUrl );
        pnlConnectionInformations.add( new JLabel( "Login: " ) );
        pnlConnectionInformations.add( txtLogin );
        pnlConnectionInformations.add( new JLabel( "Password: " ) );
        pnlConnectionInformations.add( txtPassword );
        KLink pinkLink = new KLink( "Ping database" );
        pinkLink.addActionListener( this::pingDatabase );
        pnlConnectionInformations.add( pinkLink );
        
        
        contentPane.add( pnlConnectionInformations, BorderLayout.CENTER );
        
        // --- Création de barre de boutons du bas ---
        JPanel pnlButtons = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
        JButton btnOk = new JButton( "Connect" );
        btnOk.addActionListener( this::connectListener );
        pnlButtons.add( btnOk );
        JButton btnCancel = new JButton( "Cancel" );
        btnCancel.addActionListener( this::cancelListener );
        pnlButtons.add( btnCancel );
        contentPane.add( pnlButtons, BorderLayout.SOUTH );
        
        // --- Affiche la fenêtre ---
        this.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
        this.setSize( 400, 260 );
        this.setLocationRelativeTo( owner );
        this.setVisible( true );
    }
    
    private void pingDatabase( ActionEvent event ) {
        try {
            Class.forName( txtDriverClassName.getText() );
            String url = txtUrl.getText();
            String login = txtLogin.getText();
            String password = txtPassword.getText();
            try ( var connection = DriverManager.getConnection( url, login, password ) ) {
                JOptionPane.showMessageDialog( this, "Ping succedded!" );
            }
        } catch ( Exception exception ) {
            JOptionPane.showMessageDialog( this, "Ping failed!" );
        }
        
    }
    
    private void connectListener( ActionEvent event ) {
        // --- Sauvegarde des données éditées ---
        try ( FileOutputStream fos = new FileOutputStream( CONF_FILENAME ) ) {
            props.setProperty( "jdbc.driver.class", txtDriverClassName.getText() );
            props.setProperty( "jdbc.url", txtUrl.getText() );
            props.setProperty( "jdbc.login", txtLogin.getText() );
            props.setProperty( "jdbc.password", txtPassword.getText() );
            props.store( fos, "JDBC connection data" );

            Class.forName( txtDriverClassName.getText() );
            String url = txtUrl.getText();
            String login = txtLogin.getText();
            String password = txtPassword.getText();
            Connection connection = DriverManager.getConnection( url, login, password );
            ((MainWindow) this.getOwner()).setConnection( connection );
            
            this.dispose();
        } catch ( Exception exception ) {
            exception.printStackTrace();
            JOptionPane.showMessageDialog( this, "Cannot establish connection!" );
        }
    }
    
    private void cancelListener( ActionEvent event ) {
        this.dispose();
    }
}
La classe ConnectionDialog

On intègre les composants graphiques requis dans une fenêtre

Nous allons donc utiliser deux principaux composants d'affichage de données à partir d'une base. Le premier sera basé sur la classe fr.koor.swing.jdbc.KDatabaseTree et permettra d'afficher les tables présentes dans la base de données sélectionnée. Le second, basé sur la classe fr.koor.swing.jdbc.KSqlQueryTable, permettra d'afficher les données stockées dans une table.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 
 126 
 127 
 128 
 129 
 130 
 131 
 132 
 133 
 134 
 135 
 136 
 137 
 138 
 139 
 140 
 141 
package fr.koor.databaseexplorer;

import java.awt.BorderLayout;
import java.net.URL;
import java.sql.Connection;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;

import fr.koor.swing.jdbc.KDatabaseTree;
import fr.koor.swing.jdbc.KDatabaseTree.DatabaseSelectionEvent;
import fr.koor.swing.jdbc.KSqlQueryTable;

public class MainWindow extends JFrame {
    
    private static final long serialVersionUID = 4443303248990993973L;
    
    private Connection connection = null;
    private KDatabaseTree databaseTree = new KDatabaseTree();
    private JDesktopPane desktopPane = new JDesktopPane();

    
    // --- Construction de l'interface graphique ---
    public MainWindow() {
        super( "Database Explorer - KooR.fr - V1.0" );
        this.setSize( 800,500 );
        this.setLocationRelativeTo( null );
        this.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
        
        // --- On récupère le contentPane ---
        JPanel contentPane = (JPanel) getContentPane();

        // --- On ajoute la barre d'outils au nord de la fenêtre ---
        contentPane.add( createToolBar(), BorderLayout.NORTH );
        
        // --- On assemble une arborescence (à gauche) et un JDesktopPane (à droite) avec un JSplitPane ---
        JSplitPane splitPane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, databaseTree, desktopPane );

        // --- On ajout un gestionnaire d'événements pour les clics sur le JTree ---
        databaseTree.addDatabaseSelectionListener( this::createQueryViewer );
        
        // --- On ajoute le SplitPane à la fenêtre ---
        contentPane.add( splitPane, BorderLayout.CENTER );    

        // --- On fixe la connexion à null -> on efface le contenu du JTree ---
        setConnection( null );
    }
    
    private JToolBar createToolBar() {
        JToolBar toolBar = new JToolBar();
        
        JButton btnConnect = new JButton();
        URL url = getClass().getResource( "/images/connect.png" );
        btnConnect.setIcon( new ImageIcon( url ) );
        btnConnect.setToolTipText( "Connect to a database" );
        btnConnect.addActionListener( (e) -> new ConnectionDialog( this ) );
        toolBar.add( btnConnect );

        JButton btnDisconnect = new JButton();
        url = getClass().getResource( "/images/disconnect.png" );
        btnDisconnect.setIcon( new ImageIcon( url ) );
        btnDisconnect.setToolTipText( "Disconnect from the database" );
        btnDisconnect.addActionListener( (e) -> setConnection( null ) );
        toolBar.add( btnDisconnect );

        toolBar.addSeparator();
        
        JButton btnExit = new JButton();
        url = getClass().getResource( "/images/exit.png" );
        btnExit.setIcon( new ImageIcon( url ) );
        btnExit.setToolTipText( "Exit Database Explorer" );
        btnExit.addActionListener( (e) -> dispose() );
        toolBar.add( btnExit );

        return toolBar;
    }
    
    private void createQueryViewer( DatabaseSelectionEvent event ) {
        try {
            String query = "SELECT * FROM " + event.getTableName();
            JInternalFrame internalFrame = new JInternalFrame( "Table " + event.getTableName() );
            KSqlQueryTable queryTable = new KSqlQueryTable();
            queryTable.setConnection( connection );
            queryTable.setQuery( query );
            internalFrame.getContentPane().add( queryTable );
            
            internalFrame.setClosable( true );
            internalFrame.setMaximizable( true );
            internalFrame.setIconifiable( true );
            internalFrame.setResizable( true );
            internalFrame.setSize( 400, 200 );
            //internalFrame.pack();
            
            desktopPane.add( internalFrame );
            internalFrame.setVisible( true );
        } catch( Exception exception ) {
            exception.printStackTrace();
        }
    }
    
    
    public void setConnection( Connection connection ) {

        // --- On ferme toutes les sous-fenêtres ouvertes ---
        for( var frame : this.desktopPane.getAllFrames() ) {
            frame.dispose();
        }

        // --- On la connexion si déjà ouverte ---
        try {
            if ( this.connection != null ) {
                this.connection.close();
            }           
        } catch ( Exception exception ) {
            exception.printStackTrace();
        }
        
        // --- On change la connexion utilisée par l'explorateur de la DB ---
        this.connection = connection;
        this.databaseTree.setConnection( connection );
        
    }
    
    // --- Point d'entrée du programme ---
    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel( new NimbusLookAndFeel() );
        MainWindow frame = new MainWindow();
        frame.setVisible(true);

        new ConnectionDialog( frame );
    }
    
}
La fenêtre principale


KSqlQueryTable - Lister le contenu d'une requête SQL Appliquer un « look'n feel »