(百度地圖)WebSocket地圖實時更新位置

###問題描述
今天在公司的平臺業務有一個功能需求:要求實時顯示設備的地理位置在地圖上,設備可能是一臺汽車,而我們使用的地圖是百度地圖API,這樣難免會涉及到實時更新位置的問題,又由於是web,http不是一個持續型的協議,所以功能上難免有點和桌面應用不一樣

###公司技術選型
首先是技術選型的問題,公司平臺本身是javaWeb,所以不用說基本上都是SSM和SSH這系列的框架,公司使用javaWeb同時支持RPC 和 Restfull跨平臺調用,由於我們底層還要一個視頻流的控制是由C++實現的,又加上整個平臺操作數據庫的只有JAVA,所以不可避免的會有跨語言的業務產生。

既然我們的JavaWeb支持了這麼多,直接使用servlet是不現實的,所以我們的業務必須和spring完美縫合,這樣才能保證不會出現其它坑

###爲什麼選擇WebSocket?
首先:當前的平臺並非是大衆平臺,而且企業內部使用的信息化平臺,所以無需考慮瀏覽器的兼容性,只要告訴客戶公司,你只用這些瀏覽器就好了,所以這爲使用websocket奠定了基礎

其次:是關於服務器資源的問題,如果使用大量的Ajax輪詢,必然會導致一段時間內產生大量的Http請求*(要知道其實Http請求的開銷也挺大的)*

再者:對方公司希望地圖的數據顯示儘量同步,如果使用Ajax輪詢難免會造成延遲,如果我們把Ajax輪詢時間間期調短,必然會使Http請求大量增加,如果調長會導致數據延遲性較大,影響用戶體驗

最後:spring是能完全支持webSocket的,這樣也使得使用WebSocket接入平臺不會挖坑

###WebSocket接入過程

1、首先我先介紹一下springmvc接入WebSocket需要準備什麼
maven依賴(我主要使用的是這個,當然也有其它工具包可以使用)
maven

其次我們需要編寫兩個類

一個是:WebSocketConfig
另一個是:SystemWebSocketHandler

WebSocketConfig:

package com.zsl.WebSocket.oth;

import org.springframework.context.annotation.Bean;
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;

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

    //webSocket註冊
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
        webSocketHandlerRegistry.addHandler(systemWebSocketHandler(),"/webSocketServer");
    }

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

}

SystemWebSocketHandler:

package com.zsl.WebSocket.oth;

import org.springframework.web.socket.*;
import java.util.ArrayList;
import java.util.Random;

public class SystemWebSocketHandler implements WebSocketHandler {

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

    //鏈接成功
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
        System.out.println("ConnectionEstablished");
        users.add(webSocketSession);
        webSocketSession.sendMessage(new TextMessage("鏈接成功!"));

    }

    //收到消息
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
        System.out.println("handleMessage:" + webSocketMessage.toString());
        int max=175;
        int min=10;
        Random random = new Random();
        while(true) {
            int x = random.nextInt(max) % (max - min + 1) + min;
            int y = random.nextInt(max) % (max - min + 1) + min;
            System.out.println(x + "," + y);
            TextMessage msBack = new TextMessage(x + "," + y);
            webSocketSession.sendMessage(msBack);
            Thread.sleep(1000);
        }
    }

    //異常錯誤
    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        if(webSocketSession.isOpen()){
            webSocketSession.close();
        }
        users.remove(webSocketSession);
    }

    //斷開鏈接
    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        users.remove(webSocketSession);
    }

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


}

從代碼中可以看出所有的websocket的請求路徑都是在WebSocketConfig 中配置的,這個類就是我們整合Websocket和spring的配置類,我們也在這個類裏面註冊相應的webSocket的請求路徑和對應的處理Handler,其中我們使用的註解的方式整合

在SystemWebSocketHandler中,重寫的方法就是對應與websocket的處理

##我這裏使用Java後臺生成隨機座標然後前臺通過WebSocket響應

###百度地圖頁面(樣例)
代碼:

<%@ page language="java" contentType="text/html; charset=utf-8"
         pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">    
<head>    
    <title>百度地圖API顯示多個標註點帶提示的代碼</title>    
    <!--css-->    
    <style type="text/css">
        body, html, #allmap
        {
            width: 100%;
            height: 100%;
            overflow: hidden;
            margin: 0;
        }
        #l-map
        {
            height: 100%;
            width: 78%;
            float: left;
            border-right: 2px solid #bcbcbc;
        }
        #r-result
        {
            height: 100%;
            width: 20%;
            float: left;
        }
    </style>
    <!--javascript-->    
    <script src="http://www.w3school.com.cn/jquery/jquery.js" type="text/javascript"></script>    
</head> 

