HTML5和Tomcat7 WebSocketServlet easyui的聊天室简单实现
2013-12-26 11:25
876 查看
需要的jar包
commons-beanutils-1.7.0.jar
commons-collections-3.1.jar
commons-io-1.3.2.jar
commons-lang-2.3.jar
commons-logging-1.0.4.jar
commons-logging-api-1.1.jar
ezmorph-1.0.4.jar
jackson-core-asl-1.8.7.jar
jackson-mapper-asl-1.8.7.jar
json-lib-2.2.2-jdk15.jar
另外在eclipse中开发时需要将tomcat7引入进来(myeclipse中未成功)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202011/04/9b9adcb16faaeac94db91460dab321d7)
不多说了,看下代码
index.jsp
websocket.js
websocket.css
JsonUtil.java
MsgModel.java
WebSocketMessageInbound.java
WebSocketMessageInboundPool.java
WebSocketMessageServlet.java
commons-beanutils-1.7.0.jar
commons-collections-3.1.jar
commons-io-1.3.2.jar
commons-lang-2.3.jar
commons-logging-1.0.4.jar
commons-logging-api-1.1.jar
ezmorph-1.0.4.jar
jackson-core-asl-1.8.7.jar
jackson-mapper-asl-1.8.7.jar
json-lib-2.2.2-jdk15.jar
另外在eclipse中开发时需要将tomcat7引入进来(myeclipse中未成功)
不多说了,看下代码
index.jsp
<%@ page language="java" pageEncoding="UTF-8" import="com.ibcio.WebSocketMessageServlet"%> <% String path = request.getContextPath(); String WsBasePath = "ws://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; String user = request.getParameter("username"); if(user == null){ user = (String)session.getAttribute("user"); if(user == null){ //为用户生成昵称 user = "游客" + WebSocketMessageServlet.ONLINE_USER_COUNT; WebSocketMessageServlet.ONLINE_USER_COUNT ++; session.setAttribute("user", user); } }else{ session.setAttribute("user", user); } pageContext.setAttribute("user", user); %> <!DOCTYPE html > <html> <head> <title>WebSocket 聊天室</title> <!-- 引入CSS文件 --> <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath }/css/websocket.css" /> <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath }/easyui1.3.5/themes/default/easyui.css"/> <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath }/easyui1.3.5/themes/icon.css"/> <!-- 映入easyui的JS开发包,及自己实现的webscoket. --> <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.10.2.js"></script> <script type="text/javascript" src="${pageContext.request.contextPath }/easyui1.3.5/jquery.easyui.min.js"></script> <script type="text/javascript" src="${pageContext.request.contextPath }/js/websocket.js"></script> <script type="text/javascript"> var user = "${user}"; var wsPath = "<%=WsBasePath%>"+"message"; </script> </head> <body > <h1>WebSocket聊天室</h1> <p>通过HTML5标准提供的API与EasyUI富客户端框架相结合起来,实现聊天室,有以下特点:</p> <ul class="feature-list" style="padding-left: 10px;"> <li>实时获取数据,由服务器推送,实现即时通讯</li> <li>利用WebSocket完成数据通讯,区别于轮询,长连接等技术,节省服务器资源</li> <li>结合EasyUI进行页面展示</li> <li>用户上线下线通知</li> </ul> <div> <a id="btn" href="javascript:void(0)" class="easyui-linkbutton" onclick="$('#initWin').window('open')">打开聊天窗口</a> </div> <div id="initWin" class="easyui-window" data-options="collapsible:false,minimizable:false,maximizable:false,iconCls:'user-win'" > <div id="mainLayout" class="easyui-layout" style="width:642px;height:452px;"> <div data-options="region:'east',title:'在线用户',iconCls:'user-online'" style="width:150px;"> <!-- <div id="userOnlineTree" class="easyui-tree"></div> --> <div id="userOnlineTree" class="easyui-accordion" data-options="height:400" style="border: none;"></div> </div> <div id="mainLayoutCenter" data-options="region:'center',iconCls:'user-win'"> <div class="easyui-layout" style="width:491px;height:423px;"> <div data-options="region:'south'" style="height: 150px;border: none;border-top: 1px solid #95B8E7;"> <div class="easyui-layout" style="width:489px;height:148px;"> <div data-options="region:'south'" style="height: 30px;text-align: right;border: none;border-top: 1px solid #95B8E7;"> <a id="btnSend" href="javascript:void(0);" class="easyui-linkbutton" style="margin-top: 5px;">发送</a> </div> <div data-options="region:'center'" style="height:100px;overflow-x: hidden;border: none;"> <textarea style="width: 485px; height: 112px; resize: none;border: none;" id="textArea" onkeypress="keyPress(event);"></textarea> </div> </div> </div> <div id="messageShowCenter" data-options="region:'center'" style="overflow: auto;border: none;overflow-x: hidden;backgroundColor : '#fff'" > </div> </div> </div> </div> </div> </body> </html>
websocket.js
var websocket; //聊天窗口 var win; //聊天窗口标题 var title = '欢迎您: '; //输入框 var input; //在线用户 var onlineUser; $(function() { title += user; win = $("#initWin"); input = $("#textArea"); //在线用户 onlineUser = $("#userOnlineTree"); onlineUser.accordion({ animate:false }); //我的好友分组 onlineUser.accordion('add', { title: "我的好友", content: "<div id='onlineUserContent'></div>", }); // onlineUser.tree({ // onBeforeSelect:function(node){ // var select = onlineUser.tree("getSelected"); // if(select != null && select.id == node.id){ // //取消选中 // $("#"+node.domId).removeClass("tree-node-selected"); // //cancel this select action // return false; // } // } // }); initWebSocket(); //发送信息 $("#btnSend").click(function(e){ e.preventDefault(); send(); }); //消息展示 $("#messageShowCenter").append('<div class="l-im-message-warn">交谈中请勿轻信汇款、中奖信息、陌生电话。 请遵守相关法律法规。</div>'); }); //初始话WebSocket function initWebSocket() { if (window.WebSocket) { websocket = new WebSocket(encodeURI(wsPath)); websocket.onopen = function() { //连接成功 win.panel("setTitle",title + '(已连接)'); }; websocket.onerror = function() { //连接失败 win.panel("setTitle",title + '(连接发生错误)'); }; websocket.onclose = function() { //连接断开 win.panel("setTitle",title + '(已经断开连接)'); }; //消息接收 websocket.onmessage = function(message) { var message = JSON.parse(message.data); //接收用户发送的消息 if (message.type == 'message') { receive(message); } else if (message.type == 'get_online_user') { //获取在线用户列表 $.each(message.list,function(i){ var user = message.list[i]; var node = { data: [{ id: user, text: user, iconCls : 'user', leaf : true }] }; //onlineUser.tree('append',node); var context = '<div id="'+user+'" class="tree-node"><span class="tree-indent"></span><span class="user"></span><span class="tree-title" >'+user+'</span></div>'; $("#onlineUserContent").append(context); $("#"+user).mouseover(function(){ $(this).addClass("tree-node-hover"); }).mouseout(function(){ $(this).removeClass("tree-node-hover"); }).click(function(){ if($(this).hasClass("tree-node-selected")){ $("#userOnlineTree .tree-node-selected").removeClass("tree-node-selected"); }else{ $("#userOnlineTree .tree-node-selected").removeClass("tree-node-selected"); $(this).addClass("tree-node-selected"); } }); }); } else if (message.type == 'user_join') { //用户上线 var user = message.user; var node = { data: [{ id: user, text: user, iconCls : 'user', leaf : true }] }; //onlineUser.tree('append',node); var context = '<div id="'+user+'" class="tree-node"><span class="tree-indent"></span><span class="user"></span><span class="tree-title" >'+user+'</span></div>'; $("#onlineUserContent").append(context); $("#"+user).mouseover(function(){ $(this).addClass("tree-node-hover"); }).mouseout(function(){ $(this).removeClass("tree-node-hover"); }).click(function(){ if($(this).hasClass("tree-node-selected")){ $("#userOnlineTree .tree-node-selected").removeClass("tree-node-selected"); }else{ $("#userOnlineTree .tree-node-selected").removeClass("tree-node-selected"); $(this).addClass("tree-node-selected"); } }); } else if (message.type == 'user_leave') { //用户下线 var user = message.user; //var node = onlineUser.tree('find', user); //onlineUser.tree('remove',node.target); $("#"+user).remove(); } $("#userOnlineTree div span").removeClass("tree-file").removeClass("tree-icon"); }; } } //发送消息 function send() { var message = {}; var to = onlineUser.tree('getSelected'); if(null == to){ to = ""; }else{ to = to.id; } if (websocket != null) { if (input.val()) { $.extend(message, { from : user, to : to, content : input.val(), timestamp : new Date().getTime(), type : 'message' }); if(websocket.readyState == 1){ message = JSON.stringify(message); websocket.send(message); //message保存到本地 var key = user+"to"+to; if(localStorage.getItem(key)){ localStorage.setItem(key, localStorage.getItem(key)+"\n"+message); }else{ localStorage.setItem(key,message); } input.val(''); }else{ $.messager.alert('提示', '您已经掉线,无法发送消息!','warning'); } //output.receive(message); } } else { $.messager.alert('提示', '您已经掉线,无法发送消息!','warning'); } } //接受消息 function receive(message){ if(message.from == user){ message.source = 'self'; }else{ message.source = 'remote'; } message['timestamp'] = new Date(message['timestamp']).format("H:m:s"); var msg = '<div class="l-im-message">'+ '<div class="l-im-message-header l-im-message-header-'+message.source+'">'+message.from+' '+message.timestamp+'</div>'+ '<div class="l-im-message-body">'+message.content+'</div>'+ '</div>'; $("#messageShowCenter").append(msg); var msc = document.getElementById("messageShowCenter"); if (msc) { msc.scrollTop = msc.scrollHeight; } } //enter事件 function keyPress(e){ var keynum=""; if (window.event) // IE { keynum = e.keyCode; } else if (e.which) // Netscape/Firefox/Opera { keynum = e.which; } if (e.ctrlKey !== true && keynum == 13) { //only enter e.preventDefault(); e.stopPropagation(); send(); }else if(e.ctrlKey === true && (keynum == 13 || keynum == 10)){ //ctrl+enter input.val(input.val()+"\n"); } } // 时间格式化 Date.prototype.format = function(format) { var o = { "M+" : this.getMonth() + 1, //month "d+" : this.getDate(), //day "H+" : this.getHours(), //hour "m+" : this.getMinutes(), //minute "s+" : this.getSeconds(), //second "q+" : Math.floor((this.getMonth() + 3) / 3), //quarter "S" : this.getMilliseconds() //millisecond }; if (/(y+)/.test(format)) { format = format.replace(RegExp.$1, (this.getFullYear() + "") .substr(4 - RegExp.$1.length)); } for ( var k in o) { if (new RegExp("(" + k + ")").test(format)) { format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)); } } return format; };
websocket.css
@CHARSET "UTF-8"; .l-im-message-warn { font-family: "微软雅黑"; cursor: default; width: 100%; padding: 5px 0px 5px 25px; -webkit-user-select : none; background: url("../images/information.png") no-repeat 5; } .l-im-message { font-family: "微软雅黑"; cursor: default; width: 100%; } .l-im-message-over { background-color: rgba(233, 233, 233, 0.5); } .l-im-message-selected { background-color: rgba(250, 218, 90, 0.5); } .l-im-message-header { font-size: 12px; padding: 5px 0px 5px 10px; } .l-im-message-header-self { color: green; } .l-im-message-header-remote { color: blue; } .l-im-message-body { font-size: 12px; padding: 2px 0px 2px 20px; } .user-win { background-image: url( ../images/user_win.png ) !important; } .user-online { background-image: url( ../images/group.png ) !important; } .user { background-image: url( ../images/user.gif ); width:16px; height:16px; display:inline-block; }
JsonUtil.java
package com.ibcio; import java.io.IOException; import java.util.Map; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.ObjectMapper; /** * * @author Administrator * */ @SuppressWarnings({"unchecked","rawtypes"}) public class JsonUtil { private ObjectMapper mapper; private static JsonUtil jsonUtil; public static JsonUtil getInstance() { if (null == jsonUtil) { jsonUtil = new JsonUtil(); } return jsonUtil; } private JsonUtil() { this.mapper = new ObjectMapper(); } public ObjectMapper getMapper() { return mapper; } public static String pathValue(String jsonNode, String path) { String result = ""; ObjectMapper obm = JsonUtil.getInstance().getMapper(); JsonNode rootNode; try { rootNode = obm.readTree(jsonNode); result = rootNode.path(path).getValueAsText(); } catch (JsonProcessingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return result; } public static String pathValue(JsonNode jsonNode, String path) { String result = null; result = jsonNode.path(path).getValueAsText(); return result; } public static JsonNode readNode(String jsonNode) { ObjectMapper obm = JsonUtil.getInstance().getMapper(); JsonNode rootNode = null; try { rootNode = obm.readTree(jsonNode); } catch (JsonProcessingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return rootNode; } /** * json转map * @param jsonStr * @return */ public static Map readMap(String jsonStr) { ObjectMapper om = JsonUtil.getInstance().getMapper(); Map map = null; try { map = om.readValue(jsonStr, Map.class); } catch (Exception e) { e.printStackTrace(); } return map; } /** * json 转 Object * @param jsonStr * @param clazz * @return */ public static Object readObj(String jsonStr, Class clazz) { ObjectMapper om = JsonUtil.getInstance().getMapper(); try { return om.readValue(jsonStr, clazz); } catch (Exception e) { e.printStackTrace(); } return null; } /** * object转json * @param obj * @return */ public static String writeAsString(Object obj) { ObjectMapper obm = JsonUtil.getInstance().getMapper(); String reuslt = ""; try { reuslt = obm.writeValueAsString(obj); } catch (JsonProcessingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return reuslt; } public static String nodeText(JsonNode node, String nodeName) { String text = ""; if (node != null) { JsonNode tmp = node.path(nodeName); if (tmp != null) { text = tmp.getValueAsText(); } } if (text == null) { text = ""; } return text; } }
MsgModel.java
package com.ibcio; /** * 消息模型 * * @author Administrator * */ public class MsgModel { // msg private String from; private String to; private String content; private String timestamp; private String type; // user join leave private String user; private String list; public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getTimestamp() { return timestamp; } public void setTimestamp(String timestamp) { this.timestamp = timestamp; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getList() { return list; } public void setList(String list) { this.list = list; } }
WebSocketMessageInbound.java
package com.ibcio; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import net.sf.json.JSONObject; import org.apache.catalina.websocket.MessageInbound; import org.apache.catalina.websocket.WsOutbound; public class WebSocketMessageInbound extends MessageInbound { //当前连接的用户名称 private final String user; public WebSocketMessageInbound(String user) { this.user = user; } public String getUser() { return this.user; } //建立连接的触发的事件 @Override protected void onOpen(WsOutbound outbound) { // 触发连接事件,在连接池中添加连接 JSONObject result = new JSONObject(); result.element("type", "user_join"); result.element("user", this.user); //向所有在线用户推送当前用户上线的消息 WebSocketMessageInboundPool.sendMessage(result.toString()); result = new JSONObject(); result.element("type", "get_online_user"); result.element("list", WebSocketMessageInboundPool.getOnlineUser()); //向连接池添加当前的连接对象 WebSocketMessageInboundPool.addMessageInbound(this); //向当前连接发送当前在线用户的列表 WebSocketMessageInboundPool.sendMessageToUser(this.user, result.toString()); } @Override protected void onClose(int status) { // 触发关闭事件,在连接池中移除连接 WebSocketMessageInboundPool.removeMessageInbound(this); JSONObject result = new JSONObject(); result.element("type", "user_leave"); result.element("user", this.user); //向在线用户发送当前用户退出的消息 WebSocketMessageInboundPool.sendMessage(result.toString()); } @Override protected void onBinaryMessage(ByteBuffer message) throws IOException { throw new UnsupportedOperationException("Binary message not supported."); } //客户端发送消息到服务器时触发事件 @Override protected void onTextMessage(CharBuffer message) throws IOException { //向所有在线用户发送消息 WebSocketMessageInboundPool.sendMessage(message.toString()); } }
WebSocketMessageInboundPool.java
package com.ibcio; import java.io.IOException; import java.nio.CharBuffer; import java.util.HashMap; import java.util.Map; import java.util.Set; public class WebSocketMessageInboundPool { //保存连接的MAP容器 private static final Map<String,WebSocketMessageInbound > connections = new HashMap<String,WebSocketMessageInbound>(); //向连接池中添加连接 public static void addMessageInbound(WebSocketMessageInbound inbound){ //添加连接 System.out.println("user : " + inbound.getUser() + " join.."); connections.put(inbound.getUser(), inbound); } //取得connection public static Map<String,WebSocketMessageInbound > getOnlineMap(){ return connections; } //获取所有的在线用户 public static Set<String> getOnlineUser(){ return connections.keySet(); } public static void removeMessageInbound(WebSocketMessageInbound inbound){ //移除连接 System.out.println("user : " + inbound.getUser() + " exit.."); connections.remove(inbound.getUser()); } public static void sendMessageToUser(String user,String message){ try { //向特定的用户发送数据 System.out.println("send message to user : " + user + " ,message content : " + message); WebSocketMessageInbound inbound = connections.get(user); if(inbound != null){ inbound.getWsOutbound().writeTextMessage(CharBuffer.wrap(message)); } } catch (IOException e) { e.printStackTrace(); } } //向所有的用户发送消息 public static void sendMessage(String message){ try { MsgModel mm = null; try { mm = (MsgModel)JsonUtil.readObj(message, MsgModel.class); } catch (Exception e) { e.printStackTrace(); } if(null == mm || mm.getTo() == null || "".equals(mm.getTo())){ Set<String> keySet = connections.keySet(); for (String key : keySet) { WebSocketMessageInbound inbound = connections.get(key); if(inbound != null){ System.out.println("send message to user : " + key + " ,message content : " + message); inbound.getWsOutbound().writeTextMessage(CharBuffer.wrap(message)); } } }else{ WebSocketMessageInbound inbound = connections.get(mm.getFrom()); inbound.getWsOutbound().writeTextMessage(CharBuffer.wrap(message)); inbound = connections.get(mm.getTo()); inbound.getWsOutbound().writeTextMessage(CharBuffer.wrap(message)); } } catch (IOException e) { e.printStackTrace(); } } }
WebSocketMessageServlet.java
package com.ibcio; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.StreamInbound; @WebServlet(urlPatterns = { "/message"}) //如果要接收浏览器的ws://协议的请求就必须实现WebSocketServlet这个类 public class WebSocketMessageServlet extends org.apache.catalina.websocket.WebSocketServlet { private static final long serialVersionUID = 1L; public static int ONLINE_USER_COUNT = 1; public String getUser(HttpServletRequest request){ return (String) request.getSession().getAttribute("user"); } //跟平常Servlet不同的是,需要实现createWebSocketInbound,在这里初始化自定义的WebSocket连接对象 @Override protected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request) { return new WebSocketMessageInbound(this.getUser(request)); } }
相关文章推荐
- 基于HTML5和Tomcat WebSocketServlet的聊天室简单实现
- 基于HTML5和Tomcat WebSocketServlet的聊天室简单实现
- HTML5 WebSocket(Client) + JavaWeb(Server)实现简单的聊天室功能
- HTML5基于Tomcat 7.0实现WebSocket连接并实现简单的实时聊天
- HTML5 WebSocket(Client) + JavaWeb(Server) 实现简单的聊天室功能
- HTML5 WebSocket(Client) + JavaWeb(Server) 实现简单的聊天室功能
- HTML5基于Tomcat 7.0实现WebSocket连接并实现简单的实时聊天
- 用Websocket实现的最简单的聊天室功能
- java WebSocket实现简单的聊天室(包括群发和点对点聊天)
- “服务器推”之websocket实现之简单聊天室
- php+html5基于websocket实现聊天室的方法
- 【微信支付】分享一个失败的案例 跨域405(Method Not Allowed)问题 关于IM的一些思考与实践 基于WebSocketSharp 的IM 简单实现 【css3】旋转倒计时 【Html5】-- 塔台管制 H5情景意识 --飞机 谈谈转行
- html5 websocket 简单实现
- HTML5 WebSocket+Tomcat实现真●Web版即时聊天室(单人+多人)
- 基于html5websocket java实现简单通讯(虽然通了但是...你懂得)
- websocket实现简单的聊天室
- 基于html5 websocket API简单实现断点上传文件
- HTML5-WebSocket实现聊天室
- 使用Vert.x实现一个简单的websocket聊天室
- java+html5的websocket简单实现BS聊天DEMO实例