早先搞网页开发时,最常用的就是那个叫web.xml的玩意儿,它好比项目的开机设置,告诉服务器怎么启动,该装哪些servlet。那时咱还得运行个叫InitServlet的东东,给服务器上点油,加载一些配置,连通数据库这些事情都是它负责搞定。这种做法虽然历史悠久,但质量过硬,很多老项目至今仍有它的身影!
不过这招也有烦人的地方,就是得重启服务器才能生效,这个可对我们的编程生活造成困扰。另外,项目变得越复杂,Web.xml文件就越大,越难维护了。所以,现在好多新的项目都喜欢用注解代替那个旧的Web.xml方法!
public class InitServlet extends HttpServlet { private static final long serialVersionUID = -3163557381361759907L; private static HashMap socketList; public void init(ServletConfig config) throws ServletException { InitServlet.socketList = new HashMap(); super.init(config); System.out.println("初始化聊天容器"); } public static HashMap getSocketList() { return InitServlet.socketList; } }
WebSocket的基本概念
WebSocket这个词有些人听着可能比较新鲜,意思就是我可以在咱们的网上聊天,就用一个TCP连接就好,两边可以发信息也能收,不像传统HTTP那样,得重新连一次才能继续聊~
websocket socket.MyWebSocketServlet websocket *.do initServlet socket.InitServlet 1 index.jsp
WebSocket最赞的地方就在它实时传输信息。想想看,如果是用HTTP,我们的聊天系统就得不断重建连接,那得多慢呐!但换了WebSocket,服务器和客户端就能一路畅通无阻,随时随地发消息收消息,这用户感受岂不是立马飞起?
MyWebSocketServlet的实现
搞定WebSocket时,你可能会用到叫作”MyWebSocketServlet”的类,它就像个小王子,头脑聪明,能直接继承HttpServlet,处理那些源源不断的客户端请求。这个类里头还有个更厉害的角色,就是”MyMessageInbound”类,这位兄弟直接从MessageInbound那里继承下来,专门负责处理来自客户端的文本消息。
咱们在onTextMessage這個方法里头,可以對用户发过来的信息下手,我们可以把它们解析出来,封包到一起,最后把消息传递过去。这样子咱们就能轻松搞定聊天这个事儿了。不过要是想做出牛逼点的聊天系统,光这么干可不够,还要搞定好多别的事,比如说怎么管理用户,如何储存消息之类的。
public class MyWebSocketServlet extends WebSocketServlet { public String getUser(HttpServletRequest request){ String userName = (String) request.getSession().getAttribute("user"); if(userName==null){ return null; } return userName; } protected StreamInbound createWebSocketInbound(String arg0, HttpServletRequest request) { System.out.println("用户" + request.getSession().getAttribute("user") + "登录"); return new MyMessageInbound(this.getUser(request)); } }
前台与后台的交互
WebSocket里头,前后台交流可不能少。前台是用JavaScript搞起来的,靠着WebSocket对象来发信息收信息。后台嘛就得用Java搭个平台,用上MyWebSocketServlet和MyMessageInbound就能搞定前台给过来的消息了。
咱们在前台得按规矩发信息!比如说,咱用个JSON格式,写明啥消息,说啥话。后台接到信儿后,就能看是啥种类,然后去处理咯。这样一来,前台和后台就能好好交流。
package socket; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.HashMap; 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) throws IOException { //用户所发消息处理后的map HashMap messageMap = MessageUtil.getMessage(msg); //处理消息类 //上线用户集合类map HashMap userMsgMap = InitServlet.getSocketList(); String fromName = messageMap.get("fromName"); //消息来自人 的userId String toName = messageMap.get("toName"); //消息发往人的 userId //获取该用户 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 content = messageMap.get("content"); //获取消息内容 String msgContentString = fromName + "说: " + content; //构造发送的消息 //发出去内容 CharBuffer toMsg = CharBuffer.wrap(msgContentString.toCharArray()); CharBuffer fromMsg = CharBuffer.wrap(msgContentString.toCharArray()); outFromBound.writeTextMessage(fromMsg); outbound.writeTextMessage(toMsg); // outFromBound.flush(); outbound.flush(); } } @Override protected void onClose(int status) { InitServlet.getSocketList().remove(this); super.onClose(status); } @Override protected void onOpen(WsOutbound outbound) { super.onOpen(outbound); //登录的用户注册进去 if(name!=null){ InitServlet.getSocketList().put(name, this);//存放客服ID与用户 } } @Override public int getReadTimeout() { return 0; } }
A.jsp页面与B.jsp页面的实现
聊吧功能咋做?就得用上咱俩,A页面还有那个B页面。这俩页面都能发消息也能接,就能实现一对一的私聊了!
你看,在A.jsp页面里,咱们能用JavaScript玩转WebSocket,连接服务器,发传讯息之类的都行。而到了B.jsp页面,用的还是这套本领,这不,两个页面能互相发聊天信息!
聊天系统的扩展
package util; import java.nio.CharBuffer; import java.util.HashMap; public class MessageUtil { public static HashMap getMessage(CharBuffer msg) { HashMap map = new HashMap(); String msgString = msg.toString(); String m[] = msgString.split(","); map.put("fromName", m[0]); map.put("toName", m[1]); map.put("content", m[2]); return map; } }
搞定个大型聊天系统可没那么简单,比如说网上那种聊天平台啥的,我们得做好一大堆工作!首先就是要搞好用户管理,还要有个装消息的地方,另外不能少了聊天室这个重要部分哇。
关于用户管理,就是把大家的个人资料比如用户名啊、密码啦、头像啥之类的东西存在数据库里头;说到底就是帮你存和找那些消息的人是谁,什么时候发的消息,都在这里搞定。再说到那个聊天室功能,通过WebSocket就可以让大家随时随地跟别人聊嗨皮!
WebSocket与二进制传输
在WebSocket上,我们能用二进制传输方式传送并接收数据,比如能把ArrayBuffer当作载体传输二进制内容,GetBlob来获取它们。
Index 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) { //alert(evt.data); console.log(evt); // $("#xiaoxi").val(evt.data); setMessageInnerHTML(evt.data); }; function setMessageInnerHTML(innerHTML){ document.getElementById('message').innerHTML += innerHTML + '
'; } ws.onclose = function(evt) { //alert("close"); document.getElementById('denglu').innerHTML="离线"; }; ws.onopen = function(evt) { //alert("open"); document.getElementById('denglu').innerHTML="在线"; document.getElementById('userName').innerHTML='小化'; }; } function sendMsg() { var fromName = "小化"; var toName = document.getElementById('name').value; //发给谁 var content = document.getElementById('writeMsg').value; //发送内容 ws.send(fromName+","+toName+","+content);//注意格式 }聊天功能实现
登录状态: 正在登录
登录人:
发送给谁:
发送内容:
聊天框:
虽然WebSocket能传二进制,但实际上咱日常开发中基本不用这功能。为啥?虽说是可以快那么点,可是编程的难度也上去了不少。所以大部分时候,咱们还是选文本传输,方便省事。
JavaScript与二进制传输
在JavaScript里,咱们可用FileReader把那些binarydata读出来。其实,JavaScript自己不支援bin格式的传输,但FileReader这个玩意儿就帮咱解决了这个问题,终于得以手拿着binarydata进行操作!
其实,咱们平时很少用FileReader这个东西。毕竟,二进制文件处理起来太麻烦了,还经常搞错。所以,大部分时候,咱们都是用纯文字数据来交流跟操作。
评论0