SSE

html5提供了Server-Sent Events方法,通过服务器发送事件,更新能够自动到达。

使用示例:

if (typeof (EventSource) !== "undefined") {
    var source = new EventSource("server.php");
    source.onopen = function () {
        console.log("Connection to server opened.");
    };
    source.onmessage = function (event) {
        document.getElementById("result").innerHTML += event.data + "<br>";
    };
    source.onerror = function () {
        console.log("EventSource failed.");
    };
}
else {
    document.getElementById("result").innerHTML = "抱歉,你的浏览器不支持 server-sent 事件...";
}

服务端:

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

date_default_timezone_set('PRC');

$i = 0;

while (++$i < 100) {
    echo "id: " . $i . "\tdate: " . date('c') . ";\n\n";
    ob_flush();
    flush();
    sleep(1);
}

SSE与MQTT对接

https://github.com/CloudMQTT/mqtt-sse

PostgreSQL

将Mysql数据库迁移至PostgreSQL

简单的方法:使用Navicat Premium复制功能

选中源表名-右击复制-到新库里粘贴

方法一.使用python工具 py-mysql2pgsql(python3下不支持)

项目地址:https://pypi.org/project/py-mysql2pgsql/

pip安装的时候如果遇到: _mysql.c(42) : fatal error C1083: Cannot open include file: ‘config-win.h’: No such file or directory

可以去安装 mysql-python 模块: http://www.codegood.com/archives/129

方法二.pgloader(推荐用该命令)

项目地址:https://github.com/dimitri/pgloader

1.安装:

apt install pgloader

2.创建迁移配置文件 mysql_to_pgsql.load

LOAD DATABASE
        FROM mysql://username@192.168.50.1:3306/xxl_job
        INTO postgresql://server?sslmode=allow
        WITH include drop, create tables, create indexes, workers = 8, concurrency = 1
ALTER SCHEMA 'xxl_job' RENAME TO 'public';

3.执行配置文件

pgloader -v --no-ssl-cert-verification mysql_to_pgsql.load

4.也可以单个命令中执行

pgloader mysql://user@localhost/sakila postgresql:///pagila?sslmode=allow

MySQL与PostgreSQL语法差异

LIMIT

PostgreSQL不支持 LIMIT ?,? 写法,不过可以用OFFSET代替(MySQL也兼容OFFSET)

比如:

LIMIT #{offset} , #{pagesize}

可以写成:

LIMIT #{pagesize} OFFSET #{offset}

DATE_ADD

PostgreSQL不支持DATE_ADD写法,使用timestamp代替

比如:

DATE_ADD(#{nowTime},INTERVAL -#{timeout} SECOND)

改成:

timestamp '${nowTime}'::timestamp + interval '-${timeout}) sec'

PostgreSQL设置自增auto_increment

PostgreSQL无法像MySQL一样设置自增id,可以通过计数器来实现:

-- 创建该的计数器sequence
CREATE SEQUENCE seq_test_id;
-- 设置 sequence 的开始值
SELECT setval('seq_test_id', 20);
-- 设置id的值,从计数器获取
ALTER TABLE "public".test ALTER COLUMN id SET DEFAULT nextval('seq_test_id');

查看计数器最大值:

SELECT setval('seq_test_id', max(id)) FROM m_md;

注意:id需要去除主键

显示创建表结构,实现类似 SHOW CREATE TABLE 语句

PostgreSQL无法像MySQL一样SHOW CREATE TABLE,可以通过函数来实现:

-- ----------------------------
-- Function structure for generate_create_table_statement
-- ----------------------------
DROP FUNCTION IF EXISTS "public"."generate_create_table_statement"("p_table_name" varchar);
CREATE OR REPLACE FUNCTION "public"."generate_create_table_statement"("p_table_name" varchar)
  RETURNS "pg_catalog"."text" AS $BODY$
DECLARE
    v_table_ddl   text;
    column_record record;
BEGIN
    FOR column_record IN 
        SELECT 
            b.nspname as schema_name,
            b.relname as table_name,
            a.attname as column_name,
            pg_catalog.format_type(a.atttypid, a.atttypmod) as column_type,
            CASE WHEN 
                (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
                 FROM pg_catalog.pg_attrdef d
                 WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) IS NOT NULL THEN
                'DEFAULT '|| (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
                              FROM pg_catalog.pg_attrdef d
                              WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)
            ELSE
                ''
            END as column_default_value,
            CASE WHEN a.attnotnull = true THEN 
                'NOT NULL'
            ELSE
                'NULL'
            END as column_not_null,
            a.attnum as attnum,
            e.max_attnum as max_attnum
        FROM 
            pg_catalog.pg_attribute a
            INNER JOIN 
             (SELECT c.oid,
                n.nspname,
                c.relname
              FROM pg_catalog.pg_class c
                   LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
              WHERE c.relname ~ ('^('||p_table_name||')$')
                AND pg_catalog.pg_table_is_visible(c.oid)
              ORDER BY 2, 3) b
            ON a.attrelid = b.oid
            INNER JOIN 
             (SELECT 
                  a.attrelid,
                  max(a.attnum) as max_attnum
              FROM pg_catalog.pg_attribute a
              WHERE a.attnum > 0 
                AND NOT a.attisdropped
              GROUP BY a.attrelid) e
            ON a.attrelid=e.attrelid
        WHERE a.attnum > 0 
          AND NOT a.attisdropped
        ORDER BY a.attnum
    LOOP
        IF column_record.attnum = 1 THEN
            v_table_ddl:='CREATE TABLE '||column_record.schema_name||'.'||column_record.table_name||' (';
        ELSE
            v_table_ddl:=v_table_ddl||',';
        END IF;

        IF column_record.attnum <= column_record.max_attnum THEN
            v_table_ddl:=v_table_ddl||chr(10)||
                     '    '||column_record.column_name||' '||column_record.column_type||' '||column_record.column_default_value||' '||column_record.column_not_null;
        END IF;
    END LOOP;

    v_table_ddl:=v_table_ddl||');';
    RETURN v_table_ddl;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

使用方法:

SELECT generate_create_table_statement('table_name');

OpenCV

在python环境下使用opencv:

pip install opencv-python

物体检测

void detectMultiScale(
    const Mat& image,                //待检测图像
    CV_OUT vector<Rect>& objects,    //被检测物体的矩形框向量
    double scaleFactor = 1.1,        //前后两次相继的扫描中搜索窗口的比例系数,默认为1.1 即每次搜索窗口扩大10%
    int minNeighbors = 3,            //构成检测目标的相邻矩形的最小个数 如果组成检测目标的小矩形的个数和小于minneighbors - 1 都会被排除
                                     //如果minneighbors为0 则函数不做任何操作就返回所有被检候选矩形框
    int flags = 0,                   //若设置为CV_HAAR_DO_CANNY_PRUNING 函数将会使用Canny边缘检测来排除边缘过多或过少的区域 
    Size minSize = Size(),              
    Size maxSize = Size()            //最后两个参数用来限制得到的目标区域的范围     
);

对于flags,有以下取值:

CV_HAAR_DO_CANNY_PRUNING:利用Canny边缘检测器来排除一些边缘很少或者很多的图像区域;
CV_HAAR_SCALE_IMAGE:按比例正常检测;
CV_HAAR_FIND_BIGGEST_OBJECT:只检测最大的物体;
CV_HAAR_DO_ROUGH_SEARCH:只做初略检测。

摄像头实时灰度处理

import cv2

vc = cv2.VideoCapture(0)
if vc.isOpened():
    open, frame = vc.read()
else:
    open = False
    
while open:
    ret, frame = vc.read()
    if frame is None:
        break
    if ret == True:
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        cv2.imshow('result',gray)
        if cv2.waitKey(10) & 0xFF == 27:
            break

vc.release()
cv2.destroyAllWindows()

人眼检测

代码

### 人眼检测
import cv2

# 创建级联分类器
classifier_eye = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_eye.xml')
# 载入图像
img_eye = cv2.imread('a.jpg')
h,w = img_eye.shape[:2]
print(h,w)

# 利用分类器进行检测
eyeRects = classifier_eye.detectMultiScale(img_eye, 1.2, 2, cv2.CASCADE_DO_CANNY_PRUNING, (w//20, w//20))
# 检测结果
if len(eyeRects) > 0:
    for eyeRect in eyeRects:
        x, y, w, h = eyeRect
        cv2.rectangle(img_eye, (int(x), int(y)), (int(x + w), int(y + h)), (0, 255, 255), 2, 8)
cv2.imshow('eye', img_eye)
cv2.waitKey()

车牌检测

安装hyperlpr库

pip install hyperlpr

代码:

#导入包
from hyperlpr import *
#导入OpenCV库
import cv2
#读入图片
image = cv2.imread("car1.jpg")
#识别结果
res = HyperLPR_PlateRecogntion(image)
print(res[0][0])

目标追踪

安装依赖库opencv-contrib-python

pip install --user opencv-contrib-python

代码:

# 目标追踪
import cv2
import sys


print(cv2.__version__)
if __name__ == '__main__' :

    # Set up tracker.
    # Instead of MIL, you can also use

    tracker_types = ['BOOSTING', 'MIL','KCF', 'TLD', 'MEDIANFLOW', 'GOTURN']
    tracker_type = tracker_types[2]

    
    if tracker_type == 'BOOSTING':
            tracker = cv2.TrackerBoosting_create()
    if tracker_type == 'MIL':
            tracker = cv2.TrackerMIL_create()
    if tracker_type == 'KCF':
            tracker = cv2.TrackerKCF_create()
    if tracker_type == 'TLD':
            tracker = cv2.TrackerTLD_create()
    if tracker_type == 'MEDIANFLOW':
            tracker = cv2.TrackerMedianFlow_create()
    if tracker_type == 'GOTURN':
            tracker = cv2.TrackerGOTURN_create()

    # Read video
    video = cv2.VideoCapture(0)

    # Exit if video not opened.
    if not video.isOpened():
        print("Could not open video")
        sys.exit()

    # Read first frame.
    ok, frame = video.read()
    if not ok:
        print('Cannot read video file')
        sys.exit()
    
    # Define an initial bounding box
    #bbox = (287, 23, 86, 320)

    # Uncomment the line below to select a different bounding box
    bbox = cv2.selectROI(frame, False)

    # Initialize tracker with first frame and bounding box
    ok = tracker.init(frame, bbox)

    while True:
        # Read a new frame
        ok, frame = video.read()
        if not ok:
            break
        
        # Start timer
        timer = cv2.getTickCount()

        # Update tracker
        ok, bbox = tracker.update(frame)

        # Calculate Frames per second (FPS)
        fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);

        # Draw bounding box
        if ok:
            # Tracking success
            p1 = (int(bbox[0]), int(bbox[1]))
            p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
            cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
        else :
            # Tracking failure
            cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)

        # Display tracker type on frame
        cv2.putText(frame, tracker_type + " Tracker", (100,20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50),2);
    
        # Display FPS on frame
        cv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2);

        # Display result
        cv2.imshow("Tracking", frame)

        # Exit if ESC pressed
        k = cv2.waitKey(1) & 0xff
        if k == 27 : break

