https://github.com/TooTallNate/Java-WebSocket (websockect类库包)
http://blog.openlg.net/index.php/archives/129(实例篇)
http://my.oschina.net/yushulx/blog/298140 (使用Jetty搭建Java Websocket Server,实现图像传输)
http://linxh83.iteye.com/blog/1466017 ()
http://findhy.com/blog/2014/06/12/java-websocket/(Java-WebSocket)
(7.0.26支持websocket)
http://java-websocket.org/ (A barebones WebSocket client and server implementation written in 100% Java.)
WebSocket 规范的目标是在浏览器中实现和服务器端双向通信。双向通信可以拓展浏览器上的应用类型,例如实时的数据推送(股票行情)、游戏、聊天等.
目前在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。
目录结构:
1.WebSocket Server服务抽象类WSServer.java:
package com.hisense.romeo.websocket.server;/** * * WebSocket Server服务抽象类 * 自定义处理WebSocket客户端请求的服务: * 1.继承并实现此类抽象方法 * 2.修改配置文件/WEB-INF/conf/spring/applicationContext-websocket.xml,给wsServerDispatcher添加处理 * 例如:实现一个简单的聊天室,在配置文件中添加 * {@code * * } * 当客户端请求ws://127.0.0.1:8089/chat时,系统会自动将请求分派给com.hisense.romeo.websocket.server.dispatcher.ChatWSServer处理 * 3.如需发送消息可以直接调用wsServerDispatcher.sendMessage方法 * * * @see com.hisense.romeo.websocket.server.IWSServerDispatcher * * @author lirufei@lg mailto:lirufei0808@gmail.com * @version v0.0.1 */public abstract class WSServer implements IWSServer { /** * 当前调度WebSocket请求的服务,实现者可以用它进行向客户但发送消息 */ protected IWSServerDispatcher wsServerDispatcher; /** * 注册当前WebSocket服务调度员的方法 * * @param wsServerDispatcher */ public void registerWSServerDispatcher(IWSServerDispatcher wsServerDispatcher) { this.wsServerDispatcher = wsServerDispatcher; }}
2.WebSocket请求调度工作WSServerDispatcher.java:
package com.hisense.romeo.websocket.server;import java.net.InetSocketAddress;import java.net.UnknownHostException;import java.util.Collection;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;import org.apache.log4j.Level;import org.apache.log4j.Logger;import org.java_websocket.WebSocket;import org.java_websocket.WebSocketServer;import org.java_websocket.handshake.ClientHandshake;import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.InitializingBean;/** * * 实现WebSocket请求调度工作 * 根据客户端请求地址中的请求资源进行调度 * 例如:Address: ws://127.0.0.1:8089/chat * 程序会获取address中的chat进行分发请求。 * * @author lirufei@lg mailto:lirufei0808@gmail.com * @version * */public class WSServerDispatcher extends WebSocketServer implements IWSServerDispatcher, InitializingBean, DisposableBean{ /** * Log4j */ private Logger logger = Logger.getLogger(this.getClass()); private MapwsServers; private static int port = 8089; public WSServerDispatcher() throws UnknownHostException { this(new InetSocketAddress(port)); } public WSServerDispatcher(InetSocketAddress address){ super(address); logger.debug("default using port '" + address.getPort() + "' to startup the WebSocket Server." ); } /** * 建立新连接时自动调用此方法 * * @see org.java_websocket.WebSocketServer#onOpen(org.java_websocket.WebSocket, org.java_websocket.handshake.ClientHandshake) */ @Override public void onOpen(WebSocket ws, ClientHandshake clientHandData) { ws.setHandshakedata(clientHandData); logger.debug("new Client:\n " + ws.getRemoteSocketAddress() + "\n " + clientHandData.getResourceDescriptor()); } /** * 当接收到新消息时调用此方法 * * @see org.java_websocket.WebSocketServer#onMessage(org.java_websocket.WebSocket, java.lang.String) */ @Override public void onMessage(WebSocket ws, String message) { logger.debug("new Message:\n: " + ws.getRemoteSocketAddress() + ":\n " + message); String resource = getResourceDescriptor(ws); if(resource != null && resource.trim().length()!=0){ IWSServer listener = wsServers.get(resource); if(listener != null) listener.onMessage(ws, message); else logger.error("请求资源" + resource + "不存在!"); } else logger.error("请求资源不能为空!"); } /** * 连接关闭时自动调用此方法 * * @see org.java_websocket.WebSocketServer#onClose(org.java_websocket.WebSocket, int, java.lang.String, boolean) */ @Override public void onClose(WebSocket ws, int arg1, String arg2, boolean arg3) { logger.debug("client close:\n" + ws.getRemoteSocketAddress()); } /** * 当连接出现错误时自动调用此方法 * * @see org.java_websocket.WebSocketServer#onError(org.java_websocket.WebSocket, java.lang.Exception) */ @Override public void onError(WebSocket ws, Exception e) { logger.error("client error:\n" + ws.getRemoteSocketAddress() + "\n", e); } /** * 根据请求资源导航串获取所有的客户端 * * @param navigation * @return */ @Override public Set getClientByNavigation(String navigation){ if( navigation == null) return null; Set wss = new HashSet(); Set conections = this.connections(); for (WebSocket webSocket : conections) { String resource = this.getResourceDescriptor(webSocket); if(resource != null && resource.equals(navigation)) wss.add(webSocket); } return wss; } /** * 获取客户端数量 * @see com.hisense.romeo.websocket.server.IWSSendMessage#getClientCount(java.lang.String) */ @Override public int getClientCount(String name){ Set set = this.getClientByNavigation(name); if(set != null) return set.size(); return 0; } /** * 给${navigation}的所有客户段发送消息${message} * * @param message * @param navigation Not Null */ public void sendMessage(String message, String navigation){ this.sendMessage(this.getClientByNavigation(navigation), message); } /** * 发送消息给所有客户端 * * @param message */ public void sendMessageToAll(String message){ this.sendMessage(this.connections(), message); } /** * 发送消息给wss * * @param wss * @param message */ public void sendMessage(Set wss, String message){ if( wss != null) for (WebSocket webSocket : wss) { webSocket.send(message); } } /** * 当服务器退出时调用此方法 * * @see org.springframework.beans.factory.DisposableBean#destroy() */ @Override public void destroy() throws Exception { logger.info("Stop web socket server..."); super.stop(); if( wsServers != null && !wsServers.isEmpty()){ Set set = wsServers.keySet(); for (String key : set) { wsServers.get(key).destroy(); } } } /** * 当服务器启动时调用此方法 * * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override public void afterPropertiesSet() throws Exception { logger.info("**Startup web socket server,listening on port <" + port + ">.**"); if(wsServers == null ) wsServers = new HashMap (); try { WebSocket.DEBUG = Logger.getLogger("com.hisense.romeo.websocket.server").getLevel().toInt() == Level.DEBUG_INT; this.start(); logger.debug("**Initialization dispatchers.**"); Collection collection = wsServers.values(); for (IWSServer wsServerListener : collection) { wsServerListener.registerWSServerDispatcher(this); } logger.info("**WebSocket server has started.**"); } catch (Exception e) { e.printStackTrace(); } } /** * 获取客户端webSocket请求的资源 * * @param webSocket * @return */ private String getResourceDescriptor(WebSocket webSocket){ if(webSocket != null && webSocket.getHandshakedata() != null){ String resource = webSocket.getHandshakedata().getResourceDescriptor(); if(resource != null && resource.length() > 0) return resource.substring(1); else return resource; } else return null; } /** * 设置WebSocket服务的监听端口 * * @param port */ public void setPort(int port) { WSServerDispatcher.port = port; this.setAddress(new InetSocketAddress(port)); logger.debug("Update port to '" + port + "' ant startup the WebSocket Server." ); } public int getPort(){ return super.getPort(); } public Map getWsServers() { return wsServers; } public void setWsServers(Map wsServers) { this.wsServers = wsServers; } }
3.接口IWSServerDispatcher.java:
package com.hisense.romeo.websocket.server;import java.util.Set;import org.java_websocket.WebSocket;/**** getClientByNavigation(String navigation) 根据请求资源导航串获取所有的客户端* sendMessage(String message, String navigation) 给请求${navigation}的所有客户段发送消息${message}* sendMessage(Set* @author lirufei@lg mailto:lirufei0808@gmail.com* @version v0.0.1**/public interface IWSServerDispatcher extends IWSSendMessage{/*** 根据请求资源导航串获取所有的客户端** @param navigation* @return*/public Setwss, String message) 发送消息给${wss}* sendMessageToAll(String message) 发送消息给所有客户端* getClientByNavigation(String navigation);}
4.接口IWSServer.java:
package com.hisense.romeo.websocket.server;import org.java_websocket.WebSocket;/***** @author lirufei@lg mailto:lirufei0808@gmail.com* @version**/public interface IWSServer {/*** 注册当前WebSocket服务调度员的方法** @param wsServerDispatcher*/public void registerWSServerDispatcher(IWSServerDispatcher wsServerDispatcher);/*** 当接收到客户端消息时,会调用这个方法** @param ws 客户端信息* @param msg 接收到的消息*/public abstract void onMessage(WebSocket ws, String msg);/*** 销毁方法,当服务器停止时调用这个方法*/public abstract void destroy();}
5.接口IWSSendMessage.java:
package com.hisense.romeo.websocket.server;import java.util.Set;import org.java_websocket.WebSocket;/*** 定义使用WebSocket向客户端发送消息的方法** @author lirufei@lg mailto:lirufei0808@gmail.com* @version**/public interface IWSSendMessage {/*** 给请求${navigation}的所有客户段发送消息${message}** @param message 要发送的消息* @param navigation Not Null*/public void sendMessage(String message, String navigation);/*** 发送消息给wss
** @param wss* @param message*/public void sendMessage(Setwss, String message);/*** 发送消息给所有客户端** @param message*/public void sendMessageToAll(String message);/*** 根据名字查询客户端数量** @param name*/public int getClientCount(String name);}
6.消息值对象:MessageEntity.java
package com.hisense.romeo.websocket.common;import java.io.Serializable;/*** @author lirufei@lg mailto:lirufei0808@gmail.com* @version v0.0.1**/public class MessageEntity implements Serializable{/****/private static final long serialVersionUID = 1L;/*** 用户名*/private String user;/*** 密码*/private String pass;/*** 目标模块*/private String target;/*** 消息*/private String message;/*** 是否成功*/private boolean success = true;public String getUser() {return user;}public void setUser(String user) {this.user = user;}public String getPass() {return pass;}public void setPass(String pass) {this.pass = pass;}public String getTarget() {return target;}public void setTarget(String target) {this.target = target;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public boolean getSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;}}
7.业务值对象:RefreshVO.java
package com.hisense.romeo.websocket.common;/**** 值对象* 用于WebSocket推送数据变化的进行数据刷新的值对象** @author lirufei@lg mailto:lirufei0808@gmail.com* @version**/public class RefreshVO extends MessageEntity {/****/private static final long serialVersionUID = 1L;/*** 变化的表名称*/private String[] tables;public String[] getTables() {return tables;}public void setTables(String[] tables) {this.tables = tables;}}
8.用于聊天的服务端程序ChatWSServer.java
package com.hisense.romeo.websocket.server.dispatcher;import org.java_websocket.WebSocket;import com.hisense.romeo.websocket.server.WSServer;/*** 实现简单聊天室** @author lirufei@lg mailto:lirufei0808@gmail.com* @version**/public class ChatWSServer extends WSServer{/*** @see com.hisense.romeo.websocket.server.IWSServer#onMessage(org.java_websocket.WebSocket, java.lang.String)*/@Overridepublic void onMessage(WebSocket ws, String msg) {if(wsServerDispatcher != null )wsServerDispatcher.sendMessage(ws.getRemoteSocketAddress().getHostName() + "说:" + msg, "chat");}/*** @see com.hisense.romeo.websocket.server.IWSServer#destroy()*/@Overridepublic void destroy() {}}
9.用于发送和接收消息的客户端代码chat.js:
// Write your code in the same way as for native WebSocket:var hostname = location.hostname,ws = new WebSocket('ws://' + hostname + ':8089/chat'),msg = document.getElementById('msg'),text = document.getElementById('text'),btn = document.getElementById('button');setMsgValue = function(val){msg.value = msg.value + val;if(msg.scrollByLines)msg.scrollByLines(5);elsemsg.scrollTop = msg.value.length;};ws.onopen = function() {setMsgValue('open');};ws.onmessage = function(e) {setMsgValue('\n' + e.data);};ws.onclose = function() {setMsgValue('\n' + 'close');};btn.onclick = function(){ws.send(text.value);text.value='';};text.onkeyup = function(e){if(/(m|M)(s|S)(i|I)(e|E)/.test(navigator.userAgent))e = window.event;if(e.keyCode === 13){ws.send(text.value);text.value='';}}
源码下载: