Ćwiczenie — tworzenie podstawowej aplikacji internetowej

Ukończone

Do tej pory na maszynie wirtualnej z systemem Ubuntu zainstalowano bazę danych MongoDB i Node.js. Teraz utworzysz podstawową aplikację internetową, aby zobaczyć, jak to działa. Po drodze zobaczysz, w jaki sposób można dopasować platformę AngularJS i platformę Express.

Najlepiej uczymy się na przykładach. Utworzona aplikacja internetowa implementuje podstawową bazę danych książek. Aplikacja internetowa umożliwia wyświetlanie listy informacji o książkach, dodawanie nowych książek i usuwanie istniejących książek.

Wyświetlona tutaj aplikacja internetowa demonstruje wiele pojęć, które mają zastosowanie do większości aplikacji internetowych stosu MEAN. W zależności od swoich potrzeb lub zainteresowań możesz zapoznać się z funkcjami, których potrzebujesz do tworzenia własnych aplikacji opartych na stosie MEAN.

Oto jak wygląda aplikacja internetowa Books.

Zrzut ekranu ze stroną internetową z formularzem i przyciskiem przesyłania.

Poniżej przedstawiono rolę, jaką odgrywają poszczególne składniki stosu MEAN.

  • Bazy danych MongoDB przechowuje informacje o książkach.
  • Express.js kieruje każde żądanie HTTP do odpowiedniej procedury obsługi.
  • Rozwiązanie AngularJS łączy interfejs użytkownika z logiką biznesową programu.
  • Środowisko Node.js hostuje aplikację po stronie serwera.

Ważne

Utworzysz teraz podstawową aplikację internetową dla celów szkoleniowych. Umożliwia ona przetestowanie stosu MEAN i zapoznanie się ze sposobem jego działania. Aplikacja nie jest wystarczająco bezpieczna ani gotowa do użycia w środowisku produkcyjnym.

Co z rozwiązaniem Express?

Do tej pory zainstalowano bazę danych MongoDB i Node.js na maszynie wirtualnej. A co z Express.js, E w akronimie MEAN?

Express.js to struktura serwera internetowego utworzona na potrzeby Node.js, która upraszcza proces tworzenia aplikacji internetowych.

Jej głównym celem jest obsługa kierowania żądań. Kierowanie żądań oznacza sposób, w jaki aplikacja odpowiada na żądania przesłane do określonego punktu końcowego. Punkt końcowy składa się ze ścieżki lub identyfikatora URI oraz metody żądania, takiej jak GET lub POST. Na przykład w odpowiedzi na żądanie GET do punktu końcowego /book może być zwracana lista wszystkich książek w bazie danych. Możesz odpowiedzieć na żądanie POST do punktu końcowego /book , dodając wpis do bazy danych na podstawie pól wprowadzonych przez użytkownika w formularzu internetowym.

W utworzonej wkrótce aplikacji internetowej usługa Express służy do kierowania żądań HTTP i zwracania zawartości internetowej do użytkownika. Rozwiązanie Express może również ułatwić korzystanie z plików cookie HTTP i przetwarzanie ciągów zapytań w aplikacjach internetowych.

Rozwiązanie Express jest pakietem środowiska Node.js. Narzędzie npm dostarczane wraz ze środowiskiem Node.js umożliwia instalowanie pakietów Node.js i zarządzanie nimi. W dalszej części tej lekcji utworzysz plik o nazwie package.json definiującej platformę Express i inne zależności, a następnie uruchom npm install polecenie , aby zainstalować te zależności.

Co z rozwiązaniem AngularJS?

Podobnie jak express, AngularJS, A w akronimie MEAN, nie jest jeszcze zainstalowany.

Usługa AngularJS ułatwia pisanie i testowanie aplikacji internetowych, ponieważ umożliwia lepsze oddzielenie wyglądu strony internetowej — kodu HTML — od sposobu zachowania strony internetowej. Jeśli znasz wzorzec MVC (model-view-controller) lub pojęcie powiązania danych, usługa AngularJS powinna być ci znana.

AngularJS to platforma JavaScript frontonu , co oznacza, że musi być dostępna tylko na kliencie, który uzyskuje dostęp do aplikacji. Innymi słowy rozwiązanie AngularJS działa w przeglądarce internetowej użytkownika, a nie na Twoim serwerze internetowym. Ponieważ rozwiązanie AngularJS bazuje na języku JavaScript, możesz za jego pomocą łatwo pobierać z serwera internetowego dane do wyświetlenia na stronie.

Tak naprawdę nie trzeba instalować platformy AngularJS. Wystarczy dodać odwołanie do pliku JavaScript na stronie HTML, tak samo jak w przypadku innych bibliotek języka JavaScript. Istnieje kilka sposobów na dodanie rozwiązania AngularJS do stron internetowych. W tym miejscu załadujesz usługę AngularJS z sieci dostarczania zawartości (CDN). Sieci CDN umożliwiają rozproszenie geograficzne obrazów, klipów wideo i innych treści w celu przyspieszenia ich pobierania.

