天天看點

關于websocket小聊天室

1、先來看看效果吧
關于websocket小聊天室

這個項目是spring boot的裡搞的,隻要把類放到項目裡就可以運作了

1、pom.xml 添加依賴

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
		</dependency>
           

2、添加一個java檔案(websocket 的預設服務)

@Configuration
public class WebSocketConfig {
	
	@Bean  
    public ServerEndpointExporter serverEndpointExporter() {  
        return new ServerEndpointExporter();  
    }  

}
           

3、在添加一個接收資料的工具類

@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class WebSocketServer {

	private static int onlineCount = 0;
	private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
	private static ConcurrentHashMap<String,Session> webSocketMap = new ConcurrentHashMap<String,Session>();
	private Session session;

	/**
	 * 連接配接建立成功調用的方法
	 */
	@OnOpen
	public void onOpen(Session session,@PathParam("userId")String  userId) {
		this.session = session;
		webSocketSet.add(this); // 加入set中
		webSocketMap.put(userId, session);
		addOnlineCount(); // 線上數加1
		System.out.println("有新連接配接加入!目前線上人數為" + getOnlineCount());
		//推送我到所有人清單裡
//		try {
//			sendMessage("連結已經建立!");
//		} catch (IOException e) {
//			System.out.println("IO異常");
//		}
		sendUserList(session);
	}
	
	
	public void sendUserList(Session session) {
		 Map<String, String> map = session.getPathParameters();
		Enumeration<String> sets=  webSocketMap.keys();
		while(sets.hasMoreElements()) {
			String userid= sets.nextElement();
			Enumeration<String> sett= webSocketMap.keys();
			while (sett.hasMoreElements()) {
				String string = (String) sett.nextElement();
				webSocketMap.get(userid).getAsyncRemote().sendText("list:"+string);
			}
		}
	}

	/**
	 * 連接配接關閉調用的方法
	 */
	@OnClose
	public void onClose(Session session) {
		 Map<String, String> map = session.getPathParameters();
		webSocketSet.remove(this); // 從set中删除
		webSocketMap.remove(map.get("userId"));
		subOnlineCount(); // 線上數減1
		System.out.println("有一連接配接關閉!目前線上人數為" + getOnlineCount());
		//告訴所有人我退出了
		Enumeration<String> sets=  webSocketMap.keys();
		while (sets.hasMoreElements()) {
			String str = (String) sets.nextElement();
			webSocketMap.get(str).getAsyncRemote().sendText("clist:"+map.get("userId"));
		}
	}

	/**
	 * 收到用戶端消息後調用的方法
	 *
	 * @param message
	 *            用戶端發送過來的消息
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		System.out.println("來自用戶端的消息:" + message);
		// 群發消息
//		for (WebSocketServer item : webSocketSet) {
//			try {
//				item.sendMessage(message);
//			} catch (IOException e) {
//				e.printStackTrace();
//			}
//		}
		//發給個人
		String[] msg= message.split("\\^");
		Map<String, String> map = session.getPathParameters();
		Session sessi=webSocketMap.get(msg[0]);
		if(sessi==null) {
			
			//接入電話中心
			session.getAsyncRemote().sendText("error:使用者已下線!");
		}else {
			sessi.getAsyncRemote().sendText(map.get("userId")+"^"+msg[1]);
		}
	}

	/**
	 * 發生錯誤時調用
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		System.out.println("發生錯誤");
		error.printStackTrace();
	}
	
	public void sendMessage(String message) throws IOException {
        this.session.getAsyncRemote().sendText(message);
    }
	/**
     * 群發自定義消息
     * */
    public static void sendInfo(String message) throws IOException {
        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                continue;
            }
        }
    }
    
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
    	WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
    	WebSocketServer.onlineCount--;
    }

}
           

3、建立一個html

<!DOCTYPE HTML>
<html>
<head>
<title>My WebSocket</title>
<style type="text/css">
.main{
	display:flex;
}
#windows{
	flex:0 0 auto;
}
.main > div{
	margin-left: 15px;
	flex:1;
}
.chat-bottom input{
	display: inline-block;
    padding: 5px 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    margin: 0 10px;
    width: 80%;
}
.chat-bottom button{
	padding: 5px 10px;
	border-radius: 4px;
	color:#fff;
	background-color: green;
	border:none;
}
.chat-main{
	overflow: auto;
	box-sizing:border-box;
	padding: 10px 15px;
	margin-bottom: 15px;
}
.chat-main .people-say{
	margin: 15px 0;
}
.other-say,.i-say{
	overflow: auto;
}
.other-say > div:not(.other-name){
	float:left;
	padding: 5px 10px;
	background: #ccc;
	border-radius: 4px;
	
}
.i-say > div{
	float: right;
	padding: 5px 10px;
	background: green;
	color:#fff;
	border-radius: 4px;
}
.other-name{
	width: 100%;
}
.msg-tip{
	position: absolute;
	top:50%;
	right:5px;
	transform:translateY(-50%);
    background: red;
    border-radius: 10px;
    height: 15px;
    line-height: 15px;
    color: #fff;
    padding: 1px 3px;
    font-size: 12px;
    min-width: 11px;
    text-align: center;
}
</style>
</head>

<body>
<div class="main">
	<div id="windows" style="width: 200px; height: 400px; border: solid 1px #FFCC00;">
		<div data='-1' id="title"
			style="width: 100%; height: 50px; background-color: #DDDDDD; text-align: center; line-height: 50px;">
		</div>
	</div>
	<div style="width: 300px;height: 400px;border: solid 1px #FFCC00; ">
		<div data='-1' id="titles"
			style="width: 100%; height: 50px; background-color: #DDDDDD; text-align: center; line-height: 50px;">
		</div>
		<input type="hidden" id="cuser"/>
		<div class="chat-main" style="height: 300px;width: 100%">
			
			
		</div>
		<div class="chat-bottom" style="height: 50px;width: 100%">
			<input id="msgtext" type="text" /><button οnclick="sendMsg()">發送</button>
		</div>
	</div>
