HTML5 WebSocket+Tomcat实现真●Web版即时聊天室(单人+多人)
心累,下班回到宿舍,花了一个多小时的时间打开网页。。。真实醉了,对于干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(
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做出的一个系统里的功能,问他要资料和源码,人家很傲娇,什么都不给,于是我就自己做喽,还好,做出来了,效果和他一模一样!
做技术的就是要交流嘛,给点提示也是极好的!
好了,就到这了!