Nie dodawaj jeszcze tego kodu, ale oto przykład, który ładuje usługę AngularJS z sieci CDN. Zazwyczaj ten kod jest dodany do <head> sekcji strony HTML.

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>

Uwaga

Nie należy mylić rozwiązania AngularJS z usługą Angular. Choć używane są w nich podobne koncepcje, rozwiązanie AngularJS jest wcześniejszą wersją usługi Angular. Rozwiązanie AngularJS jest nadal powszechnie używane do tworzenia aplikacji internetowych. Rozwiązanie AngularJS bazuje na języku JavaScript, natomiast usługa Angular — na języku TypeScript, który ułatwia tworzenie programów w języku JavaScript.

Jak mogę skompilować aplikację?

W tym miejscu użyjesz podstawowego procesu. Napiszesz kod aplikacji z usługi Cloud Shell, a następnie użyjesz protokołu secure copy (SCP), aby skopiować pliki do maszyny wirtualnej. Następnie uruchomisz aplikację Node.js i zobaczysz wyniki w przeglądarce.

W praktyce zazwyczaj napiszesz i przetestujesz aplikację internetową w bardziej lokalnym środowisku, na przykład z laptopa lub z maszyny wirtualnej uruchamianej lokalnie. Kod można przechowywać w systemie kontroli wersji, takim jak Git. Następnie użyj systemu ciągłej integracji i ciągłego dostarczania (CI/CD), takiego jak Azure DevOps, aby przetestować zmiany i przekazać je do maszyny wirtualnej. Wskazujemy na więcej zasobów na końcu tego modułu.

Tworzenie aplikacji internetowej z informacjami o książkach

W tym miejscu utworzysz cały kod, skrypt i pliki HTML tworzące aplikację internetową. Aby uzyskać zwięzłość, wyróżniamy ważne części każdego pliku, ale nie przechodzimy do pełnych szczegółów.

Jeśli nadal masz połączenie SSH z maszyną wirtualną, uruchom polecenie exit, aby zakończyć sesję SSH i powrócić do usługi Cloud Shell.

exit

Wrócisz w ten sposób do sesji usługi Cloud Shell.

Tworzenie plików

  1. W usłudze Cloud Shell uruchom następujące polecenia, aby utworzyć foldery i pliki dla aplikacji internetowej:

    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
    

    Aplikacja internetowa zawiera następujące foldery i pliki:

    • Books to katalog główny projektu.
      • Plik server.js definiuje punkt wejścia do aplikacji internetowej. Ładuje wymagane pakiety Node.js, określa port nasłuchiwania i rozpoczyna nasłuchiwanie przychodzącego ruchu HTTP.
      • Plik package.json zawiera informacje o aplikacji, w tym jej nazwę, opis oraz pakiety Node.js, których aplikacja potrzebuje do działania.
    • Books/app — zawiera kod, który działa na serwerze.
      • Plik model.js definiuje połączenie z bazą danych i schemat. Można traktować go jako model danych dla aplikacji.
      • Plik routes.js obsługuje kierowanie żądań. Na przykład definiuje żądanie GET do punktu końcowego /book jako żądanie zwrócenia listy wszystkich książek w bazie danych.
    • Books/public — zawiera pliki, które są dostarczane bezpośrednio do przeglądarki klienta.
      • Plik index.html zawiera stronę indeksu. Na tej stronie znajduje się formularz internetowy umożliwiający użytkownikowi przesyłanie informacji o książkach. Pozwala także wyświetlać wszystkie książki w bazie danych i usuwać wpisy z bazy.
      • Plik script.js zawiera kod JavaScript, który działa w przeglądarce użytkownika. Umożliwia wysyłanie do serwera żądań zwrócenia listy książek, dodania książek do bazy danych i usunięcia książek z bazy danych.
  2. Uruchom polecenie code, aby otworzyć pliki za pomocą edytora usługi Cloud Shell.

    code Books
    

Tworzenie modelu danych

  1. W edytorze otwórz app/model.js plik i dodaj następujący kod:

    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;
    

    Ważne

    Zawsze, gdy wklejasz lub zmieniasz kod w pliku w edytorze, pamiętaj o zapisaniu go później przy użyciu menu „...” lub klawisza skrótu (Ctrl+S w systemach Windows i Linux, Command+S w systemie macOS).

    W tym kodzie użyto platformy Mongoose w celu uproszczenia procesu przesyłania danych do i z usługi MongoDB. Mongoose to oparty na schemacie system do modelowania danych. Kod definiuje dokument bazy danych o nazwie „Book” z podanym schematem. W schemacie zdefiniowano cztery pola, które opisują każdą książkę:

    • Nazwa, czyli tytuł książki.
    • Jego międzynarodowy numer książki standardowej (ISBN), który jednoznacznie identyfikuje książkę
    • Autor.
    • Liczba stron.

    Następnie utworzysz programy obsługi HTTP mapujące żądania GET, POST i DELETE na operacje bazy danych.

