Thursday, August 11, 2016

Build a Real-Time Chat Application With Modulus and Spring Boot_part 2 (end)

3.3. View
In the view part, we have only two pages. One of them is the login page, to get the nickname of the user, and the second one is the main chat page to send messages to chat users.

As you can see in the controller section above, they are rendered by using two endpoints, /login and /chat. To create interactive pages, we will use some third-party JavaScript libraries. We will use them from CDN pages. You can see the login page below:
  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4.     <meta charset="UTF-8"/>
  5.     <title></title>
  6.     <script src="//code.jquery.com/jquery-1.11.1.js"></script>
  7.     <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
  8.     <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
  9.     <script>
  10.         $(function(){
  11.             if ($.cookie("realtime-chat-nickname")) {
  12.                 window.location = "/chat"
  13.             } else {
  14.                 $("#frm-login").submit(function(event) {
  15.                     event.preventDefault();
  16.                     if ($("#nickname").val() !== '') {
  17.                         $.cookie("realtime-chat-nickname", $("#nickname").val());
  18.                         window.location = "/chat";
  19.                     }
  20.                 })
  21.             }
  22.         })
  23.     </script>
  24.     <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"/>
  25.     <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet"/>
  26. </head>
  27. <body>
  28. <div class="container" style="padding-top: 50px">
  29.     <div class="row">
  30.         <div class="col-md-4 col-md-offset-4">
  31.             <div class="login-panel panel panel-default">
  32.                 <div class="panel-heading">
  33.                     <h3 class="panel-title">Choose a nickname to enter chat</h3>
  34.                 </div>
  35.                 <div class="panel-body">
  36.                     <form role="form" id="frm-login">
  37.                         <fieldset>
  38.                             <div class="form-group">
  39.                                 <input class="form-control" placeholder="Enter Nickname" name="nickname" id="nickname" type="text" autofocus="" required=""/>
  40.                             </div>
  41.                             <button type="submit" class="btn btn-lg btn-success btn-block">Enter Chat</button>
  42.                         </fieldset>
  43.                     </form>
  44.                 </div>
  45.             </div>
  46.         </div>
  47.     </div>
  48. </div>
  49. </body>
  50. </html>
On the login page, we have a sample nickname text box. When you click Enter Chat, your nickname will be saved to a cookie. This nickname will be used to set the chat message author field. When you click Enter Chat, the chat page will be opened. If you are already logged in and go to the login page, you will be redirected to the chat page.

Here's the chat page:
  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4.     <meta charset="UTF-8"/>
  5.     <title></title>
  6.     <script src="//code.jquery.com/jquery-1.11.1.js"></script>
  7.     <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
  8.     <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
  9.     <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.4.0/jquery.timeago.min.js"></script>
  10.     <script src="//cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.0.0/sockjs.min.js"></script>
  11.     <script src="//cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script> 
  12.     <script>
  13.         var stompClient = null; 
  14.         function connect() {
  15.             var socket = new SockJS('/newMessage');
  16.             stompClient = Stomp.over(socket);
  17.             stompClient.connect({}, function(frame) {
  18.                 stompClient.subscribe('/topic/newMessage', function(message){
  19.                     refreshMessages(JSON.parse(JSON.parse(message.body).content));
  20.                 });
  21.             });
  22.         } 
  23.         function disconnect() {
  24.             if (stompClient != null) {
  25.                 stompClient.disconnect();
  26.             }
  27.         } 
  28.         function refreshMessages(messages) {
  29.             $(".media-list").html("");
  30.             $.each(messages.reverse(), function(i, message) {
  31.                 $(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div class="media-body">'
  32.                 + message.text + '<br/><small class="text-muted">' + message.author + ' | ' + new Date(message.createDate) + '</small><hr/></div></div></div></li>');
  33.             });
  34.         } 
  35.         $(function(){ 
  36.             if (typeof $.cookie("realtime-chat-nickname") === 'undefined') {
  37.                 window.location = "/login"
  38.             } else {
  39.                 connect();
  40.                 $.get("/messages", function (messages) {
  41.                     refreshMessages(messages)
  42.                 }); 
  43.                 $("#sendMessage").on("click", function() {
  44.                     sendMessage()
  45.                 }); 
  46.                 $('#messageText').keyup(function(e){
  47.                     if(e.keyCode == 13)
  48.                     {
  49.                         sendMessage();
  50.                     }
  51.                 });
  52.             } 
  53.             function sendMessage() {
  54.                 $container = $('.media-list');
  55.                 $container[0].scrollTop = $container[0].scrollHeight;
  56.                 var message = $("#messageText").val();
  57.                 var author = $.cookie("realtime-chat-nickname");
  58.  
  59.                 stompClient.send("/app/newMessage", {}, JSON.stringify({ 'text': message, 'author': author}));
  60.  
  61.                 $("#messageText").val("")
  62.                 $container.animate({ scrollTop: $container[0].scrollHeight }, "slow"); 
  63.             }
  64.         })
  65.     </script>
  66.     <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"/>
  67.     <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet"/>
  68.     <style type="text/css">
  69.         .fixed-panel {
  70.         min-height: 500px;
  71.         max-height: 500px;
  72.         }
  73.         .media-list {
  74.         overflow: auto;
  75.         }
  76.     </style>
  77. </head>
  78. <body>
  79. <div class="container">
  80.     <div class="row " style="padding-top:40px;">
  81.         <h3 class="text-center">Realtime Chat Application with Spring Boot, Websockets, and MongoDB </h3>
  82.         <br/><br/>
  83.  
  84.         <div class="col-md-12">
  85.             <div class="panel panel-info">
  86.                 <div class="panel-heading">
  87.                     <strong><span class="glyphicon glyphicon-list"></span> Chat History</strong>
  88.                 </div>
  89.                 <div class="panel-body fixed-panel">
  90.                     <ul class="media-list">
  91.                     </ul>
  92.                 </div>
  93.                 <div class="panel-footer">
  94.                     <div class="input-group">
  95.                         <input type="text" class="form-control" placeholder="Enter Message" id="messageText" autofocus=""/>
  96.                                     <span class="input-group-btn">
  97.                                         <button class="btn btn-info" type="button" id="sendMessage">SEND <span class="glyphicon glyphicon-send"></span></button>
  98.                                     </span>
  99.                     </div>
  100.                 </div>
  101.             </div>
  102.         </div>
  103.     </div>
  104. </div>
  105. </body>
  106. </html>
