HTML5 WebSocket+Tomcat实现真●Web版即时聊天室(单人

当前位置 : 首页 > 网页制作 > html5 > HTML5 WebSocket+Tomcat实现真●Web版即时聊天室(单人

HTML5 WebSocket+Tomcat实现真●Web版即时聊天室(单人

来源: 作者: 时间:2016-01-14 17:05
心累,下班回到宿舍,花了一个多小时的时间打开网页。。。真实醉了,对于干IT的人来说,没有网络或者网络卡到爆,真实比割了JJ还难受。首先是LZ的电脑被别人中了木马,是mysql的漏

心累,下班回到宿舍,花了一个多小时的时间打开网页。。。真实醉了,对于干IT的人来说,没有网络或者网络卡到爆,真实比割了JJ还难受。首先是LZ的电脑被别人中了木马,是mysql的,在图书馆连了公共WiFi之后,被别人利用mysql 的漏洞,就中奖了,结果就是电脑多出了一个名为piress的账户具体的原因看这,最简单的办法就是把密码设置的复杂一点,不要是'root'或者'123456'!然后重新装了个系统,宿舍十几个设备同时用一个wifi,网络的情况大家自己脑补!

以上是题外话,上次实现了单人聊天之后,今天把单人聊天(点对点)和多人聊天合并在一起,并优化了一番,用起来像是一个web聊天室,效果图如下

\

先进入login.jsp页面,填写你的昵称,登录进入chat.jsp页面,我打开了四个页面模拟四个用户,用户姓名放在session里,方便后台的操作,当然了根据系统需要你可以放用户ID

<%@ page language=java contentType=text/html; charset=UTF-8 pageEncoding=UTF-8%>

<script type=text/javascript src=js/jquery-1.7.2.min.js></script><% String name = request.getParameter(username); session.setAttribute(user, name); %> <script type=text/javascript> var self = <%=name%>; var ws = null; function startWebSocket() { if ('WebSocket' in window) ws = new WebSocket(ws://localhost:8080/WebSocketUser/websocket.do); else if ('MozWebSocket' in window) ws = new MozWebSocket(ws://localhost:8080/WebSocketUser/websocket.do); else alert(not support); ws.onmessage = function(evt){ var data = evt.data; var obj = eval ('(' + data + ')');//将字符串转换成JSON if(obj.type == 'message'){ setMessageInnerHTML(obj.data); }else if(obj.type == 'user'){ var userArry = obj.data.split(','); $(#userlist).empty(); $(#userlist).append(); $.each(userArry,function(n,value){ if(value != self && value != 'admin'){ $(#userlist).append(''); } }); } }; ws.onclose = function(evt) { $('#denglu').html(离线); }; ws.onopen = function(evt) { $('#denglu').html(在线); $('#userName').html(self); }; } function setMessageInnerHTML(innerHTML){ var temp = $('#message').html(); temp += innerHTML + '
'; $('#message').html(temp); } function sendMsg() { var fromName = self; var toName = $(#userlist).val(); //发给谁 var content = $(#writeMsg).val(); //发送内容 ws.send(fromName + , + toName + , + content); } </script>

WebIM

登录状态: 正在登录
昵称:

To: *请选择聊天对象
发送内容:
聊天框:
 

样式比较粗糙,没有在界面上花时间,和之前的点对点通信并没有多大的区别,主要就是onMessage那里,根据后台推送的消息,判断消息类型,如果为‘user’,意思是有新用户登录,这个时候要将select里的option更新,效果就是,当前有多少人在线,就有多少个用户选项,当然了不包括自己!如果类型为'message',就是普通的消息类型了。

后台的代码主要改动的是MyMessageInbound文件,代码如下

package socket;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.WsOutbound;

import util.MessageUtil;

public class MyMessageInbound extends MessageInbound {

	private String name;
	public MyMessageInbound() {
		super();
	}

	public MyMessageInbound(String name) {
		super();
		this.name = name;
	}

	@Override  
	protected void onBinaryMessage(ByteBuffer arg0) throws IOException {  

	}  

	@Override  
	protected void onTextMessage(CharBuffer msg) {

		
		HashMap messageMap = MessageUtil.getMessage(msg);    //处理消息类
		String fromName = messageMap.get(fromName);    //消息来自人 的userId
		String toName = messageMap.get(toName);       //消息发往人的 userId
		String mapContent = messageMap.get(content);
		
		if(all.equals(toName)){
			String msgContentString = fromName + 对所有人说:  + mapContent;   //构造发送的消息
			String content = MessageUtil.sendContent(MessageUtil.MESSAGE,msgContentString);
			broadcastAll(content);
		}else{
			try {
				singleChat(fromName,toName,mapContent);
			} catch (IOException e) {
				e.printStackTrace();
			}		
		}
	}  

	private void singleChat(String fromName, String toName, String mapContent) throws IOException {
		HashMap userMsgMap = InitServlet.getSocketList();
		MessageInbound messageInbound = userMsgMap.get(toName);    //在仓库中取出发往人的MessageInbound
		MessageInbound messageFromInbound = userMsgMap.get(fromName);
		if(messageInbound!=null && messageFromInbound!=null){     //如果发往人 存在进行操作
			WsOutbound outbound = messageInbound.getWsOutbound(); 
			WsOutbound outFromBound = messageFromInbound.getWsOutbound();
			
			String msgContentString = fromName + 对 + toName + 说:  + mapContent;   //构造发送的消息
			String contentTemp = MessageUtil.sendContent(MessageUtil.MESSAGE,msgContentString);
			
			outFromBound.writeTextMessage(CharBuffer.wrap(contentTemp.toCharArray()));
			outbound.writeTextMessage(CharBuffer.wrap(contentTemp.toCharArray()));  //
			
			outFromBound.flush();
			outbound.flush();
		}else{
			String content = MessageUtil.sendContent(MessageUtil.MESSAGE,客服不在线请留言...);
			broadcastAll(content);
		}
	}

	@Override  
	protected void onClose(int status) { 
		if(name!=null){
			InitServlet.getSocketList().remove(name);//删除客服ID与用户
			System.out.println(用户 + name + 退出);
		}
		String names = getNames();
		String content = MessageUtil.sendContent(MessageUtil.USER,names);
		broadcastAll(content);
		super.onClose(status);
	}  

	@Override
	protected void onOpen(WsOutbound outbound) { 
		super.onOpen(outbound);
		if(name!=null){
			InitServlet.getSocketList().put(name, this);//存放客服ID与用户
		}
		String names = getNames();
		String content = MessageUtil.sendContent(MessageUtil.USER,names);
		broadcastAll(content);
	}
	
	private String getNames() {
		Map exitUser = InitServlet.getSocketList();
		Iterator it=exitUser.keySet().iterator();
		String names = ;
		while(it.hasNext()){
			String key=it.next();
			names += key + ,;
		}
		String namesTemp = names.substring(0,names.length()-1);
		return namesTemp;
	}

	
	
	public static void broadcastAll(String message){
		Set> set = InitServlet.getSocketList().entrySet();
		WsOutbound outbound = null;
		for(Map.Entry messageInbound: set){
			try {
				outbound = messageInbound.getValue().getWsOutbound();
				outbound.writeTextMessage(CharBuffer.wrap(message));
				outbound.flush();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public int getReadTimeout() {
		return 0;
	}  


}

改动也比较大,主要在onOpen那里,用户成功登录,要添加map里,同时将用户的列表以消息的方式推送给前台,消息的类型为“user”,前台会自动将用户姓名更新到每个用户聊天页面的select里。

用户的成功登录之后会将姓名(id)和对应的MyMessageInbound对象存在map里,只要找对fromName和toName,就能完成(聊天)推送的功能。

对了,这里要注意CharBuffer.wrap(message)的用法作为一个缓冲信息的用法, 用一次就清空了!

这里使用的是不是基于注解的方式,好处也在上一个博客中指出,但是现在tomcat8是用注解的方式,我们的系统是在tomcat8下运行的额,所以,还要把tomcat8版的做出来,呵呵

代码已将上传了源码,其实我这些功能是按照交流群里一位网友用socket.io做出的一个系统里的功能,问他要资料和,人家很傲娇,什么都不给,于是我就自己做喽,还好,做出来了,效果和他一模一样!

做技术的就是要交流嘛,给点提示也是极好的!

好了,今天就到这!

 

 

Tag:
网友评论

<