12. Progetto [vuejs-10]: plugin [dao], richieste HTTP asincrone
La struttura delle directory del progetto [vuejs-10] è la seguente:

Il progetto [vuejs-10] mostra un componente che effettua una richiesta HTTP a un server remoto. L'architettura utilizzata è la seguente:

Un componente [Vue.js] utilizza il livello [dao] per comunicare con il server di calcolo delle imposte.
12.1. Installazione delle dipendenze
L'applicazione [vuejs-10] utilizza la libreria [axios] per effettuare richieste asincrone al server di calcolo delle imposte. È necessario installare questa dipendenza:

- in [4-5], la riga aggiunta al file [package.json] dopo l'installazione della libreria [axios] [1-3];
12.2. La classe [Dao]
La classe [Dao] è quella sviluppata nella sezione [La classe Dao]. La includiamo qui come riferimento:
'use strict';
// imports
import qs from 'qs'
// dao] class
class Dao {
// manufacturer
constructor(axios) {
this.axios = axios;
// session cookie
this.sessionCookieName = "PHPSESSID";
this.sessionCookie = '';
}
// init session
async initSession() {
// query options HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// URL parameters
params: {
action: 'init-session',
type: 'json'
}
};
// execute query HTTP
return await this.getRemoteData(options);
}
async authentifierUtilisateur(user, password) {
// query options HHTP [post /main.php?action=authenticate-user]
const options = {
method: "POST",
headers: {
'Content-type': 'application/x-www-form-urlencoded',
},
// body of POST
data: qs.stringify({
user: user,
password: password
}),
// URL parameters
params: {
action: 'authentifier-utilisateur'
}
};
// execute query HTTP
return await this.getRemoteData(options);
}
async getAdminData() {
// query options HHTP [get /main.php?action=get-admindata]
const options = {
method: "GET",
// URL parameters
params: {
action: 'get-admindata'
}
};
// execute query HTTP
const data = await this.getRemoteData(options);
// result
return data;
}
async getRemoteData(options) {
// for the session cookie
if (!options.headers) {
options.headers = {};
}
options.headers.Cookie = this.sessionCookie;
// execute query HTTP
let response;
try {
// asynchronous request
response = await this.axios.request('main.php', options);
} catch (error) {
// the [error] parameter is an exception instance - it can take various forms
if (error.response) {
// the server response is in [error.response]
response = error.response;
} else {
// error restart
throw error;
}
}
// response is the entire HTTP response from the server (HTTP headers + response itself)
// retrieve the session cookie if it exists
const setCookie = response.headers['set-cookie'];
if (setCookie) {
// setCookie is an array
// look for the session cookie in this table
let trouvé = false;
let i = 0;
while (!trouvé && i < setCookie.length) {
// look for the session cookie
const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
if (results) {
// the session cookie is stored
// eslint-disable-next-line require-atomic-updates
this.sessionCookie = results[1];
// we found
trouvé = true;
} else {
// next item
i++;
}
}
}
// the server response is in [response.data]
return response.data;
}
}
// class export
export default Dao;
Il progetto [vuejs-10] utilizza solo il metodo asincrono [initSession] nelle righe 18–30. Si noti che la classe [Dao] viene istanziata con un parametro [axios] alla riga 10, che viene inizializzato dal codice chiamante. In questo caso, il codice chiamante è lo script [./main.js].
12.3. Il plugin [pluginDao]
Il plugin [pluginDao] è il seguente:
export default {
install(Vue, dao) {
// ajoute une propriété [$dao] à la classe Vue
Object.defineProperty(Vue.prototype, '$dao', {
// lorsque Vue.$dao est référencé, on rend le 2ième paramètre [dao]
get: () => dao,
})
}
}
Se ricordiamo la spiegazione fornita per il plugin [event-bus], vediamo che il plugin [pluginDao] crea una nuova proprietà chiamata [$dao] nella classe/funzione [Vue]. Questa proprietà avrà (come mostreremo) come valore l'oggetto esportato dallo script [./Dao], ovvero la precedente classe [Dao].
12.4. Lo script principale [main.js]
Il codice dello script principale [main.js] è il seguente:
// imports
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios';
// plugins
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);
// bootstrap
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
// couche [dao]
import Dao from './Dao';
// configuration axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/version-14';
axios.defaults.withCredentials = true;
// instanciation couche [dao]
const dao = new Dao(axios);
// plugin [dao]
import pluginDao from './plugins/dao'
Vue.use(pluginDao, dao)
// configuration
Vue.config.productionTip = false
// instanciation projet [App]
new Vue({
render: h => h(App),
}).$mount('#app')
Lo script [main.js]:
- istanzia il livello [dao] alle righe 14–21;
- include il plugin [pluginDao] alle righe 24–25;
- riga 15: viene importata la classe [Dao];
- righe 17–18: viene configurato l'oggetto [axios], che gestisce le richieste HTTP. Questo oggetto viene importato alla riga 4;
- riga 17: definisce un [timeout] di 2 secondi;
- riga 18: l'URL del server di calcolo delle imposte;
- riga 19: per abilitare lo scambio di cookie con il server;
- righe 24-25: utilizzo del plugin [pluginDao]
- riga 24: importazione del plugin;
- riga 25: integrazione del plugin. Possiamo notare che il secondo parametro del metodo [Vue.use] è il riferimento al livello [dao] definito alla riga 21. Questo è il motivo per cui la proprietà [Vue.$dao] farà riferimento al livello [dao] in tutte le istanze della classe/funzione [Vue], ovvero in tutti i componenti [Vue.js];
12.5. La vista principale [App.vue]
Il codice per la vista principale [App] è il seguente:
<template>
<div class="container">
<b-card>
<!-- message -->
<b-alert show variant="success" align="center">
<h4>[vuejs-10] : plugin [dao], requêtes HTTP asynchrones</h4>
</b-alert>
<!-- composant faisant une requête asynchrone au serveur de calcul d'impôt-->
<Component1 @error="doSomethingWithError" @endWaiting="endWaiting" @beginWaiting="beginWaiting" />
<!-- affichage d'une éventuelle erreur -->
<b-alert show
variant="danger"
v-if="showError">Evénement [error] intercepté par [App]. Valeur reçue = {{error}}</b-alert>
<!-- message d'attente avec un spinner -->
<b-alert show v-if="showWaiting" variant="light">
<strong>Requête au serveur de calcul d'impôt en cours...</strong>
<b-spinner variant="primary" label="Spinning"></b-spinner>
</b-alert>
</b-card>
</div>
</template>
<script>
import Component1 from "./components/Component1";
export default {
name: "app",
// état du composant
data() {
return {
// contrôle le spinner d'attente
showWaiting: false,
// contrôle l'affichage de l'erreur
showError: false,
// l'erreur interceptée
error: {}
};
},
// composants utilisés
components: {
Component1
},
// méthodes de gestion des évts
methods: {
// début attente
beginWaiting() {
// on affiche l'attente
this.showWaiting = true;
// on cache le msg d'erreur
this.showError = false;
},
// fin attente
endWaiting() {
// on cache l'attente
this.showWaiting = false;
},
// gestion d'erreur
doSomethingWithError(error) {
// on note qu'il y a eu erreur
this.error = error;
// on affiche le msg d'erreur
this.showError = true;
}
}
};
</script>
Commenti
- riga 9: [Component1] è il componente che effettua la richiesta HTTP asincrona. Può emettere tre eventi:
- [beginWaiting]: la richiesta sta per essere effettuata. All'utente deve essere visualizzato un messaggio di attesa;
- [endWaiting]: la richiesta è stata completata. L'attesa deve essere interrotta;
- [error]: la richiesta non è andata a buon fine. Deve essere visualizzato un messaggio di errore;
- righe 10–13: l'avviso che visualizza eventuali messaggi di errore. È controllato dal valore booleano [showError] alla riga 33. Visualizza l'errore alla riga 35;
- righe 14–18: l'avviso che visualizza il messaggio di attesa con un indicatore di caricamento. È controllato dal valore booleano [showWaiting] alla riga 47;
- righe 45–50: [beginWaiting] è il metodo eseguito alla ricezione dell'evento [beginWaiting]. Visualizza il messaggio di attesa (riga 47) e nasconde il messaggio di errore (riga 49) nel caso in cui sia ancora visibile da un'operazione precedente;
- righe 52–55: [endWaiting] è il metodo eseguito alla ricezione dell'evento [endWaiting]. Nasconde il messaggio di attesa (riga 54);
- righe 57–62: [doSomethingWithError] è il metodo eseguito alla ricezione dell'evento [error]. Registra l'errore ricevuto (riga 59) e visualizza il messaggio di errore (riga 61);
12.6. Il componente [Component1]
Il codice per il componente [Component1] è il seguente:
<template>
<b-row>
<b-col>
<b-alert show
variant="warning"
v-if="showMsg">Valeur reçue du serveur = {{data}}</b-alert>
</b-col>
</b-row>
</template>
<script>
export default {
name: "component1",
// component status
data() {
return {
showMsg: false
};
},
// event management methods
methods: {
// processing data received from the server
doSomethingWithData(data) {
// record the data received
this.data = data;
// we display it
this.showMsg = true;
}
},
// the component has just been created
created() {
// initialize the session with the server - asynchronous request
// we use the promise rendered by the [dao] layer methods
// we signal the start of the operation
this.$emit("beginWaiting");
// asynchronous operation is launched
this.$dao
// initialize a jSON session with the tax calculation server
.initSession()
// method that processes the data received in the event of success
.then(data => {
// we process the data received
this.doSomethingWithData(data);
})
// error handling method in case of error
.catch(error => {
// the error is traced back to the parent component
this.$emit("error", error.message);
}).finally(() => {
// end of wait
this.$emit("endWaiting");
})
}
};
</script>
Commenti
- righe 4–6: Il componente consiste in un singolo avviso che visualizza il valore restituito dal server di calcolo delle imposte, ma solo se la richiesta HTTP ha esito positivo. Questo avviso è controllato dal valore booleano [showMsg] alla riga 17;
- righe 31–53: La richiesta HTTP viene effettuata non appena il componente viene creato. Pertanto, il relativo codice è inserito nel metodo [created] alla riga 31;
- riga 35: al componente padre viene notificato che la richiesta asincrona sta per iniziare;
- righe 37–39: viene eseguito il metodo [this.$dao.initSession]. Inizializza una sessione JSON con il server di calcolo delle imposte. Il risultato immediato di questo metodo è una [Promise];
- righe 41–44: questo codice viene eseguito quando il server restituisce il risultato senza errori. Il risultato del server si trova in [data]. Alla riga 43, chiamiamo il metodo [doSomethingWithData] per elaborare questo risultato;
- righe 46–49: questo codice viene eseguito se si verifica un errore durante l'esecuzione della richiesta. Alla riga 48, il componente padre viene informato che si è verificato un errore e gli viene passato il messaggio di errore [error.message];
- Righe 49–52: questo codice viene eseguito in tutti i casi. Notifichiamo al componente padre che la richiesta HTTP è completa;
- Righe 23–28: il metodo [doSomethingWithData] è responsabile dell'elaborazione dei dati [data] inviati dal server. Alla riga 25, questi dati vengono memorizzati e alla riga 27 vengono visualizzati;
12.7. Esecuzione del progetto

Se il server di calcolo delle imposte non è in esecuzione al momento del lancio del progetto, si ottiene il seguente risultato:

Avviamo il server [Laragon] (vedi https://tahe.developpez.com/tutoriels-cours/php7) e ricarichiamo la pagina sopra. Il risultato è quindi il seguente:

Nota: stiamo utilizzando la versione 14 del server di calcolo delle imposte definito all'indirizzo https://tahe.developpez.com/tutoriels-cours/php7.