React:Utilisateur inscription+ upload file

Afin de créer un projet crud pour gérer les utilisateurs on besoin de créer deux type de projet:
Dans cette partie on va créer un projet avec Nodejs+ExpressJS+Mysql afin de créer les RestApi pour :
- 1GET http://localhost:8081/utilisateurs :Afficher la liste des utilisateurs
- 2POST:http://localhost:8081/utilisateurs/ajouter Ajouter un utilisateur
- 3Delete:http://localhost:8081/utilisateurs/:id :Supprimer un utilisateur passé en paramètre
- 4PUT: http://localhost:8081/utilisateurs/id/modifier :Modifier un utilisateur passé en paramètres
Installer le module mysql
Un projet nodeJs utilise plusieurs bibiothèque javasript nommées modules
Afin de travailer avec mysql on doit installer le module mysql
npm install mysql2 --save
Installer ExpressJs
npm install express --save
Installer express-fileupload
npm install express-fileupload
4.Créer le fichier dabase/creerTableUtilisateur.js
/*Importer le module mysql qui permet de gérer les transaction dans une base de données mysql */
var mysql = require('mysql2');
/*se connecter à la base de données crée puis créer les tables */
var con = mysql.createConnection({
host: "localhost", /*le serveur de la base de données*/
user: "root", /*Utilisateur de la base de données*/
password: "",/*le mot de passe de l'utilisateur de la base de données*/
port: "8111", /*le serveur de la base de données*/
database: "databaseReact" /*le nom de la base de données à Créer manullement*/
});
//se connecter en utlisant con crée
con.connect(function(err) {
/*err:contient error de connexion*/
/*afficher erreur de connexion s'il existe*/
if (err) throw err;
/*pas d'erreur donc on peut exécuter des requête sql */
/*Créer la table utilisateurs */
var sql = "CREATE TABLE utilisateurs(id int primary key auto_increment,nom varchar(25),email varchar(25),photo varchar(100),password varchar(25),active boolean default 0)";
/*Exécuter la requete sql crée*/
con.query(sql, function (err, result) {
if (err) throw err;
console.log("Table utilisateurs est crée");
});
});
5.Exécuter le script SQL pour créer la base de données
node database/creeTableUtilisateur.js
1.Créer le fichier config/config.js de configuration de la connexion à la base de données
var mysql = require('mysql2');
var connection = mysql.createConnection({
host: "localhost", /*le serveur de la base de données*/
port:"3306",/*le port du service mysql*/
user: "root", /*Utilisateur de la base de données*/
password: "",/*le mot de passe de l'utilisateur de la base de données*/
database: "databaseReact" /*le nom de la base de données à Créer manullement*/
});
//connexion à la base de données
connection.connect(function(error){
if(!!error) {
console.log(error);
} else {
console.log('Connected..!');
}
});
module.exports = connection;
3.Créer le dossie src contenant le code source de l'applications
Afin d'organiser le projet on besoin de créer les dossiers suivants
- src/models :contenant les model du projet utilisateur ,utilisateur et ses fonctions de CRUD
- src/routes :contenant le mapping entre les requêtes http est la méthode à exécuter
- src/controllers :contient les méthode à exécutée selon chaque route reçues
Model: Créer le fichier src/models/Utilisateur.js
Ce fichier représente le module de l'entité utilisateur(id,nom,email,password,photo,active) contenant:
- Un objet Utilisateur
- Les fonctions CRUD:
- insert
- update
- delete
- detail
/*importer le fichier de configuration de connexion à la base de données*/
var connexion = require('./../../config/config');
/*Créer un objet de type Utilisateur*/
var Utilisateur = function(utilisateur){
this.id = utilisateur.id;
this.nom = utilisateur.nom;
this.email = utilisateur.email;
this.password = utilisateur.password;
this.photo = utilisateur.photo;
this.active = utilisateur.active;
};
/**1.insert**/
/*Ajouter à l'objet Utilisateur la fonction insert qui permet d'ajouter un utilisateur dans la table utilisateur*/
Utilisateur.insert = function (utilisateur, result) {
/*utilisateur :sera renseigner par le controlleur contenant l'objet à insérer dans la table utilisateur
result:un objet qui contiendra la réponse à envoyer au controlleur :UtilisateurController
*/
/*Exécuter la requêtes SQL insert into utilisateur*/
connexion.query("INSERT INTO utilisateurs set ?", utilisateur, function (err, res) {
/*
function (err, res):la méthode de callback sera exécuté aprés l'exécution de la commande insert into
err:contient l'erreur sql reçu
res:contient la reponse de la methode query
*/
/*Si la fonction query délenche une erreur*/
if(err) {
console.log("error: ", err);
result(err, null);
}
/*Si la fonction query s'exécute sans erreur on envoie res.insertId :c'est la valeur de la primary key de l'objet inséré */
else{
console.log(res.insertId);
result(null, res.insertId);
}
});
}
/*Exporter la classe pour pouvoir l'importer dans le controller */
module.exports= Utilisateur;
Controller: Créer le fichier src/controllers/UtilisateurController.js
Permet de gérer la communication entre le model Utilisateur et les et le projet React :frontEndProject
const UtilisateurModel = require('../models/Utilisateur');
/*Permet de gérer les chemin des dossier et les fichiers*/
var path = require("path");
/*Insérer un nouveau utilisateur dans la table utilisateur*/
exports.insert = (req, res) =>{
if(req.body.constructor === Object && Object.keys(req.body).length === 0){
res.send(400).send({success: false, message: 'Erreur tous les champs sont obligatoires'});
}else{
/*Récupérer le fichier son nom */
const file = req.files.file;
const fileName = file.name;
/*Récupérer l'objet utisateur envoyé par React :
const formData = new FormData();
formData.append("file", file);
formData.append("fileName", file.name);
formData.append("userInfo", JSON.stringify(utilisateur));
*/
let utilisateur_nouveau=JSON.parse(req.body.userInfo);
/*se positionner dans la racine du proejt*/
let chemin=path.join(__dirname, '..', '..');
chemin = chemin+ "\\public\\photo_Utilisateurs\\";
/*file.move file to chemin*/
file.mv(chemin+"\\"+fileName, (err) => {
if (!err) {
/*Ajouter photo à l'objet utilisateur reçu*/
utilisateur_nouveau.photo="photo_Utilisateurs/"+fileName;
/*Appler la méthode insert du UtilisateurModel*/
UtilisateurModel.insert(utilisateur_nouveau, (err, utilisateur)=>{
if(err)
/*si erreur*/
res.json({status: false, message: 'Erreur Utilisateur non ajouté', data: null})
/*si OK*/
res.json({status: true, message: 'Le utilisateur est bien ajoute', data: utilisateur.insertId})
});
}
else
{
res.json({status: false, message: 'Erreur du fichiernon ajouté', data: null})
}
});
}
}
Routes: Créer le fichier src/routes/UtilisateurRoutes.js
/*importer express js pour manipuler les routes*/
const express = require('express');
/*importer le module Router de express js*/
const routerUtilisateurs = express.Router();
/*imporer utilisateurController*/
const utilisateurController = require('../controllers/UtilisateurController');
/*la route:=> utilisateurs/ajouter ,avec la méthode POST
ajouterValider:=>la fonction du UtilisateurController qui permet d'insérer un utilisateur dans la table utilisateur*/
routerUtilisateurs.post('/ajouter', utilisateurController.insert);
module.exports = routerUtilisateurs
Serveur Nodejs: modifier le fichier Serveur.js
Permettant de demarer le serveur des APIs
Installer cors
const express = require('express');
const bodyParser = require('body-parser');
const fileupload = require("express-fileupload");
/*Pemert d'authoriser la consommation des api à partir d'un autre serveur
dans ce cas projet React */
const cors = require('cors');
const app = express();
/*activer le cros domaine */
app.use(cors())
/*activer fileupload*/
app.use(fileupload());
/*Définir le dossier /public en tant qu'un dossier public So on a pas besoin de passer par
le controller afin d'afficher son contenu
*/
app.use('/public', express.static('public'))
const port = 8081;
// activer le traitement des request de type application/x-www-form-rulencoded
app.use(bodyParser.urlencoded({extended: false}));
//activer le traitement des request de type application/json
app.use(bodyParser.json());
//importer le fichier de routage pour le produit
const routerProduits = require('./src/routes/ProduitRoutes');
/*Créer les apis pour Produit*/
app.use('/apis/produits/', routerProduits);
//importer le fichier de routage pour les utilisateurs
const routerUtilisateurs = require('./src/routes/UtilisateurRoutes');
/*Créer les apis pour Utiliatuer*/
app.use('/apis/utilisateurs/', routerUtilisateurs);
/*Démarer le serveur backEnd*/
app.listen(port, ()=>{
console.log('Backend is live port : 8081');
});
Installer bootstrap
Installer Axios
npm install react-hook-form
Créer la component inscription.js
import React, { useState } from "react";
import axios from "axios";
import { useForm } from 'react-hook-form';
/*Permet de vérifier la puissance du mot de passe saisie*/
import PasswordStrengthBar from 'react-password-strength-bar';
function Inscription() {
/*un objet utilisateur qui sera rempli par le formulaire puis envoyer au backend*/
const [utilisateur,setUtilisateur]=useState({
id: null,
email: "",
photo: "",
password: "",
active:0
});
/*un objet qui contiendra le <input type="file"*/
const [file, setFile] = useState();
/*pour stocker la reponse du backend*/
const [message,setMessage]=useState("");
const [statusResponse,setStatusResponse]=useState("");
/*Stocker les valeur saisie de l'utilisateur*/
const inputChange = e => {
/*Récupérer l'input changé*/
const { name, value } = e.target;
/*Modifier dans le state l'attirb utUtilisateur changé*/
setUtilisateur(prevUtilisateur => ({
...prevUtilisateur,/*Récupérer l'ancien objet*/
[name]: value /*changé la valeur de l'attribut :<input name="nom" ou name="prenom"*/
}));
};
/*UseFrom fonction */
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
/*Envoyer un nouveau produit*/
const inscription_Utilisateur = async e => {
/*Création d'une formData pour l'envoyer au backend*/
const formData = new FormData();
formData.append("file", file);
formData.append("fileName", file.name);
formData.append("userInfo", JSON.stringify(utilisateur));
/*Appeler le backend en envoyant les données*/
await axios.post('http://localhost:8081/apis/utilisateurs/ajouter', formData)
.then(response => {
/*recevoir la réponse du backend*/
setStatusResponse(response.data.status);
setMessage(response.data.message);
/*le produit est bien ajouté initialiser les input et l'objet produit du sate*/
if(statusResponse==true)
{
setUtilisateur( {
id: "",
email: "",
photo: "",
password: "",
active:0
}
);
}
});
};
let couleur="";
if (statusResponse==true) {
couleur ="alert alert-success";
}
if (statusResponse==false) {
couleur ="alert alert-danger";
}
return (
<div className="container">
<form onSubmit={handleSubmit(inscription_Utilisateur)}>
<div className="row">
<fieldset className="border p-2">
<legend className="w-auto">Inscription Utilisateur</legend>
{/*Afficher le message si on a reçu une reponse serveur*/}
{message.length > 0 &&
<div className={ couleur} role="alert">
{message}
</div>
}
<div className="form-group mb-3">
<input
{...register("nom", {
required: 'Le nom est obligatoires'
})}
type="text"
className="form-control"
placeholder="Enter le nom"
name="nom"
value={utilisateur.nom}
onChange={e => inputChange(e)}/>
{errors?.nom &&
<span className="alert-danger">
errors.nom.message
</span>
}
</div>
<div className="form-group mb-3">
<input
{...register("email", {
required: "Required",
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: "invalid email address"
}})
}
type="email"
className="form-control"
placeholder="Enter l'email"
name="email"
value={utilisateur.email}
onChange={e => inputChange(e)} />
{/*Afficher le message de la validation */}
{errors?.email &&
<span className="alert-danger">
errors.email.message
</span>
}
</div>
<div className="form-group mb-3">
<input
{...register("password", {
required: 'Le password est obligatoires'
})}
type="password"
className="form-control"
placeholder="Enter le password"
name="password"
value={utilisateur.password}
onChange={e => inputChange(e)} />
{/*afficher la degré de complexité du mot de passe*/}
<PasswordStrengthBar password={utilisateur.password} />
{errors?.password &&
<span className="alert-danger">
errors.password.message
</span>
}
</div>
<div className="form-group mb-3">
<input
{...register("fichier", {
required: 'Le fichier est obligatoires'
})}
type="file"
className="form-control"
name="fichier"
onChange={(e) => setFile(e.target.files[0])}/>
{errors?.fichier &&
<span className="alert-danger">
errors.fichier.message
</span>
}
</div>
<input type="submit" onClick={inscription_Utilisateur} className="btn btn-secondary btn-block" value="Valider"/>
</fieldset>
</div>
</form>
</div>
);
}
export default Inscription;
Ajouter une route dans le fichier App.js
import './App.css';
/*des classe qui permet de créer des routes pour
/produits/ajouter/
/produits/
....
*/
import {
BrowserRouter as Router,
Route,
Routes
} from "react-router-dom";
/*importer les styles boostrap*/
import 'bootstrap/dist/css/bootstrap.min.css';
/*Importer les components*/
import Ajouter from './components/Produits/ajouter/ajouter.js'
import ListeProduitAvecDatatable from './components/Produits/ListeProduitAvecDatatable/ListeProduitAvecDatatable.js'
import ListePagination from './components/Produits/listePagination/listePagination.js'
import Liste from './components/Produits/liste/liste.js'
import Details from './components/Produits/details/details.js'
import Navigation from './components/navigation/navigation.js'
import Rechercher from './components/Produits/rechercher/rechercher.js'
import ListeLoadMore from './components/Produits/listeLoadMore/listeLoadMore.js'
import Inscription from './components/Utilisateurs/inscription/inscription.js'
function App() {
return (
<div>
{/*Définir un router */}
<Router>
<Navigation/>
<Routes>
<Route exact path="/produits/" element={<Liste/>}/>
<Route exact path="/produits/ajouter" element={<Ajouter/>}/>
<Route exact path="/produits/:id" element={<Details/>}/>
<Route exact path="/produitsListe" element={<ListePagination/>}/>
<Route exact path="/produitsDatatable" element={<ListeProduitAvecDatatable/>}/>
<Route exact path="/Rechercher" element={<Rechercher/>}/>
<Route exact path="/ListeLoadMore" element={<ListeLoadMore/>}/>
<Route exact path="/utilisateurs/inscription" element={<Inscription/>}/>
</Routes>
</Router>
</div>
);
}
export default App;