Tworzenie tras Express.js obsługujących żądania HTTP

  1. W edytorze otwórz app/routes.js plik i dodaj następujący kod:

    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;
    

    Ten kod tworzy cztery trasy dla aplikacji. Poniżej przedstawiono krótkie omówienie każdej z nich.

    Czasownik HTTP Punkt końcowy opis
    GET /book Pobiera wszystkie książki z bazy danych.
    POST /book Tworzy obiekt Book na podstawie informacji wprowadzonych przez użytkownika w polach formularza internetowego i zapisuje ten obiekt w bazie danych.
    DELETE /book/:isbn Usuwa z bazy danych książkę o podanym numerze ISBN.
    GET * Zwraca stronę indeksu, jeśli nie dopasowano żadnej innej trasy.

    Express.js może obsługiwać odpowiedzi HTTP bezpośrednio w kodzie obsługi tras lub obsługiwać zawartość statyczną z plików. W tym kodzie przedstawiono obie możliwości. Pierwsze trzy trasy zwracają dane JSON w odpowiedzi na żądania dotyczące książek z interfejsu API. Czwarta trasa (przypadek domyślny) zwraca zawartość pliku indeksu index.html.

Tworzenie aplikacji klienckiej JavaScript

  1. W edytorze otwórz plik public/script.js i dodaj następujący kod:

    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);
            });
        };
    });
    

    Zwróć uwagę, że ten kod definiuje moduł o nazwie myApp i kontroler o nazwie myCtrl. Nie zostaną tutaj omówione wszystkie szczegóły związane z działaniem modułów i kontrolerów, ale te nazwy będą używane w kolejnym kroku do powiązania interfejsu użytkownika (kodu HTML) z logiką biznesową aplikacji.

    Wcześniej utworzono cztery trasy do obsługi różnych operacji typu GET, POST i DELETE na serwerze. Ten kod dotyczy podobnych operacji, ale po stronie klienta (w przeglądarce internetowej użytkownika).

    Na przykład funkcja getData wysyła żądanie GET do punktu końcowego /book. Pamiętaj, że serwer obsługuje to żądanie, pobierając informacje o wszystkich książkach z bazy danych i zwracając te informacje jako dane JSON w odpowiedzi. Zwróć uwagę, że dane JSON w odpowiedzi są przypisywane do zmiennej $scope.books . Dowiesz się, jak ten kod wpływa na to, co użytkownik widzi na stronie internetowej w następnym kroku.

    Ten kod wywołuje funkcję getData podczas ładowania strony. Możesz zapoznać się z funkcjami del_book i add_book, aby poznać sposób ich działania. Do dopasowania domyślnego programu obsługi serwera nie jest potrzebny kod po stronie klienta, ponieważ domyślna procedura obsługi zwraca stronę indeksu, a nie dane JSON.

Tworzenie interfejsu użytkownika

  1. W edytorze otwórz plik public/index.html i dodaj następujący kod:

    <!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>
    

    Ten kod tworzy podstawowy formularz HTML z czterema polami do przesyłania danych książki i tabelą, w której są wyświetlane wszystkie książki przechowywane w bazie danych.

    Mimo że ten kod HTML jest standardowy, ng- atrybuty HTML mogą być dla Ciebie nieznane. Te atrybuty HTML łączą kod rozwiązania AngularJS z interfejsem użytkownika. Na przykład po wybraniu przycisku Dodaj, rozwiązanie AngularJS wywoła funkcję add_book, co spowoduje wysłanie danych z formularza na serwer.

    W tym miejscu możesz sprawdzić kod, aby dowiedzieć się, jak każdy z atrybutów ng- odnosi się do logiki biznesowej aplikacji.

Tworzenie serwera Express.js na potrzeby hostowania aplikacji

  1. W edytorze otwórz plik server.js i dodaj następujący kod:

    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'));
    });
    

    Ten kod służy do utworzenia aplikacji internetowej. Obsługuje pliki statyczne z public katalogu i używa tras zdefiniowanych wcześniej do obsługi żądań.

Definiowanie informacji o pakietach oraz zależności

Jak możesz pamiętać, plik package.json zawiera informacje o aplikacji, w tym jej nazwę, opis oraz pakiety Node.js, których aplikacja potrzebuje do działania.

  1. W edytorze otwórz plik package.json i dodaj następujący kod:

    {
      "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"
      }
    }
    

