Oefening: een algemene webtoepassing maken
Tot nu toe hebt u MongoDB en Node.js geïnstalleerd op uw virtuele Ubuntu-machine (VM). Nu is het tijd om een eenvoudige webtoepassing te maken om te zien hoe alles werkt. Onderweg ziet u hoe AngularJS en Express passen.
Oefening is een uitstekende manier om vertrouwd te raken met de materie. De webtoepassing die u bouwt, implementeert een eenvoudige boekdatabase. Met de webtoepassing kunt u informatie weergeven over boeken, nieuwe boeken toevoegen en bestaande boeken verwijderen.
De webtoepassing die u hier ziet, toont veel concepten die van toepassing zijn op de meeste MEAN-stack-webtoepassingen. U kunt de functies die u nodig hebt om uw eigen MEAN-stacktoepassingen te bouwen, verkennen op basis van uw behoeften en interesses.
De webtoepassing Books ziet er als volgt uit.
Hier ziet u hoe elk onderdeel van de MEAN-stack in de toepassing past.
- MongoDB bevat informatie over boeken.
- Express.js stuurt elke HTTP-aanvraag naar de juiste handler.
- AngularJS verbindt de gebruikersinterface met de bedrijfslogica van het programma.
- Node.js fungeert als host voor de toepassing aan serverzijde.
Belangrijk
Voor educatieve doeleinden bouwt u hier een eenvoudige webtoepassing. Het doel hiervan is het testen van uw MEAN-stack en om u een idee te geven van hoe dit werkt. De toepassing is niet voldoende veilig of gereed voor productiegebruik.
Hoe zit het met Express?
Tot nu toe hebt u MongoDB en Node.js op uw VIRTUELE machine geïnstalleerd. Hoe zit het met Express.js, de E in het MEAN-acroniem?
Express.js is een webserverframework dat is gebouwd voor Node.js dat het proces voor het bouwen van webtoepassingen vereenvoudigt.
Het belangrijkste doel van Express is het afhandelen van routering van aanvragen.
Routering verwijst naar de manier waarop de toepassing op een aanvraag naar een bepaald eindpunt reageert. Een eindpunt bestaat uit een pad of URI en een aanvraagmethode zoals GET of POST. U kunt bijvoorbeeld reageren op een GET-aanvraag naar het eindpunt /book
door de lijst met alle boeken in de database op te geven. U kunt reageren op een POST-aanvraag voor het /book
eindpunt door een vermelding toe te voegen aan de database op basis van velden die de gebruiker heeft ingevoerd in een webformulier.
In de webtoepassing die u binnenkort bouwt, gebruikt u Express om HTTP-aanvragen te routeren en webinhoud terug te sturen naar uw gebruiker. Met Express kunt u er ook voor zorgen dat webtoepassingen werken met HTTP-cookies en querytekenreeksen verwerken.
Express is een Node.js-pakket. U gebruikt het npm-hulpprogramma, dat wordt geleverd met Node.js, om Node.js-pakketten te installeren en te beheren. Verderop in deze les maakt u een bestand met de naam package.json
Express en andere afhankelijkheden en voert u vervolgens de npm install
opdracht uit om deze afhankelijkheden te installeren.
Hoe zit het met AngularJS?
Net als Express is AngularJS, de A in het MEAN-acroniem, nog niet geïnstalleerd.
Met AngularJS kunt u webtoepassingen gemakkelijker schrijven en testen, omdat u hiermee het uiterlijk van uw webpagina (uw HTML-code) beter kunt scheiden van hoe uw webpagina zich gedraagt. Als u bekend bent met het MVC-patroon (model-view-controller) of het concept van gegevensbinding, moet u vertrouwd zijn met AngularJS.
AngularJS is een front-end JavaScript-framework, wat betekent dat het alleen beschikbaar moet zijn op de client die toegang heeft tot de toepassing. Met andere woorden, AngularJS wordt uitgevoerd in de webbrowser van uw gebruiker, niet op uw webserver. En omdat AngularJS JavaScript is, kunt u hiermee eenvoudig gegevens ophalen van uw webserver om deze weer te geven op de pagina.
U installeert AngularJS niet echt. In plaats daarvan voegt u een verwijzing naar het JavaScript-bestand in uw HTML-pagina toe, net zoals bij andere JavaScript-bibliotheken. Er zijn verschillende manieren om AngularJS op te nemen in uw webpagina's. Hier laadt u AngularJS vanuit een CDN (Content Delivery Network). Een CDN is een manier om afbeeldingen, video en andere inhoud geografisch te distribueren om de downloadsnelheden te verbeteren.
Voeg deze code nog niet toe, maar hier volgt een voorbeeld waarmee AngularJS vanuit een CDN wordt geladen. Normaal gesproken voegt u deze code toe aan de <head>
sectie van uw HTML-pagina.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
Notitie
Let op: AngularJS is niet hetzelfde als Angular. Veel concepten zijn weliswaar vergelijkbaar, maar in feite is AngularJS de voorloper van Angular. AngularJS wordt nog altijd veel gebruikt voor het bouwen van webtoepassingen. Terwijl AngularJS is gebaseerd op JavaScript, is Angular gebaseerd op TypeScript, een programmeertaal waarmee u eenvoudiger JavaScript-programma's kunt schrijven.
Hoe kan ik de toepassing bouwen?
Hier gebruikt u een basisproces. U schrijft toepassingscode vanuit De Cloud Shell en gebruikt vervolgens SCP (Secure Copy Protocol) om de bestanden naar uw VIRTUELE machine te kopiëren. Vervolgens start u de Node.js toepassing en ziet u de resultaten in uw browser.
In de praktijk schrijft en test u uw webtoepassing doorgaans in een meer lokale omgeving, zoals vanaf uw laptop of vanaf een virtuele machine die u lokaal uitvoert. Mogelijk slaat u uw code op in een versiebeheersysteem zoals Git. Gebruik vervolgens een CI/CD-systeem (continue integratie en continue levering), zoals Azure DevOps, om uw wijzigingen te testen en te uploaden naar uw VM. We verwijzen u naar meer resources aan het einde van deze module.
De webtoepassing voor boeken maken
Hier maakt u alle code-, script- en HTML-bestanden waaruit uw webtoepassing bestaat. Ter beknoptheid markeren we de belangrijke onderdelen van elk bestand, maar gaan we niet in volledige details.
Als u nog steeds verbinding hebt met uw virtuele machine via SSH, voert u exit
uit om de SSH-sessie te verlaten en terug te keren naar de Cloud Shell.
exit
U bent nu terug bij uw Cloud Shell-sessie.
De bestanden maken
Voer vanuit Cloud Shell deze opdrachten uit om de mappen en bestanden voor uw webtoepassing te maken:
cd ~ mkdir Books touch Books/server.js touch Books/package.json mkdir Books/app touch Books/app/model.js touch Books/app/routes.js mkdir Books/public touch Books/public/script.js touch Books/public/index.html
De webtoepassing bevat de volgende mappen en bestanden:
-
Books
is de hoofdmap van het project.-
server.js
definieert het toegangspunt voor de webtoepassing. Hiermee worden de vereiste Node.js-pakketten geladen, wordt opgegeven op welke poorten moet worden geluisterd en wordt geluisterd naar binnenkomend HTTP-verkeer. -
package.json
bevat informatie over uw toepassing, zoals de naam, de beschrijving en de Node.js-pakketten die nodig zijn om de toepassing te kunnen uitvoeren.
-
-
Books/app
bevat de code die wordt uitgevoerd op de server.-
model.js
definieert de databaseverbinding en het schema. U kunt het zien als het gegevensmodel voor uw toepassing. -
routes.js
verwerkt routeringsaanvragen. Hiermee worden bijvoorbeeld GET-aanvragen naar het eindpunt/book
gedefinieerd door de lijst met alle boeken in de database op te geven.
-
-
Books/public
bevat bestanden die rechtstreeks aan de clientbrowser worden aangeboden.-
index.html
bevat de indexpagina. Het bevat een webformulier waarmee de gebruiker informatie over boeken kan invoeren. Ook worden hier alle boeken in de database weergegeven. Hier kunt u tevens vermeldingen in de database verwijderen. -
script.js
bevat JavaScript-code die wordt uitgevoerd in de browser van de gebruiker. Het kan aanvragen verzenden naar de server om de lijst met boeken weer te geven, boeken aan de database toe te voegen en boeken uit de database te verwijderen.
-
-
Voer de opdracht
code
uit om uw bestanden via de Cloud Shell-editor te openen.code Books
Het gegevensmodel maken
Open
app/model.js
en voeg de volgende code toe vanuit de editor:var mongoose = require('mongoose'); var dbHost = 'mongodb://localhost:27017/Books'; mongoose.connect(dbHost, { useNewUrlParser: true } ); mongoose.connection; mongoose.set('debug', true); var bookSchema = mongoose.Schema( { name: String, isbn: {type: String, index: true}, author: String, pages: Number }); var Book = mongoose.model('Book', bookSchema); module.exports = Book;
Belangrijk
Wanneer u code in een bestand in de editor plakt of wijzigt, moet u niet vergeten het bestand vervolgens op te slaan met behulp van het menu '...' of de sneltoets (Ctrl+S in Windows en Linux, Command+S in macOS).
Deze code maakt gebruik van Mongoose om de gegevensoverdracht in en uit MongoDB te vereenvoudigen. Mongoose is een schemasysteem voor het modelleren van gegevens. Met de code wordt een databasedocument met de naam 'Boek' gedefinieerd met het opgegeven schema. In het schema zijn vier velden gedefinieerd waarmee één boek wordt beschreven:
- De naam van het boek
- Het International Standard Book Number (ISBN) dat het boek uniek identificeert
- De auteur
- Het aantal pagina's
Vervolgens maakt u HTTP-handlers die GET-, POST- en DELETE-aanvragen toewijzen aan databasebewerkingen.
De Express.js routes maken die HTTP-aanvragen verwerken
Open
app/routes.js
en voeg de volgende code toe vanuit de editor:var path = require('path'); var Book = require('./model'); var routes = function(app) { app.get('/book', function(req, res) { Book.find({}, function(err, result) { if ( err ) throw err; res.json(result); }); }); app.post('/book', function(req, res) { var book = new Book( { name:req.body.name, isbn:req.body.isbn, author:req.body.author, pages:req.body.pages }); book.save(function(err, result) { if ( err ) throw err; res.json( { message:"Successfully added book", book:result }); }); }); app.delete("/book/:isbn", function(req, res) { Book.findOneAndRemove(req.query, function(err, result) { if ( err ) throw err; res.json( { message: "Successfully deleted the book", book: result }); }); }); app.get('*', function(req, res) { res.sendFile(path.join(__dirname + '/public', 'index.html')); }); }; module.exports = routes;
Met deze code worden vier routes gemaakt voor de toepassing. Hier volgt een kort overzicht van elke route.
HTTP-woord Eindpunt Beschrijving GET /book
Hiermee haalt u alle boeken uit de database op. POSTEN /book
Hiermee maakt u een Book
-object op basis van de velden die de gebruiker heeft opgegeven in het webformulier. Vervolgens wordt het object naar de database geschreven.DELETE /book/:isbn
Hiermee verwijdert u het boek op basis van het ISBN uit de database. GET *
Hiermee retourneert u de indexpagina indien geen andere route overeenkomt. Express.js http-antwoorden rechtstreeks in de routeverwerkingscode kan verwerken, of statische inhoud uit bestanden kan verwerken. In deze code ziet u beide. De eerste drie routes retourneren JSON-gegevens voor boek-API-aanvragen. De vierde route (standaard) retourneert de inhoud van het indexbestand
index.html
.
De JavaScript-clienttoepassing maken
Open
public/script.js
in de editor en voeg de volgende code toe:var app = angular.module('myApp', []); app.controller('myCtrl', function($scope, $http) { var getData = function() { return $http( { method: 'GET', url: '/book' }).then(function successCallback(response) { $scope.books = response.data; }, function errorCallback(response) { console.log('Error: ' + response); }); }; getData(); $scope.del_book = function(book) { $http( { method: 'DELETE', url: '/book/:isbn', params: {'isbn': book.isbn} }).then(function successCallback(response) { console.log(response); return getData(); }, function errorCallback(response) { console.log('Error: ' + response); }); }; $scope.add_book = function() { var body = '{ "name": "' + $scope.Name + '", "isbn": "' + $scope.Isbn + '", "author": "' + $scope.Author + '", "pages": "' + $scope.Pages + '" }'; $http({ method: 'POST', url: '/book', data: body }).then(function successCallback(response) { console.log(response); return getData(); }, function errorCallback(response) { console.log('Error: ' + response); }); }; });
U ziet hoe deze code een module met de naam
myApp
en een controller definieert met de naammyCtrl
. We gaan hier verder niet in op de werking van modules en controllers. U gebruikt deze namen in de volgende stap om de gebruikersinterface (HTML-code) te koppelen aan de bedrijfslogica van de toepassing.Eerder hebt u vier routes gemaakt waarmee verschillende GET-, POST- en DELETE-bewerkingen op de server worden verwerkt. Deze code lijkt op deze bewerkingen, maar dan vanaf de clientzijde (de webbrowser van de gebruiker).
Met de functie
getData
wordt bijvoorbeeld een GET-aanvraag verzonden naar het/book
-eindpunt. Zoals u weet, verwerkt de server deze aanvraag door informatie over alle boeken uit de database op te halen en die informatie als JSON-gegevens in het antwoord te retourneren. U ziet hoe de JSON-gegevens in het antwoord worden toegewezen aan de$scope.books
variabele. In de volgende stap leert u hoe deze code van invloed is op wat de gebruiker op de webpagina ziet.Deze code roept de functie
getData
aan wanneer de pagina wordt geladen. U kunt de functiesdel_book
enadd_book
controleren om een idee te krijgen van hun werking. U hebt geen code aan de clientzijde nodig om overeen te komen met de standaardhandler van de server, omdat de standaardhandler de indexpagina retourneert en geen JSON-gegevens.
De gebruikersinterface maken
Open
public/index.html
in de editor en voeg de volgende code toe:<!doctype html> <html ng-app="myApp" ng-controller="myCtrl"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script> <script src="script.js"></script> </head> <body> <div> <table> <tr> <td>Name:</td> <td><input type="text" ng-model="Name"></td> </tr> <tr> <td>Isbn:</td> <td><input type="text" ng-model="Isbn"></td> </tr> <tr> <td>Author:</td> <td><input type="text" ng-model="Author"></td> </tr> <tr> <td>Pages:</td> <td><input type="number" ng-model="Pages"></td> </tr> </table> <button ng-click="add_book()">Add</button> </div> <hr> <div> <table> <tr> <th>Name</th> <th>Isbn</th> <th>Author</th> <th>Pages</th> </tr> <tr ng-repeat="book in books"> <td><input type="button" value="Delete" data-ng-click="del_book(book)"></td> <td>{{book.name}}</td> <td>{{book.isbn}}</td> <td>{{book.author}}</td> <td>{{book.pages}}</td> </tr> </table> </div> </body> </html>
Met deze code maakt u een eenvoudig HTML-formulier, met vier velden voor het verzenden van boekgegevens en een tabel waarin alle boeken worden weergegeven die zijn opgeslagen in de database.
Hoewel deze HTML-code standaard is, zijn de
ng-
HTML-kenmerken mogelijk onbekend voor u. Met deze HTML-kenmerken wordt de AngularJS-code geactiveerd voor de gebruikersinterface. Wanneer u bijvoorbeeld Toevoegen selecteert, wordt via AngularJS de functieadd_book
aangeroepen, waarmee de formuliergegevens naar de server worden verzonden.U kunt de code hier bekijken om een beeld te krijgen van hoe elk van de kenmerken zich verhoudt tot de bedrijfslogica van de
ng-
toepassing.
De Express.js-server maken voor het hosten van de toepassing
Open
server.js
in de editor en voeg de volgende code toe:var express = require('express'); var bodyParser = require('body-parser'); var app = express(); app.use(express.static(__dirname + '/public')); app.use(bodyParser.json()); require('./app/routes')(app); app.set('port', 80); app.listen(app.get('port'), function() { console.log('Server up: http://localhost:' + app.get('port')); });
Met deze code wordt de webtoepassing zelf gemaakt. Het dient statische bestanden uit de
public
map en gebruikt de routes die u eerder hebt gedefinieerd om aanvragen te verwerken.
Pakketgegevens en afhankelijkheden definiëren
package.json
bevat informatie over uw toepassing, zoals de naam, de beschrijving en de Node.js-pakketten die nodig zijn om de toepassing te kunnen uitvoeren.
Open
package.json
in de editor en voeg de volgende code toe:{ "name": "books", "description": "Sample web app that manages book information.", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/MicrosoftDocs/mslearn-build-a-web-app-with-mean-on-a-linux-vm" }, "main": "server.js", "dependencies": { "express": "~4.16", "mongoose": "~5.3", "body-parser": "~1.18" } }
Er worden gegevens, de zogeheten metagegevens, weergegeven over uw toepassing, zoals de naam, de beschrijving en de licentie.
Het veld repository
geeft aan waar de code wordt onderhouden. U kunt de code later bekijken op GitHub via de URL die hier wordt weergegeven.
Met het veld main
wordt het toegangspunt van de toepassing gedefinieerd. We bieden het hier voor volledigheid. Het toegangspunt is echter alleen belangrijk als u van plan bent om uw toepassing als een Node.js-pakket te publiceren, zodat anderen deze kunnen downloaden en gebruiken.
Het veld dependencies
is belangrijk. Met dit veld worden namelijk de Node.js-pakketten gedefinieerd die uw toepassing nodig heeft. Kortom, u maakt een tweede keer verbinding met uw virtuele machine en voert u de npm install
opdracht uit om deze pakketten te installeren.
Node-pakketten maken doorgaans gebruik van het Semantic Versioning-versiebeheerschema. Het versienummer bevat drie onderdelen: de primaire versie, de secundaire versie en de patch. De tilde ~
-notatie hier vertelt npm dat de meest recente patchversie moet worden geïnstalleerd onder de opgegeven primaire en secundaire versies. De versies die u hier ziet, zijn de nieuwste versies waarmee deze module is getest. In de praktijk kunt u de versie na verloop van tijd verhogen wanneer u uw toepassing bijwerkt en test voor het gebruik van de nieuwste functies van elk afzonderlijk pakket.
De bestanden naar uw virtuele machine kopiëren
Voordat u verdergaat, moet u ervoor zorgen dat u het IP-adres van uw VIRTUELE machine bij de hand hebt. Als u deze niet hebt, voert u deze opdrachten uit vanuit de Cloud Shell om deze op te halen:
ipaddress=$(az vm show \
--name MeanStack \
--resource-group "<rgn>[sandbox resource group name]</rgn>" \
--show-details \
--query [publicIps] \
--output tsv)
echo $ipaddress
U bent klaar met het bewerken van bestanden. Zorg ervoor dat u wijzigingen in elk bestand hebt opgeslagen en sluit vervolgens de editor.
Als u de editor wilt sluiten, selecteert u het beletselteken in de rechterbovenhoek en selecteert u Editor sluiten.
Voer de volgende
scp
opdracht uit om de inhoud van de~/Books
map in uw Cloud Shell-sessie te kopiëren naar dezelfde mapnaam op uw VIRTUELE machine:scp -r ~/Books azureuser@$ipaddress:~/Books
Meer Node-pakketten installeren
Stel dat u tijdens het ontwikkelingsproces meer Node-pakketten hebt geïdentificeerd die u wilt gebruiken. Bijvoorbeeld: app/model.js
begint met deze regel.
var mongoose = require('mongoose');
De toepassing gebruikt Mongoose om gegevens van en naar de MongoDB-database over te zetten.
De toepassing vereist ook Express.js en de body-parser-pakketten. Body-parser is een invoegtoepassing waarmee Express kan werken met gegevens van het webformulier dat door de client wordt verzonden.
Laten we nu verbinding maken met uw virtuele machine en de pakketten installeren die u hebt opgegeven in package.json
.
Voordat u verbinding maakt met uw VM, moet u ervoor zorgen dat u het IP-adres van uw VM bij de hand hebt. Als u deze niet hebt, voert u de Cloud Shell-opdrachten uit in de vorige sectie om deze op te halen.
Maak een SSH-verbinding met uw VIRTUELE machine, zoals u eerder hebt gedaan:
ssh azureuser@$ipaddress
Ga naar de
Books
map onder de basismap:cd ~/Books
Voer deze opdracht uit
npm install
om de afhankelijke pakketten te installeren:sudo apt install npm -y && npm install
Houd uw SSH-verbinding geopend voor de volgende sectie.
De toepassing testen
U bent nu klaar om uw Node.js-webtoepassing te testen.
Voer vanuit de
~/Books
map deze opdracht uit om de webtoepassing te starten:sudo nodejs server.js
Met deze opdracht start u de toepassing door op poort 80 te luisteren naar binnenkomende HTTP-aanvragen.
Navigeer vanaf een ander browsertabblad naar het openbare IP-adres van uw virtuele machine.
De indexpagina met daarop een webformulier verschijnt.
Voeg een paar boeken toe aan de database. Steeds wanneer u een boek toevoegt, wordt de volledige lijst met boeken op de pagina bijgewerkt.
Als u een boek uit de database wilt verwijderen, kunt u ook Verwijderen selecteren.