</div>
</body>
<script type="text/javascript"
	src="/static/hui/lib/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
	var msgArr=[];
	var chatbox = $('.chat-main')
	//判斷是消息還是清單
	String.prototype.startWith = function(str) {
		var reg = new RegExp("^" + str);
		return reg.test(this);
	}
	var websocket = null;
	var timestamp = Date.parse(new Date());
	//判斷目前浏覽器是否支援WebSocket
	if ('WebSocket' in window) {
		websocket = new WebSocket("ws://10.130.87.227:8081/websocket/" + timestamp);
	} else {
		alert('Not support websocket');
	}
	//連接配接發生錯誤的回調方法
	websocket.onerror = function() {
		setMessageInnerHTML("error");
	};
	//連接配接成功建立的回調方法
	websocket.onopen = function(event) {
		$("#title").html("建立連結");
	}
	//接收到消息的回調方法
	websocket.onmessage = function(event) {
		//setMessageInnerHTML(event.data);
		if(event.data.startWith("list")){
			var uid=event.data.replace("list:","");
			userList(uid);
		}else if(event.data.startWith("clist")){
			var uid=event.data.replace("clist:","");
			cuserList(uid);
		}else if(event.data.startWith("error")){
			var error=event.data.replace("error:","");
			alert(error);
		}else {
			userMsg(event.data);
		}
		
	}
	//連接配接關閉的回調方法
	websocket.onclose = function() {
		setMessageInnerHTML("close");
	}
	//監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連接配接,防止連接配接還沒斷開就關閉視窗,server端會抛異常。
	window.onbeforeunload = function() {
		websocket.close();
	}
	//将消息顯示在網頁上
	function setMessageInnerHTML(innerHTML) {
		document.getElementById('message').innerHTML += innerHTML + '<br/>';
	}
	//關閉連接配接
	function closeWebSocket() {
		websocket.close();
	}
	//發送消息
	function sendMsg(){
		var message= $("#msgtext").val();
		if(message==""){
			return;
		}
		var cuser= $("#cuser").val();
		if(cuser==""){
			alert("請選擇會話人員!");
			return;
		}
		$(".chat-main").append(`<div class="i-say people-say">
			<div>`+message+`</div>
			</div>`);
		chatbox.scrollTop(chatbox[0].scrollHeight);
		websocket.send(cuser+"^"+message);
		$("#msgtext").val("");
	}
	//使用者替換
	function cuserList(uid){
		$.each($("#windows").children(),function(index,item){
			var d= $(item).attr("data");
			if(uid==d){
				//校驗是否在目前會話
				var cuser= $("#cuser").val();
				if(uid==cuser){
					$("#cuser").val("");
					$("#titles").html("目前使用者已下線。");
				}
				$(item).remove();
			}
		})
	}
	function userList(uid){
		if(timestamp==uid){
			return;
		}
		var b=false;
		$.each($("#windows").children(),function(index,item){
			var d= $(item).attr("data");
			if(uid==d){
				b=true;
			}
		})
		if(!b){
			$("#windows").append(`
					<div οnclick="msgWindow(this,`+uid+`)" data="`+uid+`" style="position:relative;width: 100%;height: 40px;border-bottom: solid 1px #DDDDDD;line-height: 40px; " > 
					`+uid+`
					</div>`);
		}
		
	}
	
	function msgWindow(obj,uid){
		var cu= $("#cuser").val();
		if(cu==uid){
			return;
		}
		$("#cuser").val(uid);
		$("#titles").html("您正在和"+uid+"聊天中!");
		$(".chat-main").html("");
		$.each(msgArr,function(index,item){
			if(item.key==uid){
				$.each(item.value,function(ins,it){
					$(".chat-main").append(`<div class="other-say people-say">
							<div class="other-name">`+uid+`</div>
							<div>`+it+`</div>
							</div>`);
							chatbox.scrollTop(chatbox[0].scrollHeight);
				})
				msgArr.splice(index);
			}
		});
		$(obj).children(".msg-tip").remove();
		
	}
	//消息處理
	function userMsg(msg){
		var msgs=msg.split("^");
		var cu= $("#cuser").val();
		if(cu==msgs[0]){
			$(".chat-main").append(`<div class="other-say people-say">
			<div class="other-name">`+cu+`</div>
			<div>`+msgs[1]+`</div>
			</div>`);
			chatbox.scrollTop(chatbox[0].scrollHeight);
		}else{
			var obj=[];
			$.each(msgArr,function(index,item){
				if(item.key==msgs[0]){
					obj=item.value;
					msgArr.splice(index);
					obj.push(msgs[1]);
					msgArr.push({key:msgs[0],value:obj});
				}
			});
			if(obj.length==0){
				//新增
				obj.push(msgs[1]);
				msgArr.push({key:msgs[0],value:obj});
			}
			//找到清單資料
			$.each($("#windows").children(),function(index,item){
			var d= $(item).attr("data");
			if(msgs[0]==d){
				$(item).append(`<span class="msg-tip">`+obj.length+`</span>`);
			}
		})
		}
	}
</script>
</html>
           

到此,這個聊天的就可以用了。大家試試吧

注意:在這個(接收資料的工具類)裡是無法進行其他spring 管理的類注入的,因為被@ServerEndpoint 修飾的類是不歸spring 管理的。如果要注入其他類可以使用一下辦法(加入紅色部分即可)

@ServerEndpoint(value = "/websocket/{userId}",configurator = SpringConfigurator.class)