花了将近一周的时间终于完成了利用WebSocket完成网页版聊天室这个小demo,期间还走过了一段“看似弯曲”的道路,可是我想其实也不算是弯路吧,由于你走过的路必将留下你的足迹。这个小demo看似简单,可是这一路走来本身也是花了很多心思才将其完成,今天就和你们一块儿分享一下。 刚刚接手这个任务时,我就想能不能使用Node.js来编写聊天室的服务器端,然后才发现这样作却存在“跨域问题”,由于你的前台是部署在Tomcat服务器上的,因此前台和后台的数据没法进行直接的交互,虽然能够间接的进行交互可是却不容易,在此不建议你们采用此种方法,可直接采用Java+html实现网页版聊天室。我将首先介绍客户端的构造然后介绍服务器端:
【1】 页面的编写(使用HTML编写)javascript
<body> <div class="container"> <center><h1>欢迎光临聊天室 </h1></center> <div id="message"></div> 昵称: <input id="username" type="text"/> 内容: <input id="text" type="text" style="width:300px"/> <button onclick="send()">发送</button> <button onclick="closeWebSocket()">退出聊天室</button> </div> </body>
说明:html
【2】页面的脚本编写java
<script type="text/javascript"> var websocket = null; //判断当前浏览器是否支持WebSocket if('WebSocket' in window){ websocket = new 地址格式是:主机名+项目名+客户端注明的名称 WebSocket("ws://localhost:8080/Chat_01/websocket"); } else{ alert('您的浏览器不支持 websocket!') } //链接发生错误的回调方法 websocket.onerror = function(){ setMessageInnerHTML("error"); }; //链接成功创建的回调方法 websocket.onopen = function(event){ alert("连接成功,欢迎加入聊天室!"); } //接收到消息的回调方法 websocket.onmessage = function(event){ setMessageInnerHTML(event.data); } //链接关闭的回调方法 websocket.onclose = function(){ var username=document.getElementById('username').value; setMessageInnerHTML(getNowFormatDate()+" "+username+" 退出了聊天室!"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket链接,防止链接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function(){ websocket.close(); } //将消息显示在网页上 function setMessageInnerHTML(innerHTML){ document.getElementById('message').innerHTML += innerHTML + ''; } //关闭链接 function closeWebSocket(){ websocket.close(); } //发送消息 function send(){ var username=document.getElementById('username').value; var message = document.getElementById('text').value; websocket.send(getNowFormatDate()+" "+username+"说: "+message+"<br/>"); //发送消息后,发送消息框自动清空 document.getElementById('text').value=""; } function getNowFormatDate() { var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位,1970-????) myDate.getMonth(); //获取当前月份(0-11,0表明1月) myDate.getDate(); //获取当前日(1-31) myDate.getDay(); //获取当前星期X(0-6,0表明星期天) myDate.getTime(); //获取当前时间(从1970.1.1开始的毫秒数) myDate.getHours(); //获取当前小时数(0-23) myDate.getMinutes(); //获取当前分钟数(0-59) myDate.getSeconds(); //获取当前秒数(0-59) myDate.getMilliseconds(); //获取当前毫秒数(0-999) myDate.toLocaleDateString(); //获取当前日期 var mytime=myDate.toLocaleTimeString(); //获取当前时间 return myDate.toLocaleString( ); //获取日期与时间 } </script>
说明:以上几个方法例如onclose,onmessage均是websocket自带的方法,你们只须要在websocket文档上查看各个函数是什么功能。web
import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; 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; //该注解用来指定一个URI,客户端能够经过这个URI来链接到WebSocket。相似Servlet的注解mapping。无需在web.xml中配置。 @ServerEndpoint("/websocket") public class MyWebSocket { // 静态变量,用来记录当前在线链接数。应该把它设计成线程安全的。 private static int onlineCount = 0; // concurrent包的线程安全Set,用来存放每一个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通讯的话,可使用Map来存放,其中Key能够为用户标识 private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>(); // 与某个客户端的链接会话,须要经过它来给客户端发送数据 private Session session; @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); // 加入set中 addOnlineCount(); // 在线数加1 System.out.println("有新链接加入!当前在线人数为" + getOnlineCount()); } /** * 链接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); // 从set中删除 subOnlineCount(); // 在线数减1 System.out.println("有一链接关闭!当前在线人数为" + getOnlineCount()); } @OnMessage public void onMessage(String message, Session session) { System.out.println("来自客户端的消息:" + message); // 群发消息 for (MyWebSocket item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); continue; } } } @OnError public void onError(Session session, Throwable error) { System.out.println("发生错误"); error.printStackTrace(); } public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); // this.session.getAsyncRemote().sendText(message); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { MyWebSocket.onlineCount++; } public static synchronized void subOnlineCount() { MyWebSocket.onlineCount--; } }
程序中我对重要的部门都标记了注释,相信你们只要稍微看过就能够看懂,在此我就不一一赘述了,你们若是在运行过程当中有问题的能够在文章下方进行评论,咱们能够一块儿讨论一下。最后我附上整个项目文件的位置以供小伙伴们下载运行。
百度网盘下载地址:连接:http://pan.baidu.com/s/1pLQbeDP 密码:t2vp 跨域
该连接可能已经失效,有须要的朋友能够发送邮件至280815640@qq.com。感谢您的关注。浏览器