tm.samf.me
Open in
urlscan Pro
2600:9000:2250:ac00:17:a50f:5380:93a1
Public Scan
URL:
https://tm.samf.me/html/requetes_sql.html
Submission: On October 24 via api from US — Scanned from DE
Submission: On October 24 via api from US — Scanned from DE
Form analysis
1 forms found in the DOMGET search.html
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs">
<input type="hidden" name="check_keywords" value="yes">
<input type="hidden" name="area" value="default">
</form>
Text Content
Tutoriel - création d'un forum * Introduction * Présentation * Enjeux * NodeJS côté serveur * Javascript côté client * Socket.io * MySQL * Bootstrap * HTML et CSS * Pré-requis * Installation * NodeJS * Les modules NodeJS * Bootstrap * MySQL * Sur Windows * Sur Mac OSX * Sur Linux * jQuery * Hello World * Les fichiers et dossiers * Code * Résultat * Socket.io * Code côté serveur * Code côté client * Résultat * Requêtes SQL et AJAX * phpMyAdmin * Code * Lecture de données depuis MySQL * avec socket.io * avec EJS * Requêtes AJAX * Base de données * Users * Messages * Discussions * Likes * Session * Quiz * Création de la base de données * TP - page d’accueil * Pistes * Correction * Code côté serveur * Code côté client * Préparation des requêtes SQL * Introduction * Code * Utilisation * Sessions * Introduction * Fonctionnement général * Code * TP - connexion et déconnexion * Pistes * Correction * Code côté serveur * Code côté client * Barre de navigation * TP - création de comptes * Pistes * Correction * Code côté serveur * Code côté client * HTML et EJS * Feuilles de style * Javascript * TP - page de profil * Pistes * Correction * Code côté serveur * Code côté client * HTML et EJS * Feuilles de style * Javascript * TinyMCE * Présentation * Préparation * TP - page de discussions * Pistes * Correction * Routes * Chargement initial de la page * Code côté serveur * Code côté client * Gestion des messages * Code côté serveur * Code côté client * Nouvelles discussions * Code côté serveur * Code côté client * Améliorations * Failles de sécurité * Base de données * Gestion des erreurs * Fonctionnalités complémentaires * Conclusion * Mot final * Annexes * Dépôts bitbucket * Code-source * Code côté serveur * Code côté client * HTML et EJS Tutoriel - création d'un forum * Docs » * Requêtes SQL et AJAX * View page source -------------------------------------------------------------------------------- REQUÊTES SQL ET AJAX¶ Pour apprivoiser le système de requêtes SQL, nous allons insérer une dernière fonctionnalité sur notre Hello World. Note Cette fonctionnalité n’est pas utile en elle-même, mais elle permet de mieux connaître la façon d’exécuter des requêtes SQL dans une base de données et vous prépare ainsi pour la suite de ce tutoriel. Lorsque nous cliquerons sur le bouton de la page d’accueil, l’application enregistrera la date de clic dans une base de données. La page d’accueil affichera toutes les dates de clic et s’actualisera en temps réel. PHPMYADMIN¶ Pour commencer, démarrez votre serveur WAMP, MAMP ou XXAMP (selon votre système d’exploitation) et allez sur la page d’accueil du serveur Apache. Pour ce faire, il cliquez sur le bouton prévu à cet effet depuis l’interface logicielle : Avertissement Il est possible que votre logiciel ne veuille pas se lancer si le port est déjà utilisé par votre serveur node. Pour régler ce problème, il suffit d’aller dans les préférences et de changer le port du serveur Apache : Sur la page principale, vous obtenez les informations nécessaires pour connecter la base de données au script nodeJS : Note Les informations sont les mêmes sur Windows et sur OSX, il y a juste le mot de passe qui change. Sur OSX, le mot de passe par défaut est root et sur Windows, il n’y a pas de mot de passe. Vous pouvez accéder à phpMyAdmin en entrant l’adresse suivante : http://localhost:votre_port/phpMyAdmin. L’interface de cette application apparaît alors. Commençons par créer une base de données toute simple du nom de hello_world pour enregister les dates de clics. Insérons-y une table du nom de “clics” avec deux collones, id et date, sans oublier de cocher la case auto_increment pour le champ id. CODE¶ Maintenant que la base de données est prête, commençons à coder ! Il nous faudra tout d’abord un nouveau fichier du nom de sql.js qui ira dans le dossier serveur. . ├── app.js ├── node_modules ├── serveur │ ├── routes.js │ ├── socket.js │ └── sql.js ├── static └── views Pour éviter de devoir changer à plusieurs endroits les données d’accès à la base de données, nous créons une fonction qui les retourne : ./serveur/sql.js exports.pool = function(mysql) { // informations pour se connecter à la base de données var pool = mysql.createPool({ host : 'localhost', user : 'root', // mettre '' comme mot de passe sur Windows password : 'root', database : 'hello_world', charset : 'UTF8_UNICODE_CI', multipleStatements: true }); // à l'appel de cette fonction, ces informations sont retournées return pool; } Puis, une fonction pour exécuter des requêtes SQL ainsi qu’une autre pour gérer les erreurs : ./serveur/sql.js exports.requete = function(mysql, sql, requete_sql, callback) { // nous récupérons les données de la fonction pool() écrite plus haut // nous utilisons getConnection() pour avoir une connection pool sql.pool(mysql).getConnection(function(err, connection) { /* lorsque nous avons les informations sur cette connection, nous exécutons la requête */ connection.query(requete_sql, function(err, results) { // nous affichons les erreurs, s'il y en a, à l'aide d'une autre fonction sql.query_error(err); /* nous testons l'existence du paramètre callback, qui est facultatif si nous ne voulons pas obtenir le résultat de la requête (par exemple pour les UPDATE) */ if(typeof(callback) !== 'undefined') { // s'il existe, nous renvoyons les résultats dans une fonction de callback callback(results); } // nous libérons la connection pour éviter de surcharger le pool connection.destroy(); }); }); } // cette fonction permet d'afficher une erreur dans la requête SQL exports.query_error = function(erreur) { if (erreur) { console.log('query error : ' + erreur.stack); } } Note Dans la fonction exports.requete, en plus des arguments requete_sql et callback qui contiennent respectivement la requête SQL et la fonction appelée pour retourner les résultats d’une requête, il existe deux autres arguments qui ne sont pas forcément évidents. mysql et sql sont des dépendances nécessaires pour que les instructions effectuées dans la fonction exports.requete s’exécutent correctement. sql contient les fonctions du fichier ./serveur/sql.js (sql.pool en l’occurence) et mysql le module node-mysql qui permet d’exécuter les requêtes SQL. Ensuite, nous entrons dans le fichier socket.js et y insérons une requête SQL qui s’exécutera lorsque le client cliquera sur le bouton. Toutefois, le fichier socket.js doit charger le module node-mysql et le fichier sql.js. Nous ajoutons donc deux paramètres dans sa fonction principale : ./serveur/socket.js exports.f = function(io, mysql, sql) { // ... } Note Les arguments que nous joignons à cette fonction sont obligatoires, car la fonction sql.requete_sql en a besoin, comme nous l’avons vu précédemment. Le fichier app.js doit également contenir d’autres require() pour accéder à ces éléments et les envoyer dans les fichiers socket.js et sql.js : ./app.js var http = require('http'); var path = require('path'); var express = require('express'); // récupération du module node-mysql var mysql = require('mysql'); var app = express(); var server = http.Server(app); var io = require('socket.io')(server); var routes = require('./serveur/routes.js'); var socket = require('./serveur/socket.js'); // récupération des fonctions du fichier sql.js var sql = require('./serveur/sql.js'); routes.f(app, __dirname, mysql, sql); socket.f(io, mysql, sql); server.listen(8888); Note Vous observez que les paramètres sql et mysql ont été ajoutés dans l’appel des fonctions routes.f() et socket.f(). Le fichier sql.js se comporte différemment de routes.js et socket.js ; nous n’appelons pas une fonction principale directement, mais nous donnons aux fonctions principales (socket.f et routes.f) les éléments (ou paramètres) pour appeler les fonctions qui se trouvent dans sql.js. Nous pouvons enfin taper notre requête sql : ./serveur/socket.js // à placer juste après console.log('Le client a cliqué sur le bouton !') var requete_sql = 'INSERT INTO clics(date) VALUES(NOW())'; sql.requete(mysql, sql, requete_sql); Grâce aux fonctions créées précédemment, écrire une requête SQL et l’exécuter ne prend que peu de lignes de code. LECTURE DE DONNÉES DEPUIS MYSQL¶ Chaque fois que l’utilisateur clique sur le bouton, la date du clic est enregistrée dans la base de données. Mais comment récupérer ces dates ? Nous avons deux possibilités : socket.io et EJS. AVEC SOCKET.IO¶ Nous ajoutons une requête SQL pour récupérer les données lorsque le client envoie un message : ./serveur/socket.js socket.on('recuperation_dates', function() { // requête SQL var requete_sql = 'SELECT * FROM clics ORDER BY id'; sql.requete(mysql, sql, requete_sql, function(results) { // le client récupère ensuite les données socket.emit('dates', results); }); }); Ensuite, du côté client, nous formatons les données de la manière suivante : ./views/index.ejs <p>Hello World !</p> <!-- la fonction avertir_serveur() s'exécute lorsque nous cliquons sur ce bouton --> <button class="btn btn-default" onclick="avertir_serveur()"> <span class="glyphicon glyphicon-link"></span> Cliquez ici ! </button><br><br> <!-- ici s'afficheront les dates --> <div id="dates"></div> ./static/js/index.js socket.emit('recuperation_dates'); socket.on('dates', function(results) { // boucle pour parcourir l'array "results" for(var i = 0; i < results.length; i++) { byId('dates').innerHTML += results[i].date + '<br>'; } }); Note Il est important de comprendre comment node-mysql envoie ses données. Elles se trouvent dans un tableau et chaque élément de ce tableau contient des objets portant le nom des champs de la table appelée lors de la requête SQL. Un exemple avec quelques dates : [ { id: 15, date: Tue Jan 12 2016 17:01:10 GMT+0100 (CET) }, { id: 16, date: Tue Jan 12 2016 17:08:46 GMT+0100 (CET) }, { id: 17, date: Tue Jan 12 2016 17:08:46 GMT+0100 (CET) }, { id: 18, date: Tue Jan 12 2016 17:08:47 GMT+0100 (CET) }, { id: 19, date: Tue Jan 12 2016 17:08:47 GMT+0100 (CET) } ] Cette technique fonctionne, mais elle comprend toutefois quelques inconvénients : * Le client charge la page, puis envoie une requête au serveur qui envoie une requête à la base de données, qui renvoie au serveur les informations que le serveur va enfin envoyer au client. Si le verbe “envoyer” est beaucoup utilisé dans la phrase précédente, c’est parce qu’il y a trop de transferts. Ceci aura pour effet de créer un léger délai depuis le moment où la page est chargée et le moment où le contenu s’affiche. * Une fois le contenu d’une requête SQL obtenu sur le client, ce contenu doit être formatté pour qu’il s’affiche sur la page. Ici, nous avons utilisé la propriété .innerHTML avec l’ajout d’un <br> pour créer un retour à la ligne à chaque nouvelle date. Mais admettons que le formatage en HTML soit beaucoup plus conséquent ; avec une classe Bootstrap et des boutons par exemple, nous devrions mettre tout ce code HTML dans une chaîne de caractères Javascript ! Le code HTML se trouverait alors dans un fichier Javascript, ce qui rendrait la modification plus compliquée. Note Cela ne signifie pas que nous ne pouvons pas utiliser socket.io pour transmettre des données ; cette technique doit juste servir à charger de petites informations (comme le nombre de likes d’un post ou le contenu d’un message qui vient d’être modifié) qui ne nécessitent pas beaucoup de formatage. AVEC EJS¶ Mais alors, comment faire pour transférer des données importantes au client ? En utilisant EJS (et AJAX si besoin est). Pour cela, nous créons une nouvelle fonction dans sql.js. Celle-ci permet de récupérer les dates et pour les envoyer à l’aide d’une fonction de callback : ./serveur/sql.js exports.date = function(mysql, sql, callback) { var requete_sql = 'SELECT * FROM clics ORDER BY id'; sql.requete(mysql, sql, requete_sql, function(results) { callback(results); }); } Puis, nous modifions la fonction app.get dans routes.js afin que la date soit retournée au chargement de la page. Pour ce faire, nous ajoutons un objet contenant les résultats de la requête SQL à la fonction res.render() : ./serveur/routes.js // affichage de la page index si on entre localhost/ app.get('/', function(req, res) { sql.date(mysql, sql, function(results) { res.render('index.ejs', { results : results }); }); }); Important Comme nous avons besoin de la variable mysql dans le fichier routes.js, nous devons modifier les paramètres de la fonction principale de ce fichier : ./serveur/routes.js exports.f = function(app, dossier, mysql, sql) { // ... } Les données étant dès lors envoyées avec EJS, il ne reste plus qu’à les traiter dans le fichier index.ejs : ./views/index.ejs <!-- balise à ajouter juste après le bouton "cliquez ici" --> <div id="dates"> <!-- on récupère la variable results qui est envoyée depuis le fichier routes.js --> <% for (var i = 0; i < results.length; i++) { %> <br><%= results[i].date %> <% } %> </div> Avertissement Il faut bien différencier les <% des <%= lorsque vous utilisez EJS. Les <%= permettent d’écrire le contenu d’une variable EJS sur la page, tandis que les <% décrivent simplement une instruction EJS (comme une fonction, une boucle...). Dans les deux cas, la fin d’une instruction EJS se termine par %>. Si nous testons le code, nous obtenons, après quelques clics sur le bouton et un rechargement de page, le résultat suivant : Mais il y a un inconvénient : il est nécessaire de recharger la page pour que les dates de clic s’actualisent. Et nous aimerions une application “en temps réel”, donc sans de telles contraintes. Socket.io et AJAX sont donc notre solution. REQUÊTES AJAX¶ Tout d’abord, un petit rappel sur cette technologie : AJAX est similaire à socket.io ; il fonctionne de manière asynchrome et fait aussi des requêtes. Ce système permet, entre autres, d’enregister le contenu d’une page web dans une variable. Cela fonctionne comme un chargement “interne”, sans avoir besoin de raffraîchir complètement la page web du client. Concrètement, dans cet exemple, nous utiliserons AJAX pour aller chercher une page créée avec EJS et l’insérer dans la page web actuelle. La page créée avec EJS contiendra la dernière date entrée dans la base de données. La requête AJAX s’exécutera lorsque socket.io dira au client “quelqu’un a cliqué sur le bouton”. Note Comme le résultat de la requête SQL n’est pas long (c’est juste une date), nous pourrions nous contenter d’utiliser socket.io pour charger la dernière date. Mais nous le ferons avec socket.io + EJS + AJAX pour être ensuite capable reproduire cette méthode pour des requêtes plus conséquentes. D’abord, nous créons une nouvelle page web (derniere_date.ejs) dans le dossier views. Dans celle-ci, nous insérons le code suivant : ./views/derniere_date.ejs <!-- avec cette condition, la page derniere_date retourne quelque chose seulement si la requête SQL retourne un résultat --> <% if (typeof(results[0].date) !== 'undefined') { %> <!-- nul besoin de parcourir une boucle puisqu'il n'y aura qu'un seul résultat à la requête SQL --> <br><%= results[0].date %> <% } %> Note Le terme “page web” n’est pas tout-à-fait exact pour désigner derniere_date. Il s’agit plutôt d’une partie d’une page web, puisque son code ne contient pas de balise <!DOCTYPE html>. Ensuite, nous modifions la fonction qui récupère les dates (qui se trouve dans sql.js) pour qu’elle fasse une requête avec la dernière date lorsqu’on le lui demande : .serveur/sql.js exports.date = function(mysql, sql, callback, derniere_date) { // teste si l'attribut derniere_date est true ou false if (!derniere_date) { var requete_sql = 'SELECT * FROM clics ORDER BY id'; } else { // nous demandons de choisir le premier élément dans // l'ordre décroissant, c'est-à-dire le dernier élément var requete_sql = 'SELECT * FROM clics ORDER BY id DESC LIMIT 0,1' } sql.requete(mysql, sql, requete_sql, function(results) { callback(results); }); } Puis, nous ajoutons une route pour charger le fichier derniere_date.ejs en lui envoyant le retour de la requête SQL : ./serveur/routes.js app.get('/derniere_date', function(req, res) { sql.date(mysql, sql, function(results) { res.render('derniere_date.ejs', { results : results }); }, true); }); Avertissement Il faut insérer cet app.get() avant celui qui s’occupe de charger la page d’erreur. Sinon, derniere_date.ejs ne se chargera jamais. A présent, en allant sur http://localhost:8888/derniere_date, vous voyez apparaître la dernière date de clic. Mais pour l’afficher dans la page, nous devons encore écrire un peu de code. Il faut créer une fonction dans index.js qui s’occupera de récupérer le contenu de la page derniere_date.ejs pour l’afficher dans la page index.ejs lorsque socket.io le lui demandera. ./static/js/index.js socket.on('charger_derniere_date', function() { var xhr = new XMLHttpRequest(); xhr.open('GET', 'derniere_date'); xhr.addEventListener('readystatechange', function() { if (xhr.readyState === 4 && xhr.status === 200) { // on ajoute le contenu de derniere_date.ejs aux dates existantes byId('dates').innerHTML += xhr.responseText; // rappel : byId() = document.getElementById() } }); xhr.send(null); }); Note Si vous ne comprenez pas complètement ce code, c’est tout à fait normal. Il utilise XMLHttpRequest, qui est l’implémentation d’AJAX en dans le moteur javascript du navigateur web. Nous n’utiliserons pas des fonctionnalités plus poussées d’AJAX dans cette application, mais si vous souhaitez mieux connaître le fonctionnement de XMLHttpRequest, vous pouvez consulter cette page qui explique, entre autres, ce bout de code. Il ne reste plus qu’à écrire un socket.emit() dans socket.js : ./serveur/socket.js socket.on('bouton_client', function() { console.log('Le client a cliqué sur le bouton !') var requete_sql = 'INSERT INTO clics(date) VALUES(NOW())'; sql.requete(mysql, sql, requete_sql); // avec la fonction socket.emit le client actuel charge la nouvelle date socket.emit('charger_derniere_date'); /* avec la fonction socket.broadcast.emit, la nouvelle date est également envoyée aux autres clients */ socket.broadcast.emit('charger_derniere_date'); }); Et voilà ! Désormais, lorsque vous cliquez sur le bouton, la nouvelle date de clic apparaît directement à la suite des autres. Astuce Vous pouvez télécharger le programme actuel en cliquant sur les liens ci-dessous : * Programme utilisant socket.io * Programme utilisant AJAX Next Previous -------------------------------------------------------------------------------- © Copyright 2015-2016, <Samuel Fringeli>. Built with Sphinx using a theme provided by Read the Docs.