SSM+websocket+二進制數據傳輸+sharedWorker

注意事項:
1.如果出現握手失敗,檢查路徑之外還可以去查看攔截器是否做了什麼處理

WebSocket和sharedWork簡介

WebSocket是持久化連接,用於解決瀏覽器與後臺服務器雙向通訊的問題
sharedWorker共享工作線程允許多個頁面共享使用,每個頁面都是鏈接到該共享工作線程的某個端口號上。頁面通過該端口與共享工作線程進行通信

配置所需jar包

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

這裏所用的版本最好和項目中所用到的spring其他內容統一,避免出現版本不兼容問題。
對版本的要求是:spring版本爲 4.0 版本及以上, Tomcat 7.047 以上版本。

websocket入口

/**
 * Component註解告訴SpringMVC該類是一個SpringIOC容器下管理的類
 * 其實@Controller, @Service, @Repository是@Component的細化
 * @Configuration註解該類,等價於XML中配置beans標籤
 */
@Configuration
@EnableWebSocket
public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        //一般瀏覽器都會支持
        registry.addHandler(WebSocketPushHandler(),"/webSocketServer").addInterceptors(new MyHandShakeInterceptor());
        //低版本瀏覽器使用此路徑,等下頁面上會講到
        registry.addHandler(WebSocketPushHandler(), "/sockjs/webSocketServer").addInterceptors(new MyHandShakeInterceptor())
                .withSockJS();
    }
    @Bean
    public WebSocketHandler WebSocketPushHandler(){
        return new MyWebSocketHander();
    }
}
  • 實現WebSocketConfigurer接口,重寫registerWebSocketHandlers方法,這是一個核心實現方法,配置websocket入口,允許訪問的域、註冊Handler、SockJs支持和攔截器。

  • registry.addHandler註冊和路由的功能,當客戶端發起websocket連接,把/path交給對應的handler處理, 而不實現具體的業務邏輯,可以理解爲收集和任務分發中心。

  • setAllowedOrigins(String[] domains),允許指定的域名或IP(含端口號)建立長連接,如果只允許自家域名訪問,這裏輕鬆設置。 如果不限時使用”*”號,如果指定了域名,則必須要以http或https開頭。

攔截器實現

/**
 * websocket握手攔截器
 * 攔截握手前,握手後的兩個切面
 */
public class MyHandShakeInterceptor implements HandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                                   Map<String, Object> attributes) throws Exception {
        System.out.println("準備進行握手");
        if (request instanceof ServletServerHttpRequest) {
//            attributes.put("username",userName);
        }
        return true;
    }
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                               Exception exception) {
        System.out.println("握手成功,進入服務端");
    }
}

1.beforeHandshake,在調用handler前處理方法。常用在註冊用戶信息,綁定WebSocketSession,在handler里根據用戶信息獲取WebSocketSession發送消息。

Handler處理類

/**WebSocket處理器
 * Created by qiumeng on 2017/8/7 0007.
 */
public class MyWebSocketHander extends TextWebSocketHandler {


    private static final List<WebSocketSession> users = new ArrayList<>();


    //用戶進入系統監聽
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("成功進入了系統。。。");
        users.add(session);
    }
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        System.out.println("成功接收到消息");
        // 把客戶端的消息解析爲JSON對象
        if(message instanceof TextMessage) {


            TextMessage msg = new TextMessage("發送的數據"+message.getPayload());
            //給所有瀏覽器羣發消息
            sendMessagesToUsers(msg);
//            this.handleTextMessage(session, (TextMessage)message);
        } else if(message instanceof BinaryMessage) {
            BinaryMessage msg = new BinaryMessage((byte[]) message.getPayload());
            //給所有瀏覽器羣發消息
            sendMessagesToUsers(msg);
//            this.handleBinaryMessage(session, (BinaryMessage)message);
        } else {
            if(!(message instanceof PongMessage)) {
                throw new IllegalStateException("Unexpected WebSocket message type: " + message);
            }
//            this.handlePongMessage(session, (PongMessage)message);
        }


    }


    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {}
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {System.out.println("安全退出了系統");}
    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
    /**
     * 給所有的用戶發送消息
     */
    public void sendMessagesToUsers(WebSocketMessage<?>  message){
        for(WebSocketSession user : users){
            try {
                //isOpen()在線就發送
                if(user.isOpen()){
                    user.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //進行實例化bean可以在其他controller實例化 調用所發送的信息
    @Bean
    public MyWebSocketHander myWebSocketHander(){
        return myWebSocketHander();
    }
}

客戶端連接

這裏只寫出javascript代碼

<script type="text/javascript">
    var receive_text = document.getElementById("up");
    var myWorker = new SharedWorker('http://localhost:8081/portal/resources/js/worker.js');
    console.log("創建sharedwork");


    myWorker.onerror = function(e)
    {
        console.log('myWorker.onerror : ' + e.message);
    }
    function myOnMessage(e) {
        receive_text.innerHTML += "<br/>" + e.data;
        receive_text.scrollTop = receive_text.scrollHeight;


    }
    if(1){
        // 4 綁定消息處理函數,僅設置 onmessage
        myWorker.port.onmessage = myOnMessage;
    }
    else{
        // 5 另外一種消息綁定方式, addEventListener 和 start 配合使用
        myWorker.port.addEventListener('message', myOnMessage);
        myWorker.port.start();
    }


    function send(){
        var ret = myWorker.port.postMessage(JSON.stringify($("#message").val()))
    }
    //頁面發送消息
    function sendMessage() {


//        var ret = myWorker.port.postMessage(stringToBytes($("#message").val()))
        var file=$("#file")[0].files[0];
        var reader = new FileReader();
        if(""==file){
            alert("請選擇文件")
        }
//        reader.readAsBinaryString(file)
        reader.readAsArrayBuffer(file)
        reader.onload = function (e) {
            if (e.target.readyState == FileReader.DONE) {
                var data = new Uint8Array(e.target.result);
                //這裏有一個問題,目前沒有解決 就是傳輸二進制數據大小的問題 好像爲100萬字節左右 
                //在大的話,目前沒有找到解決辦法
                var jsondata=JSON.stringify(data.slice(0, 100))
                var ret = myWorker.port.postMessage(jsondata);
            }
        }


    }
</script>
下面是創建sharedWorker主線程代碼work.js
var count = 0;
var ports = [];
var webSocket = new WebSocket("ws://localhost:8081/portal/webSocketServer");
var websocketMessage=null;


// 唯一的事件處理函數
onconnect = function(e) { 
console.log('onconnect from home');
// 1 網頁建立連接獲取端口
var port = e.ports[0];

ports.push({
port:port,
lastRecv: new Date()
});


// 2 綁定事件處理函數
port.addEventListener('message', function(e) {
var ret = e.data;
        //因爲WebSockets只能通過連接發送純文本數據,所以對於複雜的數據結構,在通過連接發送之前,必須進行序列化
//發送消息到後臺
if(""!=ret){
            console.log("向websocket後臺發送消息")
webSocket.send(ret);
}
});
// 3 啓動端口
port.start();
}


webSocket.onopen = function(event) {
    console.log("websocket創建");
};


webSocket.onmessage = function(event) {
    console.log("websocket返回消息")
    websocketMessage=event.data
    //data的數據格式也是字符串,如果想得到其他格式的數據,必須手工解析這些數據
    for(var i=0;i<ports.length;i++){
        var p=ports[i];
        p.port.postMessage(websocketMessage)
    }
};
webSocket.onerror = function(event) {


};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章