1. 程式人生 > >java WebSocket實現簡單的聊天室(包括群發和點對點聊天)

java WebSocket實現簡單的聊天室(包括群發和點對點聊天)

今天突然看到了WebSocket然後就網上找了一個例子,然後修改了下,實現了簡單的聊天室,包括群聊和點對點聊天。

使用的程式碼如下

jsp程式碼:

<%@ 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>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'socket.jsp' starting page</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  <style type="text/css">  
        input#chat {  
            width: 410px  
        }  
  
        #console-container {  
            width: 400px;  
        }  
  
        #console {  
            border: 1px solid #CCCCCC;  
            border-right-color: #999999;  
            border-bottom-color: #999999;  
            height: 170px;  
            overflow-y: scroll;  
            padding: 5px;  
            width: 100%;  
        }  
  
        #console p {  
            padding: 0;  
            margin: 0;  
        }  
    </style>  
    <script type="application/javascript"> 
        "use strict";  
  
        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('Error: 瀏覽器不支援WebSocket');  
                return;  
            }  
  
            Chat.socket.onopen = function () {  
                Console.log('Info: WebSocket連結已開啟');  
                document.getElementById('chat').onkeydown = function(event) {  
                    if (event.keyCode == 13) {  
                        Chat.sendMessage();  
                    }  
                };  
            };  
  
            Chat.socket.onclose = function () {  
                document.getElementById('chat').onkeydown = null;  
                Console.log('Info: webcocket關閉.');  
            };  
  
            Chat.socket.onmessage = function (message) {  
                Console.log(message.data);  
            };  
        });  
  
        Chat.initialize = function() {  
            if (window.location.protocol == 'http:') {  
                Chat.connect('ws://' + window.location.host + '/gtweb/chat');  
            } else {  
                Chat.connect('wss://' + window.location.host + '/gtweb/chat');  
            }  
        };  
  
        Chat.sendMessage = (function() {  
            var message = document.getElementById('chat').value;  
            if (message != '') {  
                Chat.socket.send(message);  
                document.getElementById('chat').value = '';  
            }  
        });  
  
        var Console = {};  
  
        Console.log = (function(message) {  
            var console = document.getElementById('console');  
            var p = document.createElement('p');  
            p.style.wordWrap = 'break-word';  
            p.innerHTML = message;  
            console.appendChild(p);  
            while (console.childNodes.length > 25) {  
                console.removeChild(console.firstChild);  
            }  
            console.scrollTop = console.scrollHeight;  
        });  
  
        Chat.initialize();  
  
        document.addEventListener("DOMContentLoaded", function() {  
            // Remove elements with "noscript" class - <noscript> is not allowed in XHTML  
            var noscripts = document.getElementsByClassName("noscript");  
            for (var i = 0; i < noscripts.length; i++) {  
                noscripts[i].parentNode.removeChild(noscripts[i]);  
            }  
        }, false);  
  
    </script>  
</head>  
<body>  
<div class="noscript"><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable  
    Javascript and reload this page!</h2></div>  
<div>  
    <p>  
        <input type="text" placeholder="輸入文字,回車傳送" id="chat" /><br>
        注意:輸入  訊息to使用者名稱   傳送給指定使用者   比如:  你好to使用者1<br>    
                   輸入   訊息     直接傳送給全體使用者    
    </p>  
    <div id="console-container">  
        <div id="console"/>  
    </div>  
</div>  
</body>
</html>
後臺程式碼:
/**
 *  ━━━━━━神獸出沒━━━━━━ 
 *   ┏┓   ┏┓ 
 *  ┏┛┻━━━┛┻┓ 
 *     ┃       ┃
 * 	  ┃   ━   ┃ 
 *     ┃ ┳┛ ┗┳    ┃ 
 *  ┃       ┃ 
 *  ┃   ┻   ┃ 
 *  ┃       ┃ 
 *  ┗━┓   ┏━┛Code is far away from bug with the animal protecting 
 *    ┃   ┃    神獸保佑,程式碼無bug 
 *    ┃   ┃ 
 *    ┃   ┗━━━┓ 
 *    ┃       ┣┓ 
 *    ┃       ┏┛ 
 *    ┗┓┓┏━┳┓┏┛ 
 *     ┃┫┫ ┃┫┫ 
 *     ┗┻┛ ┗┻┛ 
 * 
 * ━━━━━━感覺萌萌噠━━━━━━ 
 */
