Costruisci applicazioni Web usando Node.js

introduzione

Oltre alla creazione di API, Node.js è ottimo per la creazione di applicazioni Web standard. Ha potenti strumenti per incontrare il gusto degli sviluppatori web. In questo tutorial, creerai un'applicazione web che può fungere da biblioteca locale. 

Durante la creazione imparerai alcuni tipi di middleware, vedrai come gestire l'invio dei moduli in Node.js e potrai anche fare riferimento a due modelli.

Iniziamo.

Iniziare

Inizia installando il generatore express sulla tua macchina.

npm install express-generator -g

Esegui il comando express generator per generare la tua applicazione.

express tutsplus-library --view = pug
 create: tutsplus-library create: tutsplus-library / package.json create: tutsplus-library / app.js create: tutsplus-library / public create: tutsplus-library / routes create: tutsplus-library / routes / index.js create: tutsplus-library / routes / users.js create: tutsplus-library / views create: tutsplus-library / views / index.pug create: tutsplus-library / views / layout.pug create: tutsplus-library / views / error.pug create : tutsplus-library / bin crea: tutsplus-library / bin / www crea: tutsplus-library / public / javascripts crea: tutsplus-library / public / images crea: tutsplus-library / public / stylesheets crea: tutsplus-library / public / stylesheets / style.css install dependencies: $ cd tutsplus-library && npm install esegue l'app: $ DEBUG = tutsplus-library: * npm start

Ora migrate nel vostro lavoro, aprite package.json e create le dipendenze in modo simile a quello che ho di seguito.

# package.json "name": "tutsplus-library", "version": "0.0.0", "private": true, "scripts": "start": "node ./bin/www", "dipendenze": "body-parser": "~ 1.17.1", "connect-flash": "^ 0.1.1", "cookie-parser": "~ 1.4.3", "debug": "~ 2.6.3 "," express ":" ~ 4.15.2 "," express-messages ":" ^ 1.0.1 "," express-session ":" ^ 1.15.5 "," express-validator ":" ^ 4.2.1 "," mangusta ":" ^ 4.11.12 "," morgan ":" ~ 1.8.1 "," pug ":" ~ 2.0.0-beta11 "," serve-favicon ":" ~ 2.4. 2 "

Esegui il comando per installare i pacchetti.

installazione di npm

Impostare il file di entrata

app.js è stato creato quando è stato eseguito il comando del generatore; tuttavia, è necessario configurare una configurazione aggiuntiva. Modifica il file per assomigliare a quello che ho qui sotto.

# app.js var express = require ('express'); var path = require ('percorso'); var favicon = require ('serve-favicon'); var logger = require ('morgan'); var cookieParser = require ('cookie-parser'); var bodyParser = require ('body-parser'); const session = require ('express-session') const expressValidator = require ('express-validator') const flash = require ('connect-flash') const mongoose = require ('mongoose') // 1 const generi = require (' ' ./routes/genres'); const books = require ('./ routes / books'); var app = express (); // 2 mongoose.Promise = global.Promise const mongoDB = process.env.MONGODB_URI || 'mongodb: //127.0.0.1/tutsplus-library' mongoose.connect (mongoDB) // visualizza il setup del motore app.set ('views', path.join (__ dirname, 'views')); app.set ('view engine', 'pug'); // decommenta dopo aver inserito la tua favicon in / public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use (logger ( 'dev')); app.use (bodyParser.json ()); app.use (bodyParser.urlencoded (extended: false)); app.use (cookieParser ()); app.use (express.static (path.join (__ dirname, 'public'))); // 3 app.use (session (secret: 'secret', saveUninitialized: true, resave: true)) // 4 app.use (expressValidator (errorFormatter: function (param, msg, value) var namespace = param.split ('.'), root = namespace.shift (), formParam = root while (namespace.length) formParam + = '[' + namespace.shift () + ']' return param: formParam, msg: msg, valore: valore)) // 5 app.use (flash ()) app.use (funzione (req, res, next) res.locals.messages = require ('express-messages') next ()) // 6 app.use ('/ genres', generi); app.use ('/ libri', libri); // cattura 404 e inoltra al gestore degli errori app.use (funzione (req, res, next) var err = new Error ('Not Found'); err.status = 404; next (err);); // gestore degli errori app.use (funzione (err, req, res, next) // imposta i locals, fornendo solo errori nello sviluppo res.locals.message = err.message; res.locals.error = req.app.get ('env') === 'sviluppo'? err: ; // visualizza la pagina di errore res.status (err.status || 500); res.render ('error');); module.exports = app;
  1. Hai richiesto i due percorsi che utilizzerai per creare questa applicazione. Creerai il file di percorsi a breve. I percorsi richiesti vengono assegnati come valori a due diverse variabili che vengono utilizzate durante l'impostazione del middleware per i percorsi.
  2. Hai impostato l'uso di Mongoose global.Promise. La variabile MongoDB è assegnato il MONGODB_URI del tuo ambiente o il percorso del tuo server mongo locale. Questa variabile viene passata come argomento per connettersi al server MongoDB in esecuzione.
  3. Si imposta il middleware delle sessioni usando Express-session. Questo middleware è importante poiché visualizzerai messaggi flash in alcune parti della tua applicazione.
  4. Si imposta il middleware per la convalida. Questo middleware verrà utilizzato per convalidare l'input del modulo, assicurando che gli utenti dell'applicazione non inviino un modulo vuoto. La convalida utilizza un pacchetto installato, Express-validatore.
  5. Si imposta il middleware che sarà utile quando si visualizzano messaggi flash. Questo middleware fa uso di collegare-flash.
  6. I percorsi per l'applicazione sono impostati per utilizzare il file di rotte richiesto. Richieste che puntano a / generi e / libri utilizzerà rispettivamente i file dei generi e dei percorsi dei libri. Al momento non hai creato i file dei percorsi, ma lo farai presto.