<body>
            <div id="allmap"> 
                   
            </div>
            <script type="text/javascript">
                var websocket = new WebSocket('ws://localhost:8080/webSocketServer');
                websocket.onopen = function (evnt) {
                    console.log('ws clint:open websocket');
                    //發送消息
                    var msg = '這個是來自瀏覽器的消息';
                    console.log('ws clint:send msg:'+msg);
                    websocket.send(msg);
                };

                websocket.onmessage = function (evnt) {
                    console.log('ws client:get message ');
                    var bp0 = evnt.data.split(",")[0];
                    var bp1 = evnt.data.split(",")[1];
                    makers[0].setPosition(new window.BMap.Point(bp0, bp1));
                  /*  makers[0].getPosition().lng = bp0;
                    makers[0].getPosition().lat = bp1;*/
                };

                websocket.onerror = function (evnt) {
                    console.log('ws client:error '+evnt)
                };

                websocket.onclose = function (evnt) {
                    console.log('ws clent:close ')
                }
                

                var makers = new Array();
                var tempPoint = null;
                var markerArr = [    
                    { id: "1", title: "名稱:123", point: "113.264531,23.157003", address: "123456", tel: "12306" },    
                    
                ];    
     
                
                var map; //Map實例    
                function map_init() {    
                    map = new BMap.Map("allmap");
                   
                    //第1步:設置地圖中心點
                    var point = new BMap.Point(113.312213, 23.147267);    
                    //第2步:初始化地圖,設置中心點座標和地圖級別。    
                    map.centerAndZoom(point, 1);
                    //第3步:啓用滾輪放大縮小    
                    map.enableScrollWheelZoom(true);    
                    //第4步:向地圖中添加縮放控件    
                    var ctrlNav = new window.BMap.NavigationControl({    
                        anchor: BMAP_ANCHOR_TOP_LEFT,    
                        type: BMAP_NAVIGATION_CONTROL_LARGE    
                    });    
                    map.addControl(ctrlNav);    
                    //第5步:向地圖中添加縮略圖控件    
                    var ctrlOve = new window.BMap.OverviewMapControl({    
                        anchor: BMAP_ANCHOR_BOTTOM_RIGHT,    
                        isOpen: 1   
                    });    
                    map.addControl(ctrlOve);    
     
                    //第6步:向地圖中添加比例尺控件    
                    var ctrlSca = new window.BMap.ScaleControl({    
                        anchor: BMAP_ANCHOR_BOTTOM_LEFT    
                    });    
                    map.addControl(ctrlSca);    

                    //點擊事件
                    map.addEventListener("click", showInfo);

                    function showInfo(e) {//鼠標點擊顯示經緯度
                        //alert(e.point.lng + ", " + e.point.lat);
                        alert("websocket觸發");


                        if(confirm("是否發送websocket?")==true){
                            websocket.send("瀏覽器發送過來的消息");
                        }
                        tempPoint = e;
                    }
     
                    //第7步:繪製點      
                    for (var i = 0; i < markerArr.length; i++) {
                       
                        var p0 = markerArr[i].point.split(",")[0];    
                        var p1 = markerArr[i].point.split(",")[1];    
                        var maker = addMarker(new window.BMap.Point(p0, p1), i);    
                        makers[i] = maker;
                        addInfoWindow(maker, markerArr[i], i);
                    }    
                }    
     
                var makers = new Array();
                // 添加標註    
                function addMarker(point, index) {
                    var myIcon = new BMap.Icon("http://api.map.baidu.com/img/markers.png",    
                        new BMap.Size(23, 25), {    
                            offset: new BMap.Size(10, 25),    
                            imageOffset: new BMap.Size(0, 0 - index * 25)    
                        });    
                    var marker = new BMap.Marker(point, { icon: myIcon });
                    marker.enableDragging();
                    map.addOverlay(marker);    
                    return marker;    
                }    

                function getActPoint(id){
                    var marketpoint =makers[id].getPosition();
                    alert(tempPoint.point.lng+"  ,"+tempPoint.point.lat);
                }


                

     
                // 添加信息窗口    
                function addInfoWindow(marker, poi,e) {    
                    //pop彈窗標題    
                    var title = '<p style="font-weight:bold;color:#CE5521;font-size:14px">' + poi.title + '</p>';    
                    //pop彈窗信息    
                    var html = [];    
                    html.push('<table cellspacing="0" style="table-layout:fixed;width:100%;font:12px arial,simsun,sans-serif"><tbody>');    
                    html.push('<tr>');    
                    html.push('<td style="vertical-align:top;line-height:16px;width:38px;white-space:nowrap;word-break:keep-all">地址:</td>');    
                    html.push('<td style="vertical-align:top;line-height:16px">' + poi.address + ' </td>');
                    
                    html.push('</tr>');    
                    html.push('</tbody></table>');  
                    html.push('<div>');
                    html.push('<button onclick=\"getActPoint('+poi.id+');\">顯示當前位置</button>');
                          
                    html.push('</div>');     
                    var infoWindow = new BMap.InfoWindow(html.join("*"), { title: title, width: 200 });    
     
                    var openInfoWinFun = function () {    
                        marker.openInfoWindow(infoWindow);    
                    };    
                    marker.addEventListener("click", openInfoWinFun);
                    marker.setAnimation(BMAP_ANIMATION_BOUNCE); //跳動的動畫    
                    return openInfoWinFun;    
                }    
     
                //異步調用百度js    
                function map_load() {    
                    var load = document.createElement("script");    
                    load.src = "http://api.map.baidu.com/api?v=1.4&callback=map_init";    
                    document.body.appendChild(load);    
                }    
                window.onload = map_load;    
            </script>    
</body>    
</html>

最後效果:
這裏寫圖片描述

歡迎大家指出問題

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