WebSocket初建聊天室

最近在新观css3与html5相关的内容时,发现一个不错的好东西WebSocket,以前只是用过Oracle内建包的UTL_TCP,对于直接用socket与第三方服务进行通讯,确实是一件让人比较爽的事情,一些新思路顿时开阔起来。WebSocket允许浏览器里直接调用socket与服务器进行通讯,同时服务器还能主动给浏览器端进行消息推送,确实进一步丰富了BS结构,至少在浏览器里的游戏、新业务的实现,都提供了一个不错的技术选择,但是新技术毕竟还只是起步阶段,还有很多需要不断完善。

下面通过一个聊天室的例子,来慢慢了解WebSocket吧,详细的注释说明参考代码。

运行环境:

1 tomcat 8 用户web服务器及websocket服务器(其实是一个服务器,主要是WebSocket的TCP握手连接协议依赖于http协义,详细的文章参考http://tomcat.apache.org/tomcat-8.0-doc/web-socket-howto.html)

2 Myeclips 10.7,主要是用于类的编写(回头tomcat 8对应的webapps直接改到路径WebRoot对应的路径,即<Context path="/html5" docBase="D:\forDBCl\Html5\WebRoot" reloadable="true"></Context>),该版本的myeclips不支持集成tomcat 8

以上环境最大的不方便是没有办法进行调试。

强烈推荐:Myclips2015,上面可以直接开搞。


2 相关的脚本代码

2.1 WebSocket服务端参考代码,消息处理核心类

package com.cn.ljb.html5;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import com.cn.ljb.util.CommonUtils;
//后面的字符串决定了请建立websocket连接地址内容的一部分
@ServerEndpoint(value = "/websocket/chat")
public class WSChatServlet{

    private static final String GUEST_PREFIX = "Guest";
    private static final AtomicInteger connectionIds = new AtomicInteger(0);
    private static final Set<WSChatServlet> connections =
            new CopyOnWriteArraySet<WSChatServlet>();

    private Session lsession;
    private String connectFlag;
    private String nickname = "defaultNick";

    public WSChatServlet() {
    	connectFlag = GUEST_PREFIX + connectionIds.getAndIncrement();
        System.out.println("-------WSChatServlet run construct function"+connectFlag);
    }

    @OnOpen
    public void start(Session session) {
    	if(connections.contains(this))
    		System.out.println("session has exist in the Set,and Setsize="+connections.size());
    	else{
    		lsession = session;
    		connections.add(this);
    	}
    	System.out.println("-----------onOpen CurrentConnections="+connections.size()+",Flag="+connectFlag);
        //String message = String.format("* %s %s", connectFlag, ".....加入聊天室......");
        //broadcast(message);
    }


    @OnClose
    public void end() {
        if(connections.remove(this)){
	    	System.out.println("-----------affter OnClose CurrentConnections="+connections.size());
	        broadcast("....我离开了聊天室...",this.nickname);
        }
    }


    @OnMessage
    public void incoming(String message) {
        // Never trust the client
		String filteredMessage = CommonUtils.filter(message.toString());
		System.out.println("----sendMessage="+filteredMessage);
		String data[] = filteredMessage.split("[|]");
    	if(data!=null && data.length>0){
    		this.nickname = data[0];
    		broadcast(data[1],this.nickname);
    	}
    }

    @OnError
    public void onError(Throwable t) throws Throwable {
        System.out.println("--------------Chat Error: " + t.toString());
    }

    /**
     * @param type 1 连接消息  2 正式消息 3 离开消息
     * @param msg 消息主体
     * @param userName 消息发送人
     */
    private static void broadcast(String msg,String userName) {
    	String jsonData = String.format("[{\"username\":\"%s\",\"content\":\"%s\"}]", userName+" "+CommonUtils.getLongDateNow(1),msg);
        for (WSChatServlet client : connections) {
            try {
                synchronized (client) {
                    client.lsession.getBasicRemote().sendText(jsonData);
                }
            } catch (IOException e) {
            	System.out.println("Chat Error: Failed to send message to client");
                connections.remove(client);
                try {
                    client.lsession.close();
                } catch (IOException e1) {
                    // Ignore
                }
                broadcast("......我离开了......",userName);
            }
        }
    }
    
    
}

2.2 相关的工具辅助类,没有什么好讲的

package com.cn.ljb.util;

import java.util.Calendar;
import java.util.Date;

public class CommonUtils {
    public static String filter(String message) {

        if (message == null)
            return (null);

        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuilder result = new StringBuilder(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("<");
                break;
            case '>':
                result.append(">");
                break;
            case '&':
                result.append("&");
                break;
            case '"':
                result.append(""");
                break;
            default:
                result.append(content[i]);
            }
        }
        return (result.toString());

    }
    
    public static String getLongDateNow(int dataType) {
		Calendar now = Calendar.getInstance();
		String dateString = null;
		now.setTime(new Date());
		switch(dataType){
		case 1:
			dateString = String.format("%04d-%02d-%02d %02d:%02d:%02d.%03d", 
					now.get(Calendar.YEAR),
					now.get(Calendar.MONTH)+1,
					now.get(Calendar.DAY_OF_MONTH),
					now.get(Calendar.HOUR_OF_DAY),
					now.get(Calendar.MINUTE),
					now.get(Calendar.SECOND),
					now.get(Calendar.MILLISECOND));
			break;
		case 2:
			dateString = String.format("%04d-%02d-%02d", 
					now.get(Calendar.YEAR),
					now.get(Calendar.MONTH)+1,
					now.get(Calendar.DAY_OF_MONTH));
			break;
		case 3:
			now.add(Calendar.DAY_OF_MONTH, -1);
			dateString = String.format("%04d-%02d-%02d", 
					now.get(Calendar.YEAR),
					now.get(Calendar.MONTH)+1,
					now.get(Calendar.DAY_OF_MONTH));
			break;
		default:
			break;
		}
		return dateString;
	}
}

3 前端页面代码及js代码(合到一起了)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>测试聊天程序基于WebSocket</title>
<style type="text/css">
#console {
	border-radius:5px;
    border: 1px solid #CCCCCC;
    border-right-color: #999999;
    border-bottom-color: #999999;
    height: 300px;
    overflow-y: scroll;
    padding: 5px;
    width: 100%;
}
#console p {padding: 0;margin: 0;}
</style>

</head>
<body>
	<div id="mainContent" style="margin:0 auto;height:300px;width:50%;text-align:left;">
		<div id="console-container" style="margin:0 auto;height:300px;width:100%;padding-bottom:10px;">
			<div id="console"></div>
		</div>
		<p><nav>
			<input type="button" value="加入群聊" οnclick="joinChat()">
		</nav></p>
		<p>
			<span>昵称:</span><input id="nickname" type="text" style="width:20%;" placeholder="输入昵称">
			<input type="text" style="width:80%;" placeholder="输入你的聊天内容,回车发送" id="chat" />  <input type="button" value="发送消息" οnclick="sendMessage()">
		</p>
	</div>
</body>
</html>
<script type="text/javascript">
var ynickname=null;
var Chat = {};
Chat.socket = null;
Chat.connect = (function(host) {
	
    if ('WebSocket' in window) {
        Chat.socket = new WebSocket(host);
    } else if ('MozWebSocket' in window) {
        Chat.socket = new MozWebSocket(host);
    } else {
        Console.log("<h2 style='color: #ff0000'>该浏览器不支持websocket技术,请使用chrome或firefox等其他浏览器!</h2>");
        return;
    }
	
    Chat.socket.onopen = function () {
    	document.getElementById('chat').onkeydown = function(event) {
            if (event.keyCode == 13) {
               sendMessage();
            }
        };
    	Chat.socket.send(ynickname+"|我加入了聊天哦");
        //Console.log("消息:"+document.getElementById("nickname").value+" connect server success");
        
    };

    Chat.socket.onclose = function () {
        document.getElementById('chat').onkeydown = null;
        //Console.log("消息:"+document.getElementById("nickname").value+" close connection from server");
    };

    Chat.socket.onmessage = function (message) {
        Console.log(message.data);
    };
});

Chat.initialize = function() {
	if(ynickname==null){
		var nkname = document.getElementById('nickname').value;
	    if(nkname==''){
	    	alert("请先给自己取一个昵称,然后开始聊天呗!");
	    	return;
	    } else {
	    	ynickname = nkname;
	    }
	} else {
		document.getElementById('nickname').value = ynickname;
	}
    
    if(Chat.socket==null)
	    if (window.location.protocol == 'http:') {
	        Chat.connect('ws://'+window.location.host+'/html5<strong>/websocket/chat</strong>');
	    } else {
	        Chat.connect('wss://'+window.location.host+'/html5<strong>/websocket/chat</strong>');
	    }
    
    
};

Chat.sendConnMessage = (function(inputMsg) {
	if(inputMsg!='' || inputMsg!=null){
		var sendResult = Chat.socket.send(inputMsg);
	}
		
});

Chat.disConnect = (function() {
    Chat.socket.onclose();
});

var Console = {};
Console.log = (function(message) {
	var jsonData = eval(message);
	if(jsonData.length>0){
	    var console = document.getElementById('console');
	    var p = document.createElement('p');
	    p.style.wordWrap = 'break-word';
	    p.innerHTML = "<font color='blue'>"+jsonData[0].username+":</font><br>    "+jsonData[0].content;
	    console.appendChild(p);
	    while (console.childNodes.length > 25) {
	        console.removeChild(console.firstChild);
	    }
	    console.scrollTop = console.scrollHeight;
    }
});

function joinChat(){
	Chat.initialize();
}

function sendMessage(){
	if(ynickname==null){
		var nkname = document.getElementById('nickname').value;
	    if(nkname==''){
	    	alert("请先给自己取一个昵称,然后开始聊天呗!");
	    	return;
	    } else {
	    	ynickname = nkname;
	    }
	} else {
		document.getElementById('nickname').value = ynickname;
	}
	
	var message = document.getElementById('chat').value;
    if (message != '') {
        Chat.sendConnMessage(ynickname+"|"+message);
        document.getElementById('chat').value = '';
    }
}

function leaveChat(){
	Chat.disConnect();
}

</script>

最终的基本代码是全部在上面了!我们再来看一个效果截图,拿个拔号路由器配置一条转发,就能轻松跟好友们搭建临时聊天室了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值