java 实现websocket的两种方式实例详解
一、介绍
1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket
2.tomcat的方式需要tomcat7.x,JEE7的支持。
3.spring与websocket整合需要spring4.x,并且使用了socketjs,对不支持websocket的浏览器可以模拟websocket使用
二、方式一:tomcat
使用这种方式无需别的任何配置,只需服务端一个处理类,
服务器端代码
packagecom.Socket; importjava.io.IOException; importjava.util.Map; importjava.util.concurrent.ConcurrentHashMap; importjavax.websocket.*; importjavax.websocket.server.PathParam; importjavax.websocket.server.ServerEndpoint; importnet.sf.json.JSONObject; @ServerEndpoint("/websocket/{username}") publicclassWebSocket{ privatestaticintonlineCount=0; privatestaticMapclients=newConcurrentHashMap (); privateSessionsession; privateStringusername; @OnOpen publicvoidonOpen(@PathParam("username")Stringusername,Sessionsession)throwsIOException{ this.username=username; this.session=session; addOnlineCount(); clients.put(username,this); System.out.println("已连接"); } @OnClose publicvoidonClose()throwsIOException{ clients.remove(username); subOnlineCount(); } @OnMessage publicvoidonMessage(Stringmessage)throwsIOException{ JSONObjectjsonTo=JSONObject.fromObject(message); if(!jsonTo.get("To").equals("All")){ sendMessageTo("给一个人",jsonTo.get("To").toString()); }else{ sendMessageAll("给所有人"); } } @OnError publicvoidonError(Sessionsession,Throwableerror){ error.printStackTrace(); } publicvoidsendMessageTo(Stringmessage,StringTo)throwsIOException{ //session.getBasicRemote().sendText(message); //session.getAsyncRemote().sendText(message); for(WebSocketitem:clients.values()){ if(item.username.equals(To)) item.session.getAsyncRemote().sendText(message); } } publicvoidsendMessageAll(Stringmessage)throwsIOException{ for(WebSocketitem:clients.values()){ item.session.getAsyncRemote().sendText(message); } } publicstaticsynchronizedintgetOnlineCount(){ returnonlineCount; } publicstaticsynchronizedvoidaddOnlineCount(){ WebSocket.onlineCount++; } publicstaticsynchronizedvoidsubOnlineCount(){ WebSocket.onlineCount--; } publicstaticsynchronizedMap getClients(){ returnclients; } }
客户端js
varwebsocket=null; varusername=localStorage.getItem("name"); //判断当前浏览器是否支持WebSocket if('WebSocket'inwindow){ websocket=newWebSocket("ws://"+document.location.host+"/WebChat/websocket/"+username+"/"+_img); }else{ alert('当前浏览器Notsupportwebsocket') } //连接发生错误的回调方法 websocket.onerror=function(){ setMessageInnerHTML("WebSocket连接发生错误"); }; //连接成功建立的回调方法 websocket.onopen=function(){ setMessageInnerHTML("WebSocket连接成功"); } //接收到消息的回调方法 websocket.onmessage=function(event){ setMessageInnerHTML(event.data); } //连接关闭的回调方法 websocket.onclose=function(){ setMessageInnerHTML("WebSocket连接关闭"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload=function(){ closeWebSocket(); } //关闭WebSocket连接 functioncloseWebSocket(){ websocket.close(); }
发送消息只需要使用websocket.send(“发送消息”),就可以触发服务端的onMessage()方法,当连接时,触发服务器端onOpen()方法,此时也可以调用发送消息的方法去发送消息。关闭websocket时,触发服务器端onclose()方法,此时也可以发送消息,但是不能发送给自己,因为自己的已经关闭了连接,但是可以发送给其他人。
三、方法二:spring整合
WebSocketConfig.java
这个类是配置类,所以需要在springmvc配置文件中加入对这个类的扫描,第一个addHandler是对正常连接的配置,第二个是如果浏览器不支持websocket,使用socketjs模拟websocket的连接。
packagecom.websocket; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.web.socket.config.annotation.EnableWebSocket; importorg.springframework.web.socket.config.annotation.WebSocketConfigurer; importorg.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; importorg.springframework.web.socket.handler.TextWebSocketHandler; @Configuration @EnableWebSocket publicclassWebSocketConfigimplementsWebSocketConfigurer{ @Override publicvoidregisterWebSocketHandlers(WebSocketHandlerRegistryregistry){ registry.addHandler(chatMessageHandler(),"/webSocketServer").addInterceptors(newChatHandshakeInterceptor()); registry.addHandler(chatMessageHandler(),"/sockjs/webSocketServer").addInterceptors(newChatHandshakeInterceptor()).withSockJS(); } @Bean publicTextWebSocketHandlerchatMessageHandler(){ returnnewChatMessageHandler(); } }
ChatHandshakeInterceptor.java
这个类的作用就是在连接成功前和成功后增加一些额外的功能,Constants.java类是一个工具类,两个常量。
packagecom.websocket; importjava.util.Map; importorg.apache.shiro.SecurityUtils; importorg.springframework.http.server.ServerHttpRequest; importorg.springframework.http.server.ServerHttpResponse; importorg.springframework.web.socket.WebSocketHandler; importorg.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; publicclassChatHandshakeInterceptorextendsHttpSessionHandshakeInterceptor{ @Override publicbooleanbeforeHandshake(ServerHttpRequestrequest,ServerHttpResponseresponse,WebSocketHandlerwsHandler, Mapattributes)throwsException{ System.out.println("BeforeHandshake"); /* *if(requestinstanceofServletServerHttpRequest){ *ServletServerHttpRequestservletRequest=(ServletServerHttpRequest) *request;HttpSessionsession= *servletRequest.getServletRequest().getSession(false);if(session!= *null){//使用userName区分WebSocketHandler,以便定向发送消息StringuserName= *(String)session.getAttribute(Constants.SESSION_USERNAME);if *(userName==null){userName="default-system";} *attributes.put(Constants.WEBSOCKET_USERNAME,userName); * *}} */ //使用userName区分WebSocketHandler,以便定向发送消息(使用shiro获取session,或是使用上面的方式) StringuserName=(String)SecurityUtils.getSubject().getSession().getAttribute(Constants.SESSION_USERNAME); if(userName==null){ userName="default-system"; } attributes.put(Constants.WEBSOCKET_USERNAME,userName); returnsuper.beforeHandshake(request,response,wsHandler,attributes); } @Override publicvoidafterHandshake(ServerHttpRequestrequest,ServerHttpResponseresponse,WebSocketHandlerwsHandler, Exceptionex){ System.out.println("AfterHandshake"); super.afterHandshake(request,response,wsHandler,ex); } }
ChatMessageHandler.java
这个类是对消息的一些处理,比如是发给一个人,还是发给所有人,并且前端连接时触发的一些动作
packagecom.websocket; importjava.io.IOException; importjava.util.ArrayList; importorg.apache.log4j.Logger; importorg.springframework.web.socket.CloseStatus; importorg.springframework.web.socket.TextMessage; importorg.springframework.web.socket.WebSocketSession; importorg.springframework.web.socket.handler.TextWebSocketHandler; publicclassChatMessageHandlerextendsTextWebSocketHandler{ privatestaticfinalArrayListusers;//这个会出现性能问题,最好用Map来存储,key用userid privatestaticLoggerlogger=Logger.getLogger(ChatMessageHandler.class); static{ users=newArrayList (); } /** *连接成功时候,会触发UI上onopen方法 */ @Override publicvoidafterConnectionEstablished(WebSocketSessionsession)throwsException{ System.out.println("connecttothewebsocketsuccess......"); users.add(session); //这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户 //TextMessagereturnMessage=newTextMessage("你将收到的离线"); //session.sendMessage(returnMessage); } /** *在UI在用js调用websocket.send()时候,会调用该方法 */ @Override protectedvoidhandleTextMessage(WebSocketSessionsession,TextMessagemessage)throwsException{ sendMessageToUsers(message); //super.handleTextMessage(session,message); } /** *给某个用户发送消息 * *@paramuserName *@parammessage */ publicvoidsendMessageToUser(StringuserName,TextMessagemessage){ for(WebSocketSessionuser:users){ if(user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)){ try{ if(user.isOpen()){ user.sendMessage(message); } }catch(IOExceptione){ e.printStackTrace(); } break; } } } /** *给所有在线用户发送消息 * *@parammessage */ publicvoidsendMessageToUsers(TextMessagemessage){ for(WebSocketSessionuser:users){ try{ if(user.isOpen()){ user.sendMessage(message); } }catch(IOExceptione){ e.printStackTrace(); } } } @Override publicvoidhandleTransportError(WebSocketSessionsession,Throwableexception)throwsException{ if(session.isOpen()){ session.close(); } logger.debug("websocketconnectionclosed......"); users.remove(session); } @Override publicvoidafterConnectionClosed(WebSocketSessionsession,CloseStatuscloseStatus)throwsException{ logger.debug("websocketconnectionclosed......"); users.remove(session); } @Override publicbooleansupportsPartialMessages(){ returnfalse; } }
spring-mvc.xml
正常的配置文件,同时需要增加对WebSocketConfig.java类的扫描,并且增加
xmlns:websocket="http://www.springframework.org/schema/websocket" http://www.springframework.org/schema/websockethttp://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd
客户端
注意导入socketjs时要使用地址全称,并且连接使用的是http而不是websocket的ws
总结
以上所述是小编给大家介绍的java实现websocket的两种方式实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!