Go

WSL2编译inlets过程

1.安装go

apt install golang-go

2.配置go代理

echo "export GO111MODULE=on" >> ~/.profile
echo "export GOPROXY=https://goproxy.cn" >> ~/.profile
source ~/.profile

3.下载安装源码

go get -u github.com/inlets/inlets-archived
cd $GOPATH/src/github.com/inlets/inlets-archived

4.开始编译

Linux:

go build

windows:

CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build

快速安装

windows

在官网直接下载msi文件安装即可:https://golang.org/dl/

ubuntu

如果您使用的是Ubuntu 16.04 LTS,18.04 LTS或19.04,那么您可以使用longsleep/golang-backportsPPA并安装Go 1.13。

add-apt-repository ppa:longsleep/golang-backports
apt-get update
apt-get install golang-go

国内不能go get处理办法

推荐使用七牛团队发布的代理模块:https://github.com/goproxy/goproxy.cn

其他代理模块

https://github.com/golang/go/wiki/Modules#are-there-always-on-module-repositories-and-enterprise-proxies

GO在线教程:https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/preface.md

Git

记录git相关操作

Xdebug

php.ini enable xdebug

xampp里自带该插件,如果是其他环境请下载:https://xdebug.org/download.php

xampp .eg

[XDebug]
zend_extension = "E:\enviroment\xampp_5.6.33\php\ext\php_xdebug.dll"
xdebug.profiler_append = 0
xdebug.profiler_enable = 1
xdebug.profiler_enable_trigger = 0
xdebug.profiler_output_dir = "E:\enviroment\xampp_5.6.33\php\tmp"
xdebug.profiler_output_name = "cachegrind.out.%t-%s"
xdebug.remote_enable = on
xdebug.remote_handler = "dbgp"
xdebug.remote_host = "127.0.0.1"
xdebug.trace_output_dir = "E:\enviroment\xampp_5.6.33\php\tmp"
xdebug.idekey = PHPSTROM
xdebug.remote_mode = "req"
xdebug.remote_port = 9000

