从0开始疫情3D地球 - 3D疫情地球VDEarth - 6 - 数据推送

前面几篇已经完成了前端3D疫情地球的实现和疫情数据的爬虫,如何将这两个连接起来,须要在这两个程序之间搭建一个服务html

服务类型不少,这里使用websocket实现前端

1 websocket服务端python

2 websocket客户端mysql

websocket服务端

这里使用python实现一个简易的websocket服务端,借助python组件websockets便可实现git

新建一个server.py,作一个简单链接验证,代码最后设定服务地址为 localhost:9998 github

import asyncio
import websockets
import json
from mysqlDataAccess import MysqlDataAccess
import logging
from datetime import datetime
import time

interval = 60

logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',
                    level=logging.INFO)
logging.info('websocket服务启动')

# 检测客户端权限,用户名密码经过才能退出循环
async def check_permit(websocket):
    while True:
        recv_str = await websocket.recv()
        cred_dict = recv_str.split(":")
        if cred_dict[0] == "admin" and cred_dict[1] == "123456":
            logging.info('认证经过')
            return True
        else:
            content = {"code": 0, "msg": "authentication failed"}
            logging.info('认证失败')
            await websocket.send(json.dumps(content))

# 接收客户端消息并处理,这里只是简单把客户端发来的返回回去
async def send(websocket):
    await send_data(websocket)
    while True:
        await send_data(websocket)
        time.sleep(interval)

# 服务器端主逻辑
async def main_logic(websocket, path):
    await check_permit(websocket)
    # await recv_msg(websocket)
    await send(websocket)

async def send_data(websocket):
    access = MysqlDataAccess()
    data = access.getData()
    logging.info('数据获取完成')
    await websocket.send(json.dumps(data))
    logging.info('信息发送中')


start_server = websockets.serve(main_logic, 'localhost', 9998)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

里面调用了一个MysqlDataAccess类,这个用来定时的从mysql数据库获取数据,相关代码以下,实现了MySQL的疫情数据的读写web

import pymysql 

MYSQL_HOST = 'localhost'
MYSQL_DB = 'covid19'
MYSQL_USER = 'root'
MYSQL_PASSWORD = '123456'
MYSQL_PORT = 3306


class MysqlDataAccess:
    def __init__(self,host = MYSQL_HOST,database=MYSQL_DB,user=MYSQL_USER,password=MYSQL_PASSWORD,port=MYSQL_PORT):
        try:
            self.db = pymysql.connect(host,user,password,database,charset='utf8',port=port)
            self.cursor = self.db.cursor(cursor=pymysql.cursors.DictCursor)
        except  pymysql.MySQLError as e :
            print(e.args)

    def updateCountryPosition(self,name,lng,lat,type):
        sql_update = 'insert into dic_lnglat (name,lng,lat,type) values(%s,%s,%s,%s) on duplicate key update'
        sql_update += ' name= %s,lng=%s,lat=%s,type=%s'
        try:
            self.cursor.execute(sql_update,(name,lng,lat,type) * 2)
            self.db.commit()
            print(name)
        except pymysql.MySQLError as e:
            print(e.args)
            self.db.rollback()

    def getData(self):
        sql_query = 'SELECT a.name,b.lng,b.lat,IFNULL(a.new,0) as new,IFNULL(a.now,0) as now,IFNULL(a.total,0) as total,IFNULL(a.cure,0) as cure,IFNULL(a.death,0) as death from covid19  a inner join dic_lnglat b on a.`name`=b.`name`'
        try:
            self.cursor.execute(sql_query)
            return self.sql_fetch_json()
        except pymysql.MySQLError as e:
            print(e.args)


    def sql_fetch_json(self):
        keys = []
        for column in self.cursor.description:
            keys.append(column[0])
        key_number = len(keys)

        json_data = []
        for row in self.cursor.fetchall():
            item = dict()
            for q in range(key_number):
                item[keys[q]] = row[keys[q]]
            json_data.append(item)

        return json_data

这样一个简单的websocket服务就完成了sql

为了启动简单,在windows环境下,新建一个socketServer.bat用来启动服务数据库

@echo off


