Spring+WebSocket+SockJSリアルタイムチャットを実現


設計の初心はwebsocketを通じてホームページのリアルタイム通信チャットを実現することである.
エンジニアリング環境:tomcat 8+jdk 1.7+maven+eclipse
設計構想:クライアントがホームページにログインしてsocket接続を確立し、バックグラウンドにユーザー接続情報を記録し、標識を行う.ユーザがウェブページ側でチャットメッセージをバックグラウンドに送信すると、バックグラウンドは情報を受信した後、メッセージを受信者に送信し、バックエンドはメッセージを永続的に保存する.
簡単なコード実装demoは以下の通りです.
1、pom.xmlプライマリ構成
        
            javax.websocket
            javax.websocket-api
            1.0
            provided
        
        
            org.springframework
            spring-websocket
            ${spring.version}
        
        
            org.springframework
            spring-messaging
            ${spring.version}
        
        
            org.springframework
            spring-aop
            ${spring.version}
        
        
            org.apache.logging.log4j
            log4j-api
            ${log4j.version}
        
        
            org.apache.logging.log4j
            log4j-core
            ${log4j.version}
        


        
        
        
            org.springframework
            spring-aspects
            ${spring.version}
        

2、springコア構成情報
 
                
    
    
                
    
    

3、websocketサービス側実現
package com.milanosoft.RCS.web.webSocket.config;

import com.milanosoft.RCS.web.webSocket.hndler.SystemWebSocketHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import com.milanosoft.RCS.web.webSocket.interceptor.HandshakeInterceptor;
import org.springframework.context.annotation.Bean;

@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements
        WebSocketConfigurer {

    public WebSocketConfig() {
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(systemWebSocketHandler(), "/websck").addInterceptors(new HandshakeInterceptor());

        System.out.println("registed!");
        registry.addHandler(systemWebSocketHandler(), "/sockjs/websck").addInterceptors(new HandshakeInterceptor())
                .withSockJS();

    }

    @Bean
    public WebSocketHandler systemWebSocketHandler() {
        //return new InfoSocketEndPoint();
        return new SystemWebSocketHandler();
    }

}

4、websocket接続前後のイベントクラス
package com.milanosoft.RCS.web.webSocket.interceptor;

import java.util.Map;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;


@Component
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {

	@Override
	public boolean beforeHandshake(ServerHttpRequest request,
			ServerHttpResponse response, WebSocketHandler wsHandler,
			Map attributes) throws Exception {
		
		//  The extension [x-webkit-deflate-frame] is not supported  
		if(request.getHeaders().containsKey("Sec-WebSocket-Extensions")) {
			request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
        }
		
		System.out.println("Before Handshake");
		return super.beforeHandshake(request, response, wsHandler, attributes);
	}

	@Override
	public void afterHandshake(ServerHttpRequest request,
			ServerHttpResponse response, WebSocketHandler wsHandler,
			Exception ex) {
		System.out.println("After Handshake");
		super.afterHandshake(request, response, wsHandler, ex);
	}

}

//The extension[x-webkit-deflate-frame]is not supported問題if(request.getHeaders()を解決する.containsKey("Sec-WebSocket-Extensions")) {             request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");         }
このうち赤色のコードは次のエラーを解決するためで、ios携帯電話safariブラウザバージョンの問題による可能性があります.
org.springframework.web.socket.server.HandshakeFailureException: Uncaught failure for request http://localhost:8080/spring4/myHandler; nested exception is java.lang.IllegalArgumentException: The extension [x-webkit-deflate-frame] is not supported
5、websocketメッセージ処理クラス
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.milanosoft.RCS.web.webSocket.hndler;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

/**
 *
 * @author lzk
 */
@Component
public class SystemWebSocketHandler implements WebSocketHandler {

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("connect to the websocket success......");
        session.sendMessage(new TextMessage("Server:connected OK!"));
    }

    @Override
    public void handleMessage(WebSocketSession wss, WebSocketMessage> wsm) throws Exception {
        TextMessage returnMessage = new TextMessage(wsm.getPayload()
				+ " received at server");
        System.out.println(wss.getHandshakeHeaders().getFirst("Cookie"));
		wss.sendMessage(returnMessage);
    }

    @Override
    public void handleTransportError(WebSocketSession wss, Throwable thrwbl) throws Exception {
        if(wss.isOpen()){
            wss.close();
        }
       System.out.println("websocket connection closed......");
    }

    @Override
    public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception {
        System.out.println("websocket connection closed......");
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
    
}

6、クライアントページ WebSocket/SockJS Echo Sample (Adapted from Tomcat's echo sample) var ws = null; var url = null; var transports = []; function setConnected(connected) { document.getElementById('connect').disabled = connected; document.getElementById('disconnect').disabled = !connected; document.getElementById('echo').disabled = !connected; } function connect() { //alert(url); //console.log(url); if (!url) { alert('Select whether to use W3C WebSocket or SockJS'); return; } //ws = (url.indexOf('sockjs') != -1) ?new SockJS(url, undefined, {protocols_whitelist: transports}) : new WebSocket(url); if ('WebSocket' in window) { ws= new WebSocket("ws://192.168.1.104:8080/SpringWebSocketPush/websck"); console.log("ws://192.168.1.104:8080/SpringWebSocketPush/websck"); }else { ws = new SockJS("http://192.168.1.104:8080/SpringWebSocketPush/sockjs/websck"); console.log("http://192.168.1.104:8080/SpringWebSocketPush/sockjs/websck"); } //websocket = new SockJS("http://localhost:8080/SpringWebSocketPush/sockjs/websck"); ws.onopen = function () { alert('open'); setConnected(true); //log('Info: connection opened.'); }; ws.onmessage = function (event) { alert('Received:' + event.data); log('Received: ' + event.data); }; ws.onclose = function (event) { setConnected(false); log('Info: connection closed.'); log(event); }; } function disconnect() { if (ws != null) { ws.close(); ws = null; } setConnected(false); } function echo() { if (ws != null) { var message = document.getElementById('message').value; log('Sent: ' + message); ws.send(message); } else { alert('connection not established, please connect.'); } } function updateUrl(urlPath) { if (urlPath.indexOf('sockjs') != -1) { url = urlPath; document.getElementById('sockJsTransportSelect').style.visibility = 'visible'; } else { if (window.location.protocol == 'http:') { url = 'ws://' + window.location.host + urlPath; } else { url = 'wss://' + window.location.host + urlPath; } document.getElementById('sockJsTransportSelect').style.visibility = 'hidden'; } } function updateTransport(transport) { alert(transport); transports = (transport == 'all') ? [] : [transport]; } function log(message) { var console = document.getElementById('console'); var p = document.createElement('p'); p.style.wordWrap = 'break-word'; p.appendChild(document.createTextNode(message)); console.appendChild(p); while (console.childNodes.length > 25) { console.removeChild(console.firstChild); } console.scrollTop = console.scrollHeight; }


この例も他の人のコードに基づいていくつかの修正を行い、バグを修正しました.
完全なdemoの友達を要してここをダウンロードすることができます