What is the experience of writing a web chat room with ActFramework

When I saw t-io Lao Tan's experience of using t-io to write a web chat room or customer service , I was itching for a while, so I planned to use ActFramework to write a web chat room to see what the experience was.

Don't talk nonsense, just roll up your sleeves and do it.

1. Create a project

Run the following command to create a new ActFramework application project:

mvn archetype:generate -B \
    -DgroupId=com.myproj \
    -DartifactId=chatroom \
    -DarchetypeGroupId=org.actframework \
    -DarchetypeArtifactId=archetype-quickstart \
    -DarchetypeVersion=1.8.7.3

2. Project directory structure

After running, you can see the following directory structure:

.
├── pom.xml
├── run_dev
├── run_dev.bat
├── run_prod
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── myproj
    │   │           └── AppEntry.java
    │   └── resources
    │       ├── com
    │       │   └── myproj
    │       ├── conf
    │       │   ├── app.properties
    │       │   ├── prod
    │       │   │   └── app.properties
    │       │   └── uat
    │       │       └── app.properties
    │       ├── logback.xml
    │       └── rythm
    │           └── com
    │               └── myproj
    │                   └── AppEntry
    │                       └── home.html
    └── test
        └── java
            └── com
                └── myproj

3. pom.xml file

The generated project pom.xml is very simple, open it and it should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.myproj</groupId>
  <artifactId>chatroom</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>My Awesome Application</name>

  <parent>
    <groupId>org.actframework</groupId>
    <artifactId>act-starter-parent</artifactId>
    <version>1.8.7.1</version>
  </parent>

  <properties>
    <java.version>1.8</java.version>
    <app.entry>com.myproj.AppEntry</app.entry>
  </properties>

</project>

4. Server code

As far as our chat room application is concerned, without adding any other dependencies, go straight to the com.myproj.AppEntry file:

package com.myproj;

import act.Act;
import act.inject.DefaultValue;
import act.util.Output;
import org.osgl.mvc.annotation.GetAction;

/**
 * A simple hello world app entry
 *
 * Run this app, try to update some of the code, then
 * press F5 in the browser to watch the immediate change
 * in the browser!
 */
@SuppressWarnings("unused")
public class AppEntry {

    /**
     * The home (`/`) endpoint.
     *
     * This will accept a query parameter named `who` and
     * render a template (resources/rythm/__package__/AppEntry/home.html),
     * where `__package__` corresponding to the package name, e.g.
     * if your package is `com.mycomp.myproj`, then `__package__`
     * is `com/mycomp/myproj`.
     *
     * @param who
     *      request query parameter to specify the hello target.
     *      default value is `World`.
     */
    @GetAction
    public void home(@DefaultValue("World") @Output String who) {
    }

    public static void main(String[] args) throws Exception {
        Act.start();
    }

}

Remove the unnecessary comments, change the homemethod slightly, remove whothe parameters, and make this file a little cleaner:

package com.myproj;

import act.Act;
import org.osgl.mvc.annotation.GetAction;

public class AppEntry {

    /**
     * 响应 `/` 请求. 调用 `home.html` 模板生成 HTML 页面响应
     */
    @GetAction
    public void home() {
    }

    public static void main(String[] args) throws Exception {
        Act.start();
    }

}

4.1 Websocket message processing method

The following is the meat game, we need to add a method to the AppEntryclass to handle the websocket request, that is, the instant message sent by the chat room:

    @WsAction("msg")
    public void onMessage(String message, WebSocketContext context) {
        // suppress blank lines
        if (S.notBlank(message)) {
            context.sendToPeers(message);
        }
    }

That's it? 6 lines of code to handle the websocket message processing on the server side? I don't read much so I won't lie to you, it's really like this

Now look at the front end, find the home.html file in the above directory structure, open it and see this:

<!DOCTYPE html>
<html lang="en">
@args String who
<head>
  <title>Hello World - ActFramework</title>
</head>
<body>
  <h1>Hello @who</h1>
  <p>
    Powered by ActFramework @act.Act.VERSION.getVersion()
  </p>
</body>
</html>

We need to transform it into a simple chat room:

<html>
<head>
  <title>WebSocket Chat</title>
  <script src="/~/asset/js/jquery.js"></script>
  <script src="/~/asset/js/jquery.ext.js"></script>
  <style type="text/css">
    html,body {
      width:100%;
      height:100%;
      background-color: black;
      color: beige;
    }

    body {
      height: 80%;
    }

    input {
      padding: 8px 5px;
    }

    .center {
      margin-left: auto;
      margin-right: auto;
      width: 70%;
    }

    .chatform {
      margin-left: auto;
      margin-right: auto;
      margin-bottom: 0;
      width: 70%;
    }
    form{
      width: 100%;
    }
    label{
      display: inline;
      width: 100px;
    }
    #msg{
      display: inline;
      width: 100%;
    }

  </style>
</head>
<body>
<div class="page">
  <div class="center" >
    <h1>WebSocket @i18n("demo") - @i18n("chatroom")</h1>
    <div id="chat" style="height:100%;width: 100%; overflow: auto;">
    </div>
    <form onsubmit="return false;" class="chatform" action="">
      <label for="msg">@i18n("message")</label>
      <input type="text" name="message" id="msg"  onkeypress="if(event.keyCode==13) { send(this.form.message.value); this.value='' } " />
    </form>
  </div>
</div>
<script>
      var socket;

      function connect() {
          socket = $.createWebSocket('/msg');
          //socket = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/msg");
          socket.onmessage = function (event) {
              var home = document.getElementById('chat');
              home.innerHTML = home.innerHTML + event.data + "<br />";
          };
      }

      if (window.WebSocket) {
          connect();
      } else {
          alert("Your browser does not support Websockets. (Use Chrome)");
      }

      function send(message) {
          if (!window.WebSocket) {
              return false;
          }
          if (socket.readyState === WebSocket.OPEN) {
              socket.send(message);
          } else {
              reconnect(message);
          }
          return false;
      }

      function reconnect(message) {
          connect();
          setTimeout(function() {
            if (socket.readyState == WebSocket.OPEN) {
                socket.send(message);
            } else {
                alert("The socket is not open.");
            }
          }, 500);
      }
  </script>
</body>
</html>

Note that the /~/asset/js/jquery.ext.jsabove is a small extension to jQuery that comes with ActFramework, which has a $.createWebSocket()method to create a client-side websocket client.

Ok, let's try it out now. Run in the project directory:

mvn compile act:run

After running the above command, you can almost see the following console message

   ___   _  _     _     _____   ___    ___     ___    __  __ 
  / __| | || |   /_\   |_   _| | _ \  / _ \   / _ \  |  \/  |
 | (__  | __ |  / _ \    | |   |   / | (_) | | (_) | | |\/| |
  \___| |_||_| /_/ \_\   |_|   |_|_\  \___/   \___/  |_|  |_|
                                                             
                          powered by ActFramework r1.8.7-2f28

 version: v1.0-SNAPSHOT-180505_2214
scan pkg: com.myproj
base dir: /home/luog/p/greenlaw110/chatroom
     pid: 20757
 profile: dev
    mode: DEV

     zen: Readability counts.

2018-05-05 22:14:54,447 INFO  a.Act@[main] - loading application(s) ...
2018-05-05 22:14:54,459 INFO  a.a.App@[main] - App starting ....
2018-05-05 22:14:54,639 WARN  a.h.b.ResourceGetter@[main] - URL base not exists: META-INF/resources/webjars
2018-05-05 22:14:54,653 WARN  a.a.DbServiceManager@[main] - DB service not initialized: No DB plugin found
2018-05-05 22:14:55,379 WARN  a.m.MailerConfig@[main] - smtp host configuration not found, will use mock smtp to send email
2018-05-05 22:14:55,831 INFO  a.a.App@[main] - App[chatroom] loaded in 1372ms
2018-05-05 22:14:55,837 INFO  a.a.ApiManager@[jobs-thread-3] - start compiling API book
2018-05-05 22:14:55,857 INFO  o.xnio@[main] - XNIO version 3.3.8.Final
2018-05-05 22:14:55,885 INFO  o.x.nio@[main] - XNIO NIO Implementation Version 3.3.8.Final
2018-05-05 22:14:56,003 INFO  a.Act@[main] - network client hooked on port: 5460
2018-05-05 22:14:56,004 INFO  a.Act@[main] - CLI server started on port: 5461
2018-05-05 22:14:56,005 INFO  a.Act@[main] - app is ready at: http://192.168.1.2:5460
2018-05-05 22:14:56,005 INFO  a.Act@[main] - it takes 2269ms to start the app

Now is the time to test the results, go straight to the browser, open http://localhost:5460/ and start playing:

Result presentation

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325387189&siteId=291194637