zoukankan      html  css  js  c++  java
  • java 实现websocket的两种方式

    简单说明

    1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket

    2.tomcat的方式需要tomcat 7.x,JEE7的支持。

    3.spring与websocket整合需要spring 4.x,并且使用了socketjs,对不支持websocket的浏览器可以模拟websocket使用


    方式一:tomcat

    使用这种方式无需别的任何配置,只需服务端一个处理类,


    服务器端代码

    [java]
    1. package com.Socket;  
    2.   
    3. import java.io.IOException;  
    4. import java.util.Map;  
    5. import java.util.concurrent.ConcurrentHashMap;  
    6. import javax.websocket.*;  
    7. import javax.websocket.server.PathParam;  
    8. import javax.websocket.server.ServerEndpoint;  
    9. import net.sf.json.JSONObject;  
    10.   
    11. @ServerEndpoint("/websocket/{username}")  
    12. public class WebSocket {  
    13.   
    14.     private static int onlineCount = 0;  
    15.     private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();  
    16.     private Session session;  
    17.     private String username;  
    18.       
    19.     @OnOpen  
    20.     public void onOpen(@PathParam("username") String username, Session session) throws IOException {  
    21.   
    22.         this.username = username;  
    23.         this.session = session;  
    24.           
    25.         addOnlineCount();  
    26.         clients.put(username, this);  
    27.         System.out.println("已连接");  
    28.     }  
    29.   
    30.     @OnClose  
    31.     public void onClose() throws IOException {  
    32.         clients.remove(username);  
    33.         subOnlineCount();  
    34.     }  
    35.   
    36.     @OnMessage  
    37.     public void onMessage(String message) throws IOException {  
    38.   
    39.         JSONObject jsonTo = JSONObject.fromObject(message);  
    40.           
    41.         if (!jsonTo.get("To").equals("All")){  
    42.             sendMessageTo("给一个人", jsonTo.get("To").toString());  
    43.         }else{  
    44.             sendMessageAll("给所有人");  
    45.         }  
    46.     }  
    47.   
    48.     @OnError  
    49.     public void onError(Session session, Throwable error) {  
    50.         error.printStackTrace();  
    51.     }  
    52.   
    53.     public void sendMessageTo(String message, String To) throws IOException {  
    54.         // session.getBasicRemote().sendText(message);  
    55.         //session.getAsyncRemote().sendText(message);  
    56.         for (WebSocket item : clients.values()) {  
    57.             if (item.username.equals(To) )  
    58.                 item.session.getAsyncRemote().sendText(message);  
    59.         }  
    60.     }  
    61.       
    62.     public void sendMessageAll(String message) throws IOException {  
    63.         for (WebSocket item : clients.values()) {  
    64.             item.session.getAsyncRemote().sendText(message);  
    65.         }  
    66.     }  
    67.       
    68.       
    69.   
    70.     public static synchronized int getOnlineCount() {  
    71.         return onlineCount;  
    72.     }  
    73.   
    74.     public static synchronized void addOnlineCount() {  
    75.         WebSocket.onlineCount++;  
    76.     }  
    77.   
    78.     public static synchronized void subOnlineCount() {  
    79.         WebSocket.onlineCount--;  
    80.     }  
    81.   
    82.     public static synchronized Map<String, WebSocket> getClients() {  
    83.         return clients;  
    84.     }  
    85. }  


    客户端js

    [javascript]
    1. var websocket = null;  
    2. var username = localStorage.getItem("name");  
    3.   
    4. //判断当前浏览器是否支持WebSocket  
    5. if ('WebSocket' in window) {  
    6.     websocket = new WebSocket("ws://" + document.location.host + "/WebChat/websocket/" + username + "/"+ _img);  
    7. else {  
    8.     alert('当前浏览器 Not support websocket')  
    9. }  
    10.   
    11. //连接发生错误的回调方法  
    12. websocket.onerror = function() {  
    13.     setMessageInnerHTML("WebSocket连接发生错误");  
    14. };  
    15.   
    16. //连接成功建立的回调方法  
    17. websocket.onopen = function() {  
    18.     setMessageInnerHTML("WebSocket连接成功");  
    19. }  
    20.   
    21. //接收到消息的回调方法  
    22. websocket.onmessage = function(event) {  
    23.     setMessageInnerHTML(event.data);  
    24. }  
    25.   
    26. //连接关闭的回调方法  
    27. websocket.onclose = function() {  
    28.     setMessageInnerHTML("WebSocket连接关闭");  
    29. }  
    30.   
    31. //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。  
    32. window.onbeforeunload = function() {  
    33.     closeWebSocket();  
    34. }  
    35.   
    36. //关闭WebSocket连接  
    37. function closeWebSocket() {  
    38.     websocket.close();  
    39. }  


    发送消息只需要使用websocket.send("发送消息"),就可以触发服务端的onMessage()方法,当连接时,触发服务器端onOpen()方法,此时也可以调用发送消息的方法去发送消息。关闭websocket时,触发服务器端onclose()方法,此时也可以发送消息,但是不能发送给自己,因为自己的已经关闭了连接,但是可以发送给其他人。


    方法二:spring整合

    此方式基于spring mvc框架,相关配置可以看我的相关博客文章


    WebSocketConfig.java

    这个类是配置类,所以需要在spring mvc配置文件中加入对这个类的扫描,第一个addHandler是对正常连接的配置,第二个是如果浏览器不支持websocket,使用socketjs模拟websocket的连接。

    [java]
    1. package com.websocket;  
    2.   
    3. import org.springframework.context.annotation.Bean;  
    4. import org.springframework.context.annotation.Configuration;  
    5. import org.springframework.web.socket.config.annotation.EnableWebSocket;  
    6. import org.springframework.web.socket.config.annotation.WebSocketConfigurer;  
    7. import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;  
    8. import org.springframework.web.socket.handler.TextWebSocketHandler;  
    9.   
    10. @Configuration  
    11. @EnableWebSocket  
    12. public class WebSocketConfig implements WebSocketConfigurer {  
    13.     @Override  
    14.     public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {  
    15.         registry.addHandler(chatMessageHandler(),"/webSocketServer").addInterceptors(new ChatHandshakeInterceptor());  
    16.         registry.addHandler(chatMessageHandler(), "/sockjs/webSocketServer").addInterceptors(new ChatHandshakeInterceptor()).withSockJS();  
    17.     }  
    18.    
    19.     @Bean  
    20.     public TextWebSocketHandler chatMessageHandler(){  
    21.         return new ChatMessageHandler();  
    22.     }  
    23.   
    24. }  



    ChatHandshakeInterceptor.java

    这个类的作用就是在连接成功前和成功后增加一些额外的功能,Constants.java类是一个工具类,两个常量。

    [java]
    1. package com.websocket;  
    2.   
    3. import java.util.Map;  
    4. import org.apache.shiro.SecurityUtils;  
    5. import org.springframework.http.server.ServerHttpRequest;  
    6. import org.springframework.http.server.ServerHttpResponse;  
    7. import org.springframework.web.socket.WebSocketHandler;  
    8. import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;  
    9.   
    10. public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {  
    11.   
    12.     @Override  
    13.     public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,  
    14.             Map<String, Object> attributes) throws Exception {  
    15.         System.out.println("Before Handshake");  
    16.         /* 
    17.          * if (request instanceof ServletServerHttpRequest) { 
    18.          * ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) 
    19.          * request; HttpSession session = 
    20.          * servletRequest.getServletRequest().getSession(false); if (session != 
    21.          * null) { //使用userName区分WebSocketHandler,以便定向发送消息 String userName = 
    22.          * (String) session.getAttribute(Constants.SESSION_USERNAME); if 
    23.          * (userName==null) { userName="default-system"; } 
    24.          * attributes.put(Constants.WEBSOCKET_USERNAME,userName); 
    25.          *  
    26.          * } } 
    27.          */  
    28.   
    29.         //使用userName区分WebSocketHandler,以便定向发送消息(使用shiro获取session,或是使用上面的方式)  
    30.         String userName = (String) SecurityUtils.getSubject().getSession().getAttribute(Constants.SESSION_USERNAME);  
    31.         if (userName == null) {  
    32.             userName = "default-system";  
    33.         }  
    34.         attributes.put(Constants.WEBSOCKET_USERNAME, userName);  
    35.   
    36.         return super.beforeHandshake(request, response, wsHandler, attributes);  
    37.     }  
    38.   
    39.     @Override  
    40.     public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,  
    41.             Exception ex) {  
    42.         System.out.println("After Handshake");  
    43.         super.afterHandshake(request, response, wsHandler, ex);  
    44.     }  
    45.   
    46. }  



    ChatMessageHandler.java

    这个类是对消息的一些处理,比如是发给一个人,还是发给所有人,并且前端连接时触发的一些动作

    [java]
    1. package com.websocket;  
    2.   
    3. import java.io.IOException;  
    4. import java.util.ArrayList;  
    5. import org.apache.log4j.Logger;  
    6. import org.springframework.web.socket.CloseStatus;  
    7. import org.springframework.web.socket.TextMessage;  
    8. import org.springframework.web.socket.WebSocketSession;  
    9. import org.springframework.web.socket.handler.TextWebSocketHandler;  
    10.   
    11. public class ChatMessageHandler extends TextWebSocketHandler {  
    12.   
    13.     private static final ArrayList<WebSocketSession> users;// 这个会出现性能问题,最好用Map来存储,key用userid  
    14.     private static Logger logger = Logger.getLogger(ChatMessageHandler.class);  
    15.   
    16.     static {  
    17.         users = new ArrayList<WebSocketSession>();  
    18.     }  
    19.   
    20.     /** 
    21.      * 连接成功时候,会触发UI上onopen方法 
    22.      */  
    23.     @Override  
    24.     public void afterConnectionEstablished(WebSocketSession session) throws Exception {  
    25.         System.out.println("connect to the websocket success......");  
    26.         users.add(session);  
    27.         // 这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户  
    28.         // TextMessage returnMessage = new TextMessage("你将收到的离线");  
    29.         // session.sendMessage(returnMessage);  
    30.     }  
    31.   
    32.     /** 
    33.      * 在UI在用js调用websocket.send()时候,会调用该方法 
    34.      */  
    35.     @Override  
    36.     protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {  
    37.         sendMessageToUsers(message);  
    38.         //super.handleTextMessage(session, message);  
    39.     }  
    40.   
    41.     /** 
    42.      * 给某个用户发送消息 
    43.      * 
    44.      * @param userName 
    45.      * @param message 
    46.      */  
    47.     public void sendMessageToUser(String userName, TextMessage message) {  
    48.         for (WebSocketSession user : users) {  
    49.             if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {  
    50.                 try {  
    51.                     if (user.isOpen()) {  
    52.                         user.sendMessage(message);  
    53.                     }  
    54.                 } catch (IOException e) {  
    55.                     e.printStackTrace();  
    56.                 }  
    57.                 break;  
    58.             }  
    59.         }  
    60.     }  
    61.   
    62.     /** 
    63.      * 给所有在线用户发送消息 
    64.      * 
    65.      * @param message 
    66.      */  
    67.     public void sendMessageToUsers(TextMessage message) {  
    68.         for (WebSocketSession user : users) {  
    69.             try {  
    70.                 if (user.isOpen()) {  
    71.                     user.sendMessage(message);  
    72.                 }  
    73.             } catch (IOException e) {  
    74.                 e.printStackTrace();  
    75.             }  
    76.         }  
    77.     }  
    78.   
    79.     @Override  
    80.     public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {  
    81.         if (session.isOpen()) {  
    82.             session.close();  
    83.         }  
    84.         logger.debug("websocket connection closed......");  
    85.         users.remove(session);  
    86.     }  
    87.   
    88.     @Override  
    89.     public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {  
    90.         logger.debug("websocket connection closed......");  
    91.         users.remove(session);  
    92.     }  
    93.   
    94.     @Override  
    95.     public boolean supportsPartialMessages() {  
    96.         return false;  
    97.     }  
    98.   
    99. }  



    spring-mvc.xml

    正常的配置文件,同时需要增加对WebSocketConfig.java类的扫描,并且增加

    [html]
    1. xmlns:websocket="http://www.springframework.org/schema/websocket"  
    2.               http://www.springframework.org/schema/websocket   
    3.               <target="_blank" href="http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd">http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd</a>  



    客户端

    [html]
    1. <script type="text/javascript"  
    2.         src="http://localhost:8080/Bank/js/sockjs-0.3.min.js"></script>  
    3.     <script>  
    4.         var websocket;  
    5.       
    6.         if ('WebSocket' in window) {  
    7.             websocket = new WebSocket("ws://" + document.location.host + "/Bank/webSocketServer");  
    8.         } else if ('MozWebSocket' in window) {  
    9.             websocket = new MozWebSocket("ws://" + document.location.host + "/Bank/webSocketServer");  
    10.         } else {  
    11.             websocket = new SockJS("http://" + document.location.host + "/Bank/sockjs/webSocketServer");  
    12.         }  
    13.       
    14.         websocket.onopen = function(evnt) {};  
    15.         websocket.onmessage = function(evnt) {  
    16.             $("#test").html("(<font color='red'>" + evnt.data + "</font>)")  
    17.         };  
    18.       
    19.         websocket.onerror = function(evnt) {};  
    20.         websocket.onclose = function(evnt) {}  
    21.       
    22.         $('#btn').on('click', function() {  
    23.             if (websocket.readyState == websocket.OPEN) {  
    24.                 var msg = $('#id').val();  
    25.                 //调用后台handleTextMessage方法  
    26.                 websocket.send(msg);  
    27.             } else {  
    28.                 alert("连接失败!");  
    29.             }  
    30.         });  
    31.     </script>  


    注意导入socketjs时要使用地址全称,并且连接使用的是http而不是websocket的ws

  • 相关阅读:
    20.GC日志详解及日志分析工具
    19.JVM调优工具锦囊
    两个页面的传参(转自博客园的春哥也编程)
    纯js实现背景图片切换
    关于引用类型用ref传参的问题
    C++ return
    C++内存管理
    Chrome插件开发一(配置文件)
    C++对象传递
    const 与 #define 的比较
  • 原文地址:https://www.cnblogs.com/interdrp/p/7903736.html
Copyright © 2011-2022 走看看