F:
rem ִ开启socker服务 
cd F:\mygithub\VDDataServer\SocketServer
python3 server.py

TIMEOUT /T 10
exit

执行bat就能够打开服务json

websocket客户端

websocket的客户端,VDEarth是基于js的前端可视化应用,这里须要实现一个前端的websocket客户端,这里直接对以前的VDEarth前端组件进行改造

在VDEarth项目文件夹src文件夹下新增一个socket.js, 新增socket访问类

import _ from 'lodash';

function reconnect() {
  console.log('从新链接');
}
function open() {
  // Web Socket 已链接上,使用 send() 方法发送数据
  this.ws.send(this.account + ':' + this.password);
}
// 接受数据执行回调方法
function receive(evt, callback) {
  var data = evt.data;
  if (_.isFunction(callback)) {
    callback(JSON.parse(data));
  }
}
function close() {
  // 关闭 websocket
  console.log('链接已关闭...');
  reconnect();
}
function reload() {
  this.ws.send('reload');
}
class socket {
  constructor(server, port, account, password) {
    this.account = account;
    this.password = password;
    this.server = server;
    this.port = port;
  }

  init(onmessage) {
    if ('WebSocket' in window) {
      try {
        this.uri = 'ws://' + this.server + ':' + this.port;
        this.ws = new WebSocket(this.uri);
        this.ws.onopen = () => {
          open.call(this);
        };
        this.ws.onmessage = (evt) => {
          receive.call(this, evt, onmessage);
        };
        this.ws.onclose = () => {
          close.call(this);
        };
        window.onbeforeunload = () => {
          reload();
        };
      } catch (error) {
        console.log(error);
      }
    } else {
      // 浏览器不支持 WebSocket
      console.log('您的浏览器不支持 WebSocket!');
    }
  }
}

export default socket;

修改VDEarth.js

数据的加载主要是用在了柱形图和名称标记那里,因此修改那里的代码,即initObj方法,VDEarth类的options方法配置默认的socket连接,server  = localhost,port = 9998,account = admin,password = 123456

// 建立模型
function initObj() {
  let self = this;
  let fontloader = new FontLoader();
  // 建立地球模型组
  this.baseGroup = new Group();
  // 建立地球
  this.radius = minSize(this.contentWidth, this.contentHeight) * 0.2;
  let globalMesh = new model().createGlobe(this.radius, this.textrue);
  this.baseGroup.add(globalMesh);
  // 建立星点
  let stars = new model().createStars();
  this.baseGroup.add(stars);

  // 建立链接
  var mySocket = new socket(
    this.options.server,
    this.options.port,
    this.options.account,
    this.options.password
  );
  mySocket.init(function (data) {
    // 建立一个标记组
    self.markerGroup = new Group();
    // 建立标记
    var myMarkers = new marker();
    // 柱形
    myMarkers.addBoxMarkers(self.markerGroup, self.radius, data);
    // 加载字体
    if (self.font) {
      myMarkers.addNameMarkers(self.markerGroup, self.radius, data, self.font);
    } else {
      fontloader.load('./fonts/SimHei_Regular.json', function (font) {
        self.font = font;
        myMarkers.addNameMarkers(
          self.markerGroup,
          self.radius,
          data,
          self.font
        );
      });
    }
    self.baseGroup.add(self.markerGroup);
  });
  this.scene.add(this.baseGroup);
}

至此定时数据推送和VDEarth的展现更新就完成了

打开爬虫服务,打开websokcet服务,打开浏览器就输入VDEarth 的web容器的地址就能够了

 

相关连接

从0开始疫情3D地球 - 3D疫情地球VDEarth - 1- 引言 

从0开始疫情3D地球 - 3D疫情地球VDEarth - 2 - 前端代码构建 

从0开始疫情3D地球 - 3D疫情地球VDEarth - 3 - 3D地球组件实现(1) 

从0开始疫情3D地球 - 3D疫情地球VDEarth - 4 - 3D地球组件实现(2) 

从0开始疫情3D地球 - 3D疫情地球VDEarth - 5 - 疫情数据爬虫 

从0开始疫情3D地球 - 3D疫情地球VDEarth - 6 - 数据推送  

相关文章
相关标签/搜索