Zobaczysz informacje o aplikacji, czyli jej metadane, w tym jej nazwę, opis i licencję.

Pole repository określa lokalizację, w której przechowywany jest kod. Możesz później zapoznać się z tym kodem w witrynie GitHub pod podanym tu adresem URL.

Pole main definiuje punkt wejścia aplikacji. Udostępniamy go tutaj, aby zapewnić kompletność. Jednak punkt wejścia jest ważny tylko wtedy, gdy planujesz opublikować aplikację jako pakiet Node.js dla innych osób do pobrania i użycia.

Pole dependencies jest ważne. Definiuje pakiety Node.js wymagane przez aplikację. Wkrótce połączysz się z maszyną wirtualną po raz drugi i uruchom npm install polecenie , aby zainstalować te pakiety.

Pakiety Node na ogół korzystają ze schematu wersjonowania semantycznego. Numer wersji składa się z trzech elementów: wersji głównej, wersji pomocniczej i numeru poprawki. Zapis z tyldą (~) wskazuje, że narzędzie npm powinno zainstalować najnowszą wersję poprawki w ramach wskazanej wersji głównej i pomocniczej. Wyświetlone tutaj wersje to najnowsze wersje, z którymi przetestowano ten moduł. W praktyce możesz z czasem zwiększać wersję, aktualizując i testując aplikację w celu korzystania z najnowszych funkcji poszczególnych pakietów zależności.

Kopiowanie plików na maszynę wirtualną

Przed kontynuowaniem upewnij się, że adres IP maszyny wirtualnej jest przydatny. Jeśli go nie masz, uruchom następujące polecenia z usługi Cloud Shell, aby je pobrać:

ipaddress=$(az vm show \
  --name MeanStack \
  --resource-group "<rgn>[sandbox resource group name]</rgn>" \
  --show-details \
  --query [publicIps] \
  --output tsv)
echo $ipaddress
  1. Edycja plików została zakończona. Upewnij się, że zapisano zmiany w każdym pliku, a następnie zamknij edytor.

    Aby zamknąć edytor, wybierz wielokropek w prawym górnym rogu, a następnie wybierz pozycję Zamknij edytor.

  2. Uruchom następujące scp polecenie, aby skopiować zawartość ~/Books katalogu w sesji usługi Cloud Shell do tej samej nazwy katalogu na maszynie wirtualnej:

    scp -r ~/Books azureuser@$ipaddress:~/Books
    

Instalowanie większej liczby pakietów Node

Załóżmy, że podczas procesu programowania zidentyfikowano więcej pakietów node, których chcesz użyć. Możesz na przykład pamiętać, że plik app/model.js zaczyna się od takiego wiersza.

var mongoose = require('mongoose');

Pamiętaj, że w aplikacji używana jest platforma Mongoose, ułatwiająca przesyłanie danych do i z bazy MongoDB.

Aplikacja wymaga również Express.js i pakietów analizatora treści. Body-parser to wtyczka umożliwiająca platformie Express pracę z danymi z formularza internetowego wysyłanego przez klienta.

Nawiąż połączenie z maszyną wirtualną i zainstaluj pakiety określone w pliku package.json.

  1. Przed nawiązaniem połączenia z maszyną wirtualną upewnij się, że masz przygotowany jej adres IP. Jeśli go nie masz, uruchom polecenia usługi Cloud Shell w poprzedniej sekcji, aby je pobrać.

  2. Utwórz połączenie SSH z maszyną wirtualną, tak jak wcześniej:

    ssh azureuser@$ipaddress
    
  3. Przejdź do Books katalogu w katalogu głównym:

    cd ~/Books
    
  4. Uruchom polecenie npm install , aby zainstalować pakiety zależne:

    sudo apt install npm -y && npm install
    

Pozostaw otwarte połączenie SSH dla następnej sekcji.

Testowanie aplikacji

Możesz teraz przystąpić do testowania aplikacji internetowej Node.js.

  1. ~/Books W katalogu uruchom następujące polecenie, aby uruchomić aplikację internetową:

    sudo nodejs server.js
    

    To polecenie uruchamia aplikację, nasłuchując przychodzących żądań HTTP na porcie 80.

  2. W nowej karcie przeglądarki przejdź do publicznego adresu IP maszyny wirtualnej.

    Zostanie wyświetlona strona indeksu zawierająca formularz internetowy.

    Zrzut ekranu ze stroną internetową książki z formularzem i przyciskiem przesyłania.

    Spróbuj dodać kilka książek do bazy danych. Po dodaniu każdej książki pełna lista książek na stronie zostanie zaktualizowana.

    Zrzut ekranu ze stroną internetową książki wypełnioną przykładowymi danymi.

    Aby usunąć książkę z bazy danych, możesz również wybrać pozycję Usuń.