Vertx3 Java版 在线聊天实时推送 官网Demo

Java代码:

package io.vertx.example.web.chat;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.eventbus.EventBus;
import io.vertx.example.util.Runner;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.StaticHandler;
import io.vertx.ext.web.handler.sockjs.BridgeOptions;
import io.vertx.ext.web.handler.sockjs.PermittedOptions;
import io.vertx.ext.web.handler.sockjs.SockJSHandler;

import java.text.DateFormat;
import java.time.Instant;
import java.util.Date;

/**
 * A {@link io.vertx.core.Verticle} which implements a simple, realtime,
 * multiuser chat. Anyone can connect to the chat application on port
 * 8000 and type messages. The messages will be rebroadcast to all
 * connected users via the @{link EventBus} Websocket bridge.
 *
 * @author <a href="https://github.com/InfoSec812">Deven Phillips</a>
 */
public class Server extends AbstractVerticle {

  // Convenience method so you can run it in your IDE
  public static void main(String[] args) {
    Runner.runExample(Server.class);
  }

  @Override
  public void start() throws Exception {

    Router router = Router.router(vertx);

    // Allow events for the designated addresses in/out of the event bus bridge
    BridgeOptions opts = new BridgeOptions()
      .addInboundPermitted(new PermittedOptions().setAddress("chat.to.server"))
      .addOutboundPermitted(new PermittedOptions().setAddress("chat.to.client"));

    // Create the event bus bridge and add it to the router.
    SockJSHandler ebHandler = SockJSHandler.create(vertx).bridge(opts);
    router.route("/eventbus/*").handler(ebHandler);

    // Create a router endpoint for the static content.
    router.route().handler(StaticHandler.create());

    // Start the web server and tell it to use the router to handle requests.
    vertx.createHttpServer().requestHandler(router::accept).listen(8080);

    EventBus eb = vertx.eventBus();

    // Register to listen for messages coming IN to the server
    eb.consumer("chat.to.server").handler(message -> {
      // Create a timestamp string
      String timestamp = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(Date.from(Instant.now()));
      // Send the message back out to all clients with the timestamp prepended.
      eb.publish("chat.to.client", timestamp + ": " + message.body());
    });

  }
}
 

 页面代码:

<!--
  #%L
  distributed-chat-service
  %%
  Copyright (C) 2015 Zanclus Consulting
  %%
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
  
       http://www.apache.org/licenses/LICENSE-2.0
  
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  #L%
  -->
<html>
<head>
  <title>Distributed Chat Service</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  <script src="//cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script>
  <script src="vertxbus.js"></script>
  <style>
    .inset {
      box-shadow: inset 0 0 4px #000000;
      -moz-box-shadow: inset 0 0 4px #000000;
      -webkit-box-shadow: inset 0 0 4px #000000;
      width: 400px;
      border-width: 4px;
      padding: 5px;
    }

    input.inset {
      height: 40px;
    }

    div.inset {
      height: 500px;
      white-space: pre-wrap
    }
  </style>
</head>
<body>
<script>
  var eb = new vertx.EventBus("/eventbus/");
  eb.onopen = function () {
    eb.registerHandler("chat.to.client", function (msg) {
      $('#chat').append(msg + "\n");
    });
  };

  function send(event) {
    if (event.keyCode == 13 || event.which == 13) {
      var message = $('#input').val();
      if (message.length > 0) {
        console.log($('#input'));
        eb.publish("chat.to.server", message);
        $('#input').val("");
      }
    }
  }
</script>
<div id="chat" class="inset"></div>
<input id="input" type="text" onkeydown="send(event)" class="inset">
</body>
</html>

Js引用资源:

/*
 * Copyright 2014 Red Hat, Inc.
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Apache License v2.0 which accompanies this distribution.
 *
 *  The Eclipse Public License is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  The Apache License v2.0 is available at
 *  http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under either of these licenses.
 */

/*
 *   Copyright (c) 2011-2013 The original author or authors
 *   ------------------------------------------------------
 *   All rights reserved. This program and the accompanying materials
 *   are made available under the terms of the Eclipse Public License v1.0
 *   and Apache License v2.0 which accompanies this distribution.
 *
 *       The Eclipse Public License is available at
 *       http://www.eclipse.org/legal/epl-v10.html
 *
 *       The Apache License v2.0 is available at
 *       http://www.opensource.org/licenses/apache2.0.php
 *
 *   You may elect to redistribute this code under either of these licenses.
 */

var vertx = vertx || {};

!function(factory) {
  if (typeof define === "function" && define.amd) {
    // Expose as an AMD module with SockJS dependency.
    // "vertxbus" and "sockjs" names are used because
    // AMD module names are derived from file names.
    define("vertxbus", ["sockjs"], factory);
  } else {
    // No AMD-compliant loader
    factory(SockJS);
  }
}(function(SockJS) {

  vertx.EventBus = function(url, options) {
  
    var that = this;
    var sockJSConn = new SockJS(url, undefined, options);
    var handlerMap = {};
    var replyHandlers = {};
    var state = vertx.EventBus.CONNECTING;
    var pingTimerID = null;
    var pingInterval = null;
    if (options) {
      pingInterval = options['vertxbus_ping_interval'];
    }
    if (!pingInterval) {
      pingInterval = 5000;
    }
  
    that.onopen = null;
    that.onclose = null;

    that.send = function(address, message, replyHandler) {
      sendOrPub("send", address, message, replyHandler)
    }
  
    that.publish = function(address, message) {
      sendOrPub("publish", address, message, null)
    }
  
    that.registerHandler = function(address, handler) {
      checkSpecified("address", 'string', address);
      checkSpecified("handler", 'function', handler);
      checkOpen();
      var handlers = handlerMap[address];
      if (!handlers) {
        handlers = [handler];
        handlerMap[address] = handlers;
        // First handler for this address so we should register the connection
        var msg = { type : "register",
                    address: address };
        sockJSConn.send(JSON.stringify(msg));
      } else {
        handlers[handlers.length] = handler;
      }
    }
  
    that.unregisterHandler = function(address, handler) {
      checkSpecified("address", 'string', address);
      checkSpecified("handler", 'function', handler);
      checkOpen();
      var handlers = handlerMap[address];
      if (handlers) {
        var idx = handlers.indexOf(handler);
        if (idx != -1) handlers.splice(idx, 1);
        if (handlers.length == 0) {
          // No more local handlers so we should unregister the connection
  
          var msg = { type : "unregister",
                      address: address};
          sockJSConn.send(JSON.stringify(msg));
          delete handlerMap[address];
        }
      }
    }
  
    that.close = function() {
      checkOpen();
      state = vertx.EventBus.CLOSING;
      sockJSConn.close();
    }
  
    that.readyState = function() {
      return state;
    }
  
    sockJSConn.onopen = function() {
      // Send the first ping then send a ping every pingInterval milliseconds
      sendPing();
      pingTimerID = setInterval(sendPing, pingInterval);
      state = vertx.EventBus.OPEN;
      if (that.onopen) {
        that.onopen();
      }
    };
  
    sockJSConn.onclose = function() {
      state = vertx.EventBus.CLOSED;
      if (pingTimerID) clearInterval(pingTimerID);
      if (that.onclose) {
        that.onclose();
      }
    };
  
    sockJSConn.onmessage = function(e) {
      var msg = e.data;
      var json = JSON.parse(msg);
      var type = json.type;
      if (type === 'err') {
        console.error("Error received on connection: " + json.body);
        return;
      }
      var body = json.body;
      var replyAddress = json.replyAddress;
      var address = json.address;
      var replyHandler;
      if (replyAddress) {
        replyHandler = function(reply, replyHandler) {
          // Send back reply
          that.send(replyAddress, reply, replyHandler);
        };
      }
      var handlers = handlerMap[address];
      if (handlers) {
        // We make a copy since the handler might get unregistered from within the
        // handler itself, which would screw up our iteration
        var copy = handlers.slice(0);
        for (var i  = 0; i < copy.length; i++) {
          copy[i](body, replyHandler);
        }
      } else {
        // Might be a reply message
        var handler = replyHandlers[address];
        if (handler) {
          delete replyHandlers[address];
          handler(body, replyHandler);
        }
      }
    }

    function sendPing() {
      var msg = {
        type: "ping"
      }
      sockJSConn.send(JSON.stringify(msg));
    }
  
    function sendOrPub(sendOrPub, address, message, replyHandler) {
      checkSpecified("address", 'string', address);
      checkSpecified("replyHandler", 'function', replyHandler, true);
      checkOpen();
      var envelope = { type : sendOrPub,
                       address: address,
                       body: message };
      if (replyHandler) {
        var replyAddress = makeUUID();
        envelope.replyAddress = replyAddress;
        replyHandlers[replyAddress] = replyHandler;
      }
      var str = JSON.stringify(envelope);
      sockJSConn.send(str);
    }
  
    function checkOpen() {
      if (state != vertx.EventBus.OPEN) {
        throw new Error('INVALID_STATE_ERR');
      }
    }
  
    function checkSpecified(paramName, paramType, param, optional) {
      if (!optional && !param) {
        throw new Error("Parameter " + paramName + " must be specified");
      }
      if (param && typeof param != paramType) {
        throw new Error("Parameter " + paramName + " must be of type " + paramType);
      }
    }
  
    function isFunction(obj) {
      return !!(obj && obj.constructor && obj.call && obj.apply);
    }
  
    function makeUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
        .replace(/[xy]/g,function(a,b){return b=Math.random()*16,(a=="y"?b&3|8:b|0).toString(16)})}
  
  }
  
  vertx.EventBus.CONNECTING = 0;
  vertx.EventBus.OPEN = 1;
  vertx.EventBus.CLOSING = 2;
  vertx.EventBus.CLOSED = 3;

  return vertx.EventBus;

});

猜你喜欢

转载自harborchung.iteye.com/blog/2229594