Modello di libro e genere

Il modello del libro utilizzerà lo schema di Mongoose per definire come saranno strutturati i libri. Crea una directory chiamata Modelli, e un nuovo file chiamato Book.js. Ecco come appare.

# models / Book.js const mongoose = require ('mongoose') mongoose.Promise = global.Promise const Schema = mongoose.Schema const bookSchema = Schema (nome: tipo: String, trim: true, obbligatorio: 'Prego inserire nome di un libro ', descrizione: tipo: String, trim: true, autore: tipo: String, trim: true,, genere: [type: Schema.Types.ObjectId, ref:' Genre '] ) module.exports = mongoose.model ('Book', bookSchema)

Qui hai quattro campi. L'ultimo campo è usato per memorizzare il genere a cui ogni libro appartiene. Il campo dei generi qui fa riferimento al modello di genere, che verrà creato successivamente. Ecco perché il tipo è impostato su Schema.Types.ObjectId, che è dove verranno salvati gli ID di ogni genere di riferimento. arbitro specifica il modello a cui stai facendo riferimento. Nota che il genere viene salvato come matrice, il che significa che un libro può avere più di un genere.

Andiamo avanti a creare il modello di genere.

# models / genre.js const mongoose = require ('mongoose') mongoose.Promise = global.Promise const Schema = mongoose.Schema const genreSchema = Schema (nome: tipo: String, trim: true, obbligatorio: 'Inserisci un nome di genere ') module.exports = mongoose.model (' Genre ', genreSchema)

Per il tuo genere, hai bisogno di un solo campo: nome.

Percorso e visualizzazione dell'indice di genere

Per questo tutorial, utilizzerai due percorsi percorsi per il tuo genere: un percorso per aggiungere nuovi generi e un altro che elenca i generi che hai. Crea un file nella directory dei percorsi chiamata genres.js.

Inizia richiedendo tutti i moduli che utilizzerai.

# routes / genres.js var express = require ('express'); var router = express.Router (); const mongoose = require ('mongoose') const Genre = require ('... / models / Genre')

Successivamente, elimina la route che gestisce il file di indice per i tuoi generi.

router.get ('/', (req, res, next) => const genres = Genre.find (). exec () .then ((generi) => res.render ('generi',  generi: generi), (err) => throw err));

Questo percorso viene chiamato ogni volta che vengono fatte delle richieste / generi. Qui chiami il metodo find sul tuo modello di genere per ottenere tutti i generi che sono stati creati. Questi generi vengono quindi renderizzati su un modello chiamato generi. Andiamo avanti e crealo, ma prima aggiorna il tuo layout.pug per assomigliare a questo:

# views / layout.pug doctype html html head title = titolo link (rel = 'stylesheet', href = "/ stylesheets / style.css") link (rel = 'stylesheet', href = "https://bootswatch.com /paper/bootstrap.css ") script (src = 'https: //ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js') script (src = 'https: // maxcdn .bootstrapcdn.com / bootstrap / 3.3.7 / js / bootstrap.min.js ') body. container-fluid header header nav.navbar.navbar-inverse .container-fluid .navbar-header button.navbar-toggle.collapsed ( type = 'button', data-toggle = "collapse", data-target = "# bs-example-navbar-collapse-2") span.sr-only Attiva / disattiva la navigazione span.icon-bar span.icon-bar span. icon-bar a.navbar-brand (href = '#') Libreria locale # bs-example-navbar-collapse-2.collapse.navbar-collapse ul.nav.navbar-nav.navbar-right li a (href = ' / libri ') Visualizza libri li a (href =' / books / add ') Aggiungi nuovo libro li a (href =' / genres ') Visualizza Generi li a (href =' / genres / add ') Aggiungi nuovo contenuto del blocco Genre

