HTML5通讯协议——WebSocket

1.导入maven依赖

        <!-- websocket -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-messaging</artifactId>
           <version>${spring.version}</version>
        </dependency>

 

2.创建类 HandshakeInterceptor 继承 HttpSessionHandshakeInterceptor

public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
            ServerHttpResponse response, WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {

        /**
         * 在拦截器内强行修改websocket协议,将部分浏览器不支持的 x-webkit-deflate-frame 扩展修改成
         * permessage-deflate
         */
        if (request.getHeaders().containsKey("Sec-WebSocket-Extensions")) {
            request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
        }
        String jspCode = ((ServletServerHttpRequest) request).getServletRequest().getParameter("jspCode");
        if (jspCode != null) {
            attributes.put("jspCode", jspCode);
        } else {
            return false;
        }
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request,
            ServerHttpResponse response, WebSocketHandler wsHandler,
            Exception ex) {
        super.afterHandshake(request, response, wsHandler, ex);
    }
}

 

3.创建类 MyWebSocketConfig 继承 WebMvcConfigurerAdapter 并实现 WebSocketConfigurer

@Component
@EnableWebMvc
@EnableWebSocket
public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
    @Resource
    MyWebSocketHandler handler;
    
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // TODO Auto-generated method stub
        registry.addHandler(handler, "/websocket").addInterceptors(new HandshakeInterceptor());  
        registry.addHandler(handler, "/websocket/sockjs").addInterceptors(new HandshakeInterceptor()).withSockJS();
    }
}

 

4.创建类 MyWebSocketHandler 实现 WebSocketHandler

@Component
public class MyWebSocketHandler implements WebSocketHandler {

    public static final Map<String, WebSocketSession> userSocketSessionMap;

    static {
        userSocketSessionMap = new HashMap<String, WebSocketSession>();
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session)
            throws Exception {
        // TODO Auto-generated method stub
        String jspCode = session.getId() + "-" + (String) session.getHandshakeAttributes().get("jspCode");
        
        if (userSocketSessionMap.get(jspCode) == null) {
            System.out.println("添加会话:" + jspCode);
            userSocketSessionMap.put(jspCode, session);
        }
    }

    @Override
    public void handleMessage(WebSocketSession session,
            WebSocketMessage<?> message) throws Exception {
        // TODO Auto-generated method stub
        session.sendMessage(message);
    }

    @Override
    public void handleTransportError(WebSocketSession session,
            Throwable exception) throws Exception {
        // TODO Auto-generated method stub
        if (session.isOpen()) {
            session.close();
        }
        Iterator<Entry<String, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();
        // 移除Socket会话
        while (it.hasNext()) {
            Entry<String, WebSocketSession> entry = it.next();
            if (entry.getValue().getId().equals(session.getId())) {
                userSocketSessionMap.remove(entry.getKey());
                System.out.println("Socket会话已经移除:用户ID:" + entry.getKey());
                break;
            }
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session,
            CloseStatus closeStatus) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("Websocket:" + session.getId() + "已经关闭");
        Iterator<Entry<String, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();
        // 移除Socket会话
        while (it.hasNext()) {
            Entry<String, WebSocketSession> entry = it.next();
            if (entry.getValue().getId().equals(session.getId())) {
                userSocketSessionMap.remove(entry.getKey());
                System.out.println("Socket会话已经移除:用户ID:" + entry.getKey());
                break;
            }
        }
    }

    @Override
    public boolean supportsPartialMessages() {
        // TODO Auto-generated method stub
        return false;
    }
}

 

5.前段使用

<!-- websocket -->
<script type="text/javascript">
    $(function() {

        var jspCode = "${user.userId}";

        var websocket;
        if ('WebSocket' in window) {
            websocket = new WebSocket("ws://localhost:8080/ebcrawler/websocket?jspCode=" + jspCode);
        } else if ('MozWebSocket' in window) {
            websocket = new MozWebSocket("ws://localhost:8080/ebcrawler/websocket?jspCode=" + jspCode);
        } else {
            websocket = new SockJS("http://localhost:8080/ebcrawler/websocket/sockjs?jspCode=" + jspCode);
        }

        websocket.onopen = function(event) {
            $(".commonMsg").each(function() {
                $(this).html($(this).html() + "已连接<br/>")
            });
        };
        websocket.onmessage = function(event) {
            var data = event.data;
            var type = data.substring(0, data.indexOf("-"));
            var msg = data.substring(data.indexOf("-") + 1);
            if (type == "1") {
                $("#doneMsg").html($("#doneMsg").html() + msg + "<br/>");
            } else if (type == "2") {
                $("#doingMsg").html(msg + "<br/>");
            } else if (type == "3") {
                $("#errorMsg").html(msg + "<br/>" + $("#errorMsg").html());
            } else {

            }

        };
        websocket.onerror = function(event) {
            $(".commonMsg").each(function() {
                $(this).html($(this).html() + "websocket发生错误<br/>")
            });
        };
        websocket.onclose = function(event) {
            $(".commonMsg").each(function() {
                $(this).html($(this).html() + "已关闭<br/>")
            });
        };
    });
</script>

 

6.后端使用

        //websocket发给前端
        Iterator<Entry<String, WebSocketSession>> it = MyWebSocketHandler.userSocketSessionMap.entrySet().iterator();  
        // 发给同一userId的客户端  
        while (it.hasNext()) {  
  
            final Entry<String, WebSocketSession> entry = it.next();
            String keyUserId = entry.getKey().substring(entry.getKey().indexOf("-") + 1);
            WebSocketSession session = entry.getValue();
            if (session.isOpen() && keyUserId.equals(userId)) {  
                try {  
                    if (session.isOpen()) {  
                        synchronized(session) {
                            entry.getValue().sendMessage(new TextMessage(msg));  
                        }
                    }  
                } catch (IOException e) {  
                    e.printStackTrace();  
                } 
            }  
        }

  注意当多线程发送消息时,同一个WebSocketSession一次只能发送条消息,所以需要用synchronize将session锁住

posted @ 2018-02-23 16:43  晨M风  阅读(1466)  评论(0编辑  收藏  举报