I den här handledningen kommer jag att visa dig hur du implementerar en chattapplikation i realtid med Node.js, Socket.IO och MongoDB, och sedan kommer vi att distribuera den här applikationen till Modulus tillsammans.
Först av allt, låt mig visa dig det slutliga utseendet på applikationen som vi kommer att ha i slutet av artikeln.
Node.js kommer att vara kärnan i applikationen, med Express som MVC, MongoDB för databasen och Socket.IO för realtidskommunikation. När vi är klara kommer vi att distribuera vår applikation till Modulus. MongoDB-delen finns faktiskt inuti Modulus.
1. Scenario
- John vill använda vår applikation och öppnar den i webbläsaren.
- På första sidan väljer han ett smeknamn som ska användas under chatten och loggar in för att chatta.
- I textområdet skriver han något och trycker på Enter.
- Texten skickas till en RESTful-tjänst (Express) och denna text skrivs till MongoDB.
- Innan du skriver i MongoDB kommer samma text att sändas till de användare som för närvarande är inloggade på chattappen.
Som du kan se är detta en väldigt enkel app, men den täcker nästan allt för en webbapplikation. Det finns inget kanalsystem i den här applikationen, men du kan dela källkoden och implementera kanalmodulen för övning.
2. Projektdesign från grunden
Jag ska försöka förklara de små delarna av projektet först och kombinera dem i slutet. Jag kommer att börja från baksidan till främre änden. Så låt oss börja med domänobjekten (MongoDB-modeller).
2.1. Modell
För databasabstraktion kommer vi att använda Mongoose. I det här projektet har vi bara en modell som heter Message
. Den här meddelandemodellen innehåller bara text
, createDate
, och author
. Det finns ingen modell för författaren som User
, eftersom vi inte kommer att implementera ett användarregistrering/inloggningssystem fullt ut. Det kommer att finnas en enkel smeknamns-tillhandahållande sida, och detta smeknamn kommer att sparas i en cookie. Detta kommer att användas i Message
modell som text i author
fält. Du kan se ett exempel på JSON-modell nedan:
{ text: "Hi, is there any Full Stack Developer here?" author: "john_the_full_stack", createDate: "2015.05.15" }
För att skapa dokument som detta kan du implementera en modell genom att använda Mongoose-funktionerna nedan:
var mongoose = require('mongoose') var Message = new mongoose.Schema({ author: String, message: String, createDate: { type: Date, default: Date.now } }); mongoose.model('Message', Message)
Importera helt enkelt Mongoose-modulen, definiera din modell med dess fält och fältattribut i JSON-format och skapa en modell med namnet Message
. Denna modell kommer att inkluderas på de sidor som du vill använda.
Kanske har du en fråga om varför vi lagrar meddelandet i databasen, när vi redan sänder detta meddelande till användaren i samma kanal. Det är sant att du inte behöver lagra chattmeddelanden, men jag ville bara förklara databasintegrationslagret. Hur som helst, vi kommer att använda den här modellen i vårt projekt inuti kontrollerna. Styrenheter?
2.2. Styrenhet
Som jag sa tidigare kommer vi att använda Express för MVC-delen. Och C
här står för Controller
. För våra projekt kommer det bara att finnas två slutpunkter för meddelanden. En av dem är för att ladda nya chattmeddelanden, och den andra är för att hantera skickade chattmeddelanden för att lagra i databasen och sedan sända in i kanalen.
..... app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); }); app.post('/messages', function(req, res, next) { var message = req.body.message; var author = req.body.author; var messageModel = new Message(); messageModel.author = author; messageModel.message = message; messageModel.save(function (err, result) { if (!err) { Message.find({}).sort('-createDate').limit(5).exec(function(err, messages) { io.emit("message", messages); }); res.send("Message Sent!"); } else { res.send("Technical error occurred!"); } }); }); app.get('/messages', function(req, res, next) { Message.find({}).sort('-createDate').limit(5).exec(function(err, messages) { res.json(messages); }); }); .....
De första och andra kontrollerna är bara för att servera statiska HTML-filer för chatt- och inloggningssidorna. Den tredje är för att hantera postbegäran till /messages
slutpunkt för att skapa nya meddelanden. I den här kontrollern konverteras först och främst förfrågningskroppen till meddelandemodellen, och sedan sparas denna modell i databasen genom att använda Mongoose-funktionen save
.
Jag kommer inte att fördjupa mig i Mongoose särskilt mycket – du kan ta en titt i dokumentationen för mer information. Du kan tillhandahålla en återuppringningsfunktion för sparafunktionen för att kontrollera om det är något problem eller inte. Om det lyckas har vi hämtat de senaste fem posterna sorterade i fallande ordning efter createDate
, och har sänt fem meddelanden till kunderna i kanalen.
Ok, vi har avslutat MC
. Låt oss byta till View
del.
2.3. Visa
I allmänhet kan en mallmotor som Jade, EJS, Styre, etc. användas inom Express. Men vi har bara en sida, och det är ett chattmeddelande, så jag kommer att servera detta statiskt. Faktiskt, som jag sa ovan, finns det ytterligare två kontroller för att betjäna denna statiska HTML-sida. Du kan se följande för att visa en statisk HTML-sida.
app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); });
Denna slutpunkt serverar helt enkelt index.html och login.html genom att använda res.sendFile
. Båda index.html och login.html finns i samma mapp som server.js, varför vi använde __dirname
före HTML-filnamnet.
2.4. Användargränssnitt
På front-end-sidan har jag använt Bootstrap och det finns ingen anledning att förklara hur jag lyckades göra det. Jag har helt enkelt bundit en funktion till en textruta, och när du trycker på Retur knapp eller Skicka knappen kommer meddelandet att skickas till back-end-tjänsten.
Den här sidan har också en nödvändig js-fil av Socket.IO för att lyssna på kanalen som heter message
. Socket.IO-modulen är redan importerad i backend, och när du använder den här modulen på serversidan lägger den automatiskt till en slutpunkt för att servera Socket.IO js-filen, men vi använder den som serveras från cdn <script src="//cdn.socket.io/socket.io-1.3.5.js"></script>
. När ett nytt meddelande kommer in till den här kanalen kommer det automatiskt att upptäckas och meddelandelistan uppdateras med de senaste fem meddelandena.
<script> var socket = io(); socket.on("message", function (messages) { refreshMessages(messages); }); function refreshMessages(messages) { $(".media-list").html(""); $.each(messages.reverse(), function(i, message) { $(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div class="media-body">' + message.message + '<br/><small class="text-muted">' + message.author + ' | ' + message.createDate + '</small><hr/></div></div></div></li>'); }); } $(function(){ if (typeof $.cookie("realtime-chat-nickname") === 'undefined') { window.location = "/login" } else { $.get("/messages", function (messages) { refreshMessages(messages) }); $("#sendMessage").on("click", function() { sendMessage() }); $('#messageText').keyup(function(e){ if(e.keyCode == 13) { sendMessage(); } }); } function sendMessage() { $container = $('.media-list'); $container[0].scrollTop = $container[0].scrollHeight; var message = $("#messageText").val(); var author = $.cookie("realtime-chat-nickname"); $.post( "/messages", {message: message, author: author}, function( data ) { $("#messageText").val("") }); $container.animate({ scrollTop: $container[0].scrollHeight }, "slow"); } }) </script>
Det finns ytterligare en kontroll i koden ovan:cookiedelen. Om du inte har valt något smeknamn för chatten betyder det att kakan inte är inställd för smeknamnet, och du kommer automatiskt att omdirigeras till inloggningssidan.
Om inte kommer de senaste fem meddelandena att hämtas genom ett enkelt Ajax-anrop till /messages
slutpunkt. På samma sätt, när du klickar på Skicka eller tryck på Retur nyckel, kommer textmeddelandet att hämtas från textrutan, och smeknamnet kommer att hämtas från cookien, och dessa värden kommer att skickas till servern med en postbegäran. Det finns ingen strikt kontroll av smeknamnet här, eftersom jag ville fokusera på realtidsdelen, inte användarautentiseringsdelen.
Som du kan se är den övergripande strukturen för projektet mycket enkel. Låt oss komma till implementeringsdelen. Som jag sa tidigare kommer vi att använda Modulus, en av de bästa PaaS för att distribuera, skala och övervaka din applikation på det språk du väljer.
3. Implementering
3.1. Förutsättningar
Det första jag tänker på är att visa dig hur man distribuerar, men för framgångsrik implementering behöver vi en fungerande databas. Låt oss ta en titt på hur man skapar en databas på Modulus och sedan utför distributionen.
Gå till Modulus-instrumentpanelen efter att du har skapat ett konto. Klicka på Databaser menyn till vänster och klicka på Skapa databas.
Fyll i de obligatoriska fälten i popup-formuläret enligt nedan.
När du fyller i de obligatoriska fälten och klickar på Skapa, det kommer att skapa en MongoDB-databas åt dig, och du kommer att se din databas-URL på skärmen. Vi kommer att använda MONGO URI , så kopiera den URI:n.
I vårt projekt hämtas Mongo URI från miljövariabeln MONGO_URI
, och du måste ställa in den miljövariabeln i instrumentpanelen. Gå till instrumentpanelen, klicka på Projekt menyn, välj ditt projekt i listan och klicka på Administration i den vänstra menyn. På den här sidan kommer du att se avsnittet om miljövariabler när du rullar ner på sidan, som visas nedan.
Du kan distribuera till Modulus på två sätt:
- ladda upp projektets ZIP-fil med hjälp av instrumentpanelen
- distribution från kommandoraden med hjälp av Modulus CLI
Jag kommer att fortsätta med kommandoradsalternativet, eftersom det andra är lätt att göra. Först av allt, installera Modulus CLI:
npm install -g modulus
Gå till din projektmapp och utför följande kommando för att logga in på Modulus.
modulus login
När du utför kommandot ovan kommer du att uppmanas att ange ett användarnamn och lösenord:
Om du har skapat ett konto med GitHub kan du använda --github
alternativ.
modulus login --github
Nu är du inloggad på Modulus och det är dags att skapa ett projekt. Använd följande kommando för att skapa ett projekt:
modulus project create "Realtime Chat"
När du kör den här funktionen kommer du att bli tillfrågad om körtiden. Välj det första alternativet, som är Node.js, och för det andra kommer du att bli tillfrågad om servostorleken, och du kan behålla den som standard.
Vi har skapat ett projekt, och den här gången kommer vi att distribuera vårt nuvarande projekt till Modulus. Utför följande kommando för att skicka det aktuella projektet till Realtime Chat projekt på Modulus-sidan.
modulus deploy
Det kommer att distribuera ditt projekt och du kommer att få din pågående projekt-URL i slutet av meddelandet om framgångsrik implementering:
Realtime Chat running at realtime-chat-46792.onmodulus.net
Som du kan se är distributionen till Modulus väldigt enkel!
Modulus CLI har mycket användbara kommandon att använda under din projektinstallation eller vid körning. Till exempel, för att avsluta loggar för ditt pågående projekt, kan du använda modulus project logs tail
, för att skapa en MongoDB-databas använd modulus mongo create <db-name>
, för att ställa in en miljövariabel använd modulus env set <key> <value>
, etc. Du kan se en fullständig lista med kommandon genom att använda Modulus hjälp.