Questo darà ai tuoi punti di vista una bella struttura per facilitare la navigazione. Ora crea un file di visualizzazione chiamato genre.pug. In questo file, eseguirai un ciclo attraverso i generi creati e trasmetteresti ciascun genere in una lista non ordinata.

Ecco come dovrebbe apparire il file.

# views / genres.pug estende il contenuto del blocco di layout h1 Genere ul.well.well-lg ogni genere, io in genere li.well.well-sm p # genre.name

Aggiungi nuovi percorsi e viste di genere

Torna al tuo Percorsi / genres.js aggiungere i percorsi che gestiranno la creazione di nuovi generi.

# routes / genres.js // 1 router.get ('/ add', (req, res, next) => res.render ('addGenre')) // 2 router.post ('/ add', (req, res, next) => req.checkBody ('name', 'Name is required'). notEmpty () const errors = req.validationErrors () if (errori) console.log (errori) res.render ('addgenres', genere, errori) const genere = (nuovo genere (req.body)). save () .then ((data) => res.redirect ('/ genres')) .catch ((errors) => console.log ('oops ...') console.log (errori))) // 3 module.exports = router;
  1. Il compito di questo router è semplicemente di visualizzare la pagina per aggiungere nuovi percorsi. Questo router viene chiamato ogni volta che vengono fatte delle richieste / generi / aggiungi sentiero.
  2. Questo router gestisce l'invio del modulo. Quando il modulo viene inviato, controlliamo che venga inserito un nome dall'utente. Se non viene inserito alcun nome, la pagina viene nuovamente visualizzata. Se i controlli sono validi, il genere viene salvato e l'utente viene reindirizzato a / generi pagina.
  3. Il modulo viene esportato come router.

Ora puoi andare avanti e creare la pagina per aggiungere un nuovo genere.

# views / addGenre.pug estende il contenuto del blocco di layout .row .col-md-12 h1 Aggiungi modulo Libro (metodo = "POST", action = "/ genres / add") .form-group label.col-lg-2. control.label Nome .col-lg-10 input.form-control (type = "text", name = "name") .form-group .col-lg-10.col-lg-offset-2 input.button. btn.btn-primary (type = 'submit', value = "Submit") se gli errori ul per errori negli errori li! = error.msg

Libri Percorsi e Visualizza

Crea un nuovo file di percorso per i libri e nominalo books.js. Come hai fatto prima con il genere, inizia richiedendo i moduli necessari.

# routes / books.js var express = require ('express'); var router = express.Router (); const mongoose = require ('mongoose') const Book = require ('... / models / Book') const Genre = require ('... / models / Genre')

Quindi, configura il router per visualizzare tutti i libri salvati nella libreria. Provalo da solo nel modo in cui imposti quello del genere; puoi sempre ricontrollare per apportare correzioni.

Immagino che l'abbia provato ... ecco come dovrebbe apparire.

router.get ('/', (req, res, next) => const books = Book.find (). exec (). then ((books) => res.render ('books',  libri: libri), (err) => throw err));

Quando viene chiamato questo router, viene effettuata una richiesta per trovare tutti i libri salvati nel database. Se tutto va bene, i libri sono mostrati su / libri pagina, altrimenti viene generato un errore.

Devi creare un nuovo file per visualizzare tutti i libri, ed ecco come dovrebbe apparire.

# views / books.pug estende il contenuto del blocco di layout h1 Libri ul.well.well-lg ogni libro, io nei libri li.well.well-sm a (href = '/ books / show / $ book.id') # book.name p = book.description

Basta scorrere i libri restituiti e produrre il nome e la descrizione di ogni libro utilizzando un elenco non ordinato. Il nome del libro punta alla singola pagina del libro.

Aggiungi nuove rotte di libri e vista

Il prossimo router che hai configurato gestirà l'aggiunta di nuovi libri. Qui verranno utilizzati due router: uno renderà semplicemente la pagina e un altro gestirà l'invio del modulo.

Ecco come appaiono i router.

router.get ('/ add', (req, res, next) => const genres = Genre.find (). exec () .then ((generi) => res.render ('addBooks', generi)) .catch ((err) => throw err)) router.post ('/ add', (req, res, next) => req.checkBody ('nome', 'Nome è richiesto '). notEmpty () req.checkBody (' description ',' Description is required '). notEmpty () req.checkBody (' genere ',' Genere richiesto '). notEmpty const errors = req.validationErrors () if (errori) console.log (errori) res.render ('addBooks', book, errors) const book = (new Book (req.body)). save () .then ((data) => res.redirect ('/ books')) .catch ((errors) => console.log ('oops ...')))