phpstrom enable xdebug

通过file->settings->Languages Frameworks->PHP找到Servers,Host对应远程主机URL, Debugger 选用 Xdebug ,如果是远程调试,一定得开启路径映射功能,否则无法调试,本地的路径不用选,在新建远程项目的时候就已经确定,Absolute path on the server 则是远程主机的 Web 路径。

点击电话图标,开启调试监听

客户端触发调试

让客户端触发调试,有多种方式

在URL后追加参数

?XDEBUG_SESSION_START=forxdebug

往cookie里追加参数

XDEBUG_SESSION=PHPSTORM

我们可以借助Xdebug helper插件

从Chrome插件商店里安装:

https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc

然后点击插件小图标开启debug,该插件会自动往cookie里追加XDEBUG_SESSION

在postman里直接添加cookie参数

往postman里Headers里添加

cookie:XDEBUG_SESSION=PHPSTORM

调试时修改变量值

可以新建一个watch,创建对应的变量,并赋值。

PWA

PWA 是 Progressive Web Apps 的简称

中文叫渐进式web模型,或者叫下一代web模型。

我们可以理解成谷歌版小程序(其实它是小程序的爷爷!)

给 VUE 项目添加 PWA

新版vue脚手架模版已经集成pwa,这次是针对老的vue项目升级pwa。

首先把webpack从3.x升级到4.x,处理掉中间的各种兼容问题后:

安装 @vue/cli-plugin-pwa 插件,安装的时候会自动更新配置,比如它会找到入口文件src/main.js 并引入 registerServiceWorker.js

import './registerServiceWorker'

然后安装 workbox-webpack-plugin 模块:

yarn add workbox-webpack-plugin -D

接下来编辑webpack.prod.conf.js给生产环境下的webpack配置添加插件相关配置

const WorkboxPlugin = require('workbox-webpack-plugin');

plugins: [
    new WorkboxPlugin.GenerateSW({
        cacheId: 'bbq', // 设置前缀
        skipWaiting: true, // 强制等待中的 Service Worker 被激活
        clientsClaim: true, // Service Worker 被激活后使其立即获得页面控制权
        swDest: 'service-worker.js', // 输出 Service worker 文件
        globDirectory: 'dist',
        globPatterns: ['**/*.{html,js,css,png.jpg}'], // 匹配的文件
        globIgnores: ['service-worker.js'], // 忽略的文件
        runtimeCaching: [
            // 配置路由请求缓存
            {
            urlPattern: /.*\.js/, // 匹配文件
            handler: 'networkFirst' // 网络优先
            }
        ]
    }),
    ...
]

最后还要修改 config\prod.env.js 文件,给它添加BASE_URL变量:

module.exports = {
    NODE_ENV: '"production"',
    BASE_URL: '"/vue/"'
}

Python

Python交互模式REPL

JavaScript

JavaScript 中等号判断

JavaScript

ES6 浏览器兼容

如果在页面直接写ES6语法,会导致低版本浏览器不兼容,通过引入browser和browser-polyfill来支持:

<script src="https://cdn.staticfile.org/babel-core/5.8.38/browser.min.js"></script>
<script src="https://cdn.staticfile.org/babel-core/5.8.38/browser-polyfill.min.js"></script>

Bluebird 是早期 Promise 的一种实现,它提供了丰富的方法和语法糖,一方面降低了 Promise 的使用难度,一方面扩展了 Promise 的功能:

<script src="https://cdn.jsdelivr.net/bluebird/3.5.0/bluebird.min.js"></script>

针对浏览器来选择 polyfill,在线创建一个兼容脚本

https://polyfill.io/v3/url-builder/

使用方法:

<script crossorigin="anonymous" src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Promise"></script>
或者
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=Promise"></script>

在线把ES6转成ES5

谷歌的:http://google.github.io/traceur-compiler/demo/repl.html

Babel:https://babeljs.io/repl