jetty是一个轻量级的可嵌入的web服务器,他对websocket的支持也是非常好的,下面就介绍如何通过jetty服务器的websocket实现聊天室功能:
一、后台实现
后台使用的springMVC,具体的搭建可以看
http://dwj147258.iteye.com/blog/2328962,在这里web.xml文件中需要加入servlet
<servlet> <servlet-name>websocket</servlet-name> <servlet-class>main.java.test.websocket.WebSocketInitServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>websocket</servlet-name> <url-pattern>/websocket.ws</url-pattern> </servlet-mapping> <servlet>
来拦截来自前端的websocket请求,这里的servlet类WebSocketInitServlet代码实现如下,
package main.java.test.websocket; import javax.servlet.http.HttpServletRequest; import org.eclipse.jetty.websocket.WebSocketServlet; public class WebSocketInitServlet extends WebSocketServlet { private static final long serialVersionUID = -7302427588920888589L; /** * websocket建立连接 */ @Override public WebSocket doWebSocketConnect(HttpServletRequest request, String arg1) { return new WebSocket(); } }
覆盖了一个dowebsocketconnect方法,返回的webSocket对象则是具体的websocket业务处理了,代码实现如下
package main.java.test.websocket; import java.util.List; import net.sf.json.JSONObject; import org.eclipse.jetty.websocket.WebSocket.OnTextMessage; import com.sun.istack.internal.logging.Logger; public class WebSocket implements OnTextMessage { private static final Logger log = Logger.getLogger(WebSocket.class); /** * websocket连接 */ private Connection conn = null; private String key ; /** * websocket关闭事件触发 */ @Override public void onClose(int arg0, String arg1) { log.info("onClose begin. arg0:"+arg0+" arg1:"+arg1+" conn:"+conn); WebSocketManager.getInstance().removeWebSocket(key); log.info("onClose end. arg0:"+arg0+" arg1:"+arg1+" conn:"+conn); } /** * websocket连接建立触发 */ @Override public void onOpen(Connection conn) { // 如果客户端在这个MaxIdleTime中都没有活动,则它会自动结束 log.info("WebSocket onOpen. conn:"+conn.toString()+""+ conn.getMaxIdleTime()+" class:"+conn.getClass()); conn.setMaxIdleTime(Integer.MAX_VALUE); String toStr = conn.toString(); String name = toStr.substring(toStr.indexOf("(")+1, toStr.indexOf(")")); this.key = name ; this.conn = conn; WebSocketManager.getInstance().addWebSocket(this); System.out.println("服务端websocket连接建立"+conn.getProtocol()+" "+conn.toString()); } /** * websocket收到消息触发 */ @Override public void onMessage(String data) { /*log.info("onMessage. receive a Messag:" + data); JSONObject jsonObject = JSONObject.fromObject(data); System.out.println("name="+jsonObject.getString("name")+" age="+jsonObject.getString("age")); WebSocketMessage webSocketMessage = (WebSocketMessage)JSONObject.toBean(jsonObject, WebSocketMessage.class); OnMessageThread onMessageThread =new OnMessageThread(this,webSocketMessage); new Thread(onMessageThread).start(); String jsonMsg = JSONObject.fromObject(jsonObject).toString(); sendMessage(jsonMsg) ;*/ WebSocketManager.getInstance().sendAllMessage(data); } /** * websocket发送消息接口 * @param message */ public void sendMessage(String message){ try{ log.info("sendMessage. message:"+message); conn.sendMessage(message); }catch(Exception e){ log.warning("sendMessage error,close the conn and clear the resource. msg:"+e.getMessage(),e); closeConnection(); } } /** * 关闭连接 */ private void closeConnection(){ conn.close(); } public String getKey(){ return key ; } }
在这里,还需用到一个管理websocket的类,WebSocketManager,代码如下
package main.java.test.websocket; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; public class WebSocketManager { private ConcurrentHashMap<String , WebSocket> websockts = new ConcurrentHashMap<String , WebSocket>(); private static WebSocketManager instance ; public static WebSocketManager getInstance(){ if(instance == null ){ instance = new WebSocketManager(); } return instance ; } private WebSocketManager(){} public void addWebSocket(WebSocket ws){ websockts.put(ws.getKey(), ws); } public void removeWebSocket(String key ){ websockts.remove(key); } public void sendAllMessage(String message){ for(Entry<String, WebSocket> entry : websockts.entrySet()){ entry.getValue().sendMessage(message); } } }
到这里,来自前端的消息都会进入websocket的onmessage方法中,然后websocket会全部转发出去
二、前端实现
首先前端页面需要一个页面来显示接收的消息,并需要一个文本域来输入发送的消息,页面代码如下
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Home</title> <meta charset="utf-8"> <title>WebSocket简单实例</title> <style>body{text-align:center}</style> </head> <body> <textarea id="receive" cols="80" rows="20" readonly="true"></textarea><br> <textarea id="send" cols="80" rows="8"></textarea><br> <input style="height:36px;width:80px" type="button" id="loginng" value="发送" onclick="send()"><br> </body> <script type="text/javascript" src="/js/jquery.js"></script> <script type="text/javascript" src="/js/common.js"></script> <script type="text/javascript" src="/js/webchannel.js"></script> </html> 在这里,用到了webchannel.js,这个就是连接服务器websocket的js实现,如下,
var Webchannel = { wso: "", wsUrl: "ws://" + window.location.host + "/websocket.ws", busiTypes: {}, initWebsocket: function () { if ("WebSocket" in window) { wso = new WebSocket(Webchannel.wsUrl); } else if ("MozWebSocket" in window) { wso = new MozWebSocket(Webchannel.wsUrl); } else { console.log("The browser don't support the WebSocket"); } wso.onopen = function () { console.log("connect success"); }; wso.onclose = function () { try{ wso = new WebSocket(Webchannel.wsUrl); }catch(e){ console.log("disconnect error"+e); } console.log("disconnect success"); }; wso.onerror = function () { console.log("sorry,it get error"); }; wso.onmessage = function (receiveMsg) { var str = $("#receive").val(); var reMsg = receiveMsg.data.substring(1 ,receiveMsg.data.length-1); $("#receive").val(str+"\n"+reMsg); } }, sendMsg:function(data){ var jsonData= JSON.stringify(data); wso.send(jsonData); }, closeWebSocket: function () { if (1 == wso.readyState) { wso.close(); wso = ""; } }, regBusitype: function (busiType, backFunction) { Webchannel.busiTypes[busiType] = backFunction; } }; Webchannel.initWebsocket(); function send(){ var data = $("#send").val(); $("#send").val(""); Webchannel.sendMsg(data); }
在这个js中,打开页面就会进行一个websocket初始化,连接服务器,点击页面上的发送按钮就会调用js中的send方法,send方法获取页面中需要发送的内容,然后调用wensocket方法发送消息给服务器,
这样就实现了网页版的群聊功能