Nel primo router, stai visualizzando il / addBooks pagina. Questo router viene chiamato quando viene effettuata una richiesta /Inserisci sentiero. Poiché i libri aggiunti dovrebbero avere generi, si desidera visualizzare i generi che sono stati salvati nel database.

 const genre = Genre.find (). exec () .then ((generi) => 

Il codice sopra trova tutti i generi nel tuo database e li restituisce nei generi variabili. Con questo, sarete in grado di scorrere i generi e visualizzarli come caselle di controllo.

Il secondo router gestisce l'invio del modulo. Innanzitutto, controlli il corpo della richiesta per assicurarti che alcuni campi non siano vuoti. Questo è dove il Express-validatore middleware che hai impostato app.js è a portata di mano. Se ci sono errori, la pagina viene nuovamente visualizzata. Se non ce ne sono, la nuova istanza di Book viene salvata e l'utente viene reindirizzato alla pagina / books.

Andiamo avanti e creiamo le opinioni per questo.

Crea un nuovo file di visualizzazione chiamato addBooks.pug. Si noti che il nome della vista corrisponde al primo parametro assegnato a res.render. Questo perché stai rendendo un modello. Durante il reindirizzamento, si passa semplicemente il percorso a cui si desidera reindirizzare, come si è fatto con res.redirect ( '/ libri').

Stabilito ciò, ecco come dovrebbero apparire le visualizzazioni.

# views / addBooks.pug estende il contenuto del blocco di layout .row .col-md-12 h1 Aggiungi modulo Libro (metodo = "POST", action = "/ books / add") .form-group label.col-lg-2. control-label Nome .col-lg-10 input.form-control (type = "text", name = "name") .form-group label.col-lg-2.control-label Autore .col-lg-10 input.form-control (type = "text", name = "author") .form-group label.col-lg-2.control-label Descrizione del libro .col-lg-10 textarea # textArea.form-control (righe = '3', name = "description") .form-group label.col-lg-2.control-label Genre .col-lg-10 per genere nei generi .checkbox input.checkbox (type = 'checkbox', name = "genre", id = genre._id, value = genre._id, checked = genre.checked) label (per = genre._id) # genre.name .form-group .col-lg-10.col- lg-offset-2 input.button.btn.btn-primary (type = 'submit', value = "Submit") se errori ul per errori negli errori li! = error.msg 

La cosa importante da notare qui è l'azione e il metodo del modulo. Quando si fa clic sul pulsante di invio, si sta facendo un INVIARE richiesta a / libri / aggiungi. Un'altra cosa: ancora una volta fai un ciclo attraverso la collezione di generi restituiti e mostra ognuno di loro.

Book Show Route and View

Lasciaci cadere il percorso per gestire le richieste fatte a ciascuna pagina di libri. Mentre sei lì, è importante esportare anche il tuo modulo.

# routes / books.js router.get ('/ show /: id', (req, res, next) => const book = Book.findById (_id: req.params.id) .popola (percorso : 'genere', modello: 'Genere', popolare: percorso: 'genere', modello: 'Libro') .exec () .then ((libro) => res.render ('libro',  book)) .catch ((err) => throw err)) module.exports = router;

Nessuna magia sta accadendo qui.

Innanzitutto, le richieste fatte a questo router devono avere un id: l'id del libro. Questo id è ottenuto dai parametri della richiesta usando req.params.id. Questo è usato per identificare il libro specifico che dovrebbe essere ottenuto dal database, poiché gli ID sono unici. Quando il libro viene trovato, il valore del genere del libro viene popolato con tutti i generi che sono stati salvati in questa istanza di libro. Se tutto va bene, viene visualizzata la vista del libro, altrimenti viene generato un errore.

Creiamo la vista per un libro. Ecco come dovrebbe apparire.

blocca contenuto .well.well-lg h1 # [strong name:] # book.name ul li # [strong Descrizione:] # book.description li # [strong author]: # book.author li # [Genere forte:] ogni genere in book.genre # genre.name |,

Puoi avviare il tuo nodo server eseguendo:

DEBUG = libreria tutsplus: * npm start

Conclusione

Ora sai come costruire un'applicazione web standard in Node.js, non solo una semplice app da fare. Sei stato in grado di gestire l'invio dei moduli, fare riferimento a due modelli e impostare alcuni middleware.

Puoi andare oltre estendendo l'applicazione: prova ad aggiungere la possibilità di eliminare un libro. Per prima cosa aggiungi un pulsante alla pagina dello spettacolo, quindi vai ai file dei percorsi e aggiungi un router per questo. Si noti che questo sarà a INVIARE richiesta.

Puoi anche pensare a più funzioni da aggiungere all'applicazione. Spero ti sia piaciuto.