This page is for simply viewing and sending messages. Messages are delivered to this page via WebSockets. On this page you can see sockjs and stompjs. Those are for handling notifications. Whenever a new message comes, the latest messages area is repopulated.

By the way, when you first open the chat page, the latest messages will be retrieved in the messages area. As you can see on the JavaScript side, our message channel is newMessage. So, we are listening to this channel, and when you click the Send button, the message in the text box will be sent to the endpoint and that message will be broadcast to the connected clients after successful storage.

As you can see, the software architecture here is very simple and easy to develop. We have production-ready code, and let's deploy it to Modulus.

Modulus is one of the best PaaS for deploying, scaling and monitoring your application in the language of your choice.

4. Deployment 

4.1. Prerequisites
Before deploying the application, let's create a database by using the Modulus admin panel. You need a Modulus account for dba creation and application deployment, so please create an account if you don't have one.

Go to the Modulus dashboard and create a database:


On the database creation screen please provide a database name, select the MongoDB version (I have used 2.6.3, so it will be better if you choose 2.6.3 too), and finally define a user to apply database read/write operations.

You can get a MongoDB URL after successfully creating the database. We will use the MongoDB URL in the environment variables to be used by the Spring Boot application.

To set the environment variables for MongoDB, you need to have an application. Go to Dashboard and click Projects. On this page, click Create New Project.

To continue with configuring the environment variables, please go to Dashboard and click Projects. Select your project, and click Administration. Scroll down the page, and set environment variables with the key SPRING_DATA_MONGODB_URI and value of your database URI:


When you deploy your application, Spring will use that environment variable value. We have done with the requirements, and let's continue with the deployment part.

4.2. Deployment With CLI
In order to deploy the project, run a gradle build task:
  1. gradle build
This task will generate a war file called ROOT.war. Copy this file to a fresh folder and install modulus CLI if you haven't.
  1. npm install -g modulus
Log in to the system;
  1. modulus login
Now execute the following command to deploy ROOT.war to Modulus.
  1. modulus deploy
This will deploy the war file and you can tail project logs to see the status of your deployment by executing the following command:
  1. modulus project logs tail
That's all with the deployment!

5. Conclusion

The main purpose of this tutorial is to show you how to create a real-time chat application with Spring Boot, WebSockets, and MongoDB.

In order to run the project in production, Modulus is used as a PaaS provider. Modulus has very simple steps for deployment, and it also has an internal database (MongoDB) for our projects. Beside this, you can use very helpful tools in the Modulus dashboard like Logs, Notifications, Auto-Scaling, Db Administration, and more.
Written by Hüseyin Babal

If you found this post interesting, follow and support us.
Suggest for you:

Java Programming For Beginners

Complete Java For Selenium WebDriver And Test Automation

The Complete Android & Java Course - Build 21 Android Apps

Android Application Programming - Build 20+ Android Apps

Scalable programming with Scala and Spark

No comments:

Post a Comment