package gt.controller.admin;

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 org.springframework.web.bind.annotation.RequestMapping;

/**
 * 類名稱:ChatAnnotation.java 類描述:簡單的聊天室 作 者:why 時 間:2017年3月7日
 */
@ServerEndpoint(value = "/chat")
public class ChatAnnotation {
	private static final String GUEST_PREFIX = "使用者";
	/**
	 * 一個提供原子操作的Integer的類。在Java語言中,++i和i++操作並不是執行緒安全的,
	 * 在使用的時候,不可避免的會用到synchronized關鍵字。 而AtomicInteger則通過一種執行緒安全的加減操作介面。
	 */
	private static final AtomicInteger connectionIds = new AtomicInteger(0);
	private static final Set<ChatAnnotation> connections = new CopyOnWriteArraySet<>();

	private final String nickname;
	private Session session;

	public ChatAnnotation() {
		nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
	}

	/**
	 * 建立連線時間呼叫的方法
	 * 
	 * @param session
	 */
	@OnOpen
	public void start(Session session) {
		this.session = session;
		connections.add(this);
		String message = String.format("* %s %s", nickname, "加入聊天室");
		//上線通知
		broadcast(message);
		try {
			//系統問候語
			SendHello(this.nickname);
			//返回線上使用者
			onlineList();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	/**
	 * 連結關閉時呼叫方法
	 */
	@OnClose
	public void end() {
		connections.remove(this);
		String message = String.format("* %s %s", nickname, "退出聊天室");
		broadcast(message);
	}
	/**
	 * 傳輸資訊過程中呼叫方法
	 * @param message
	 */
	@OnMessage
	public void incoming(String message) {
		// Never trust the client
		// TODO: 過濾輸入的內容
		String m = String.format("* %s %s", nickname, message);
		if(m.contains("to")){
			//點對點發送
			broadcastOneToOne(m,nickname);
		}else{
			//群發
			broadcast(m);
		}
	}
	/**
	 * 發生錯誤是呼叫方法
	 * @param t
	 * @throws Throwable
	 */
	@OnError
	public void onError(Throwable t) throws Throwable {
		System.out.println("錯誤: " + t.toString());
	}
	/**
	 * 訊息廣播
	 * 通過connections,對所有其他使用者推送資訊的方法
	 * @param msg
	 */
	private static void broadcast(String msg) {
		for (ChatAnnotation client : connections) {
			try {
				synchronized (client) {
					client.session.getBasicRemote().sendText(msg);
				}
			} catch (IOException e) {
				System.out.println("錯誤:向客戶端傳送訊息失敗");
				connections.remove(client);
				try {
					client.session.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				String message = String.format("* %s %s", client.nickname,"退出聊天室");
				broadcast(message);
			}
		}
	}
	/**
	 * 點對點發送訊息
	 * 通過connections,對所有其他使用者推送資訊的方法
	 * @param msg
	 */
	private static void broadcastOneToOne(String msg, String nickName) {
		String[] arr = msg.split("to");
		for (ChatAnnotation client : connections) {
			try {
				if(arr[1].equals(client.nickname) || nickName.equals(client.nickname)){
					synchronized (client) {
						client.session.getBasicRemote().sendText(arr[0]);
					}
				}
			} catch (IOException e) {
				System.out.println("錯誤:向客戶端傳送訊息失敗");
				connections.remove(client);
				try {
					client.session.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				String message = String.format("* %s %s", client.nickname,"退出聊天室");
				broadcast(message);
			}
		}
	}
	//系統問候語
	private static void SendHello(String nickName) throws IOException{
		String m = String.format("* %s %s", nickName, "你好");
		for (ChatAnnotation client : connections) {
			if(client.nickname.equals(nickName)){
				client.session.getBasicRemote().sendText(m);
			}
		}
	}
	//線上使用者
	private static void onlineList() throws IOException{
		String online = "";
		for (ChatAnnotation client : connections) {
			if(online.equals("")){
				online = client.nickname;
			}else{
				online += ","+client.nickname;
			}
		}
		String m = String.format("* %s %s", "當前線上使用者", online);
		for (ChatAnnotation client : connections) {
			client.session.getBasicRemote().sendText(m);
		}
	}
}

註釋都加在程式碼中了,到此簡單的聊天室就可以使用了。

如圖所示。