gat1400 digest摘要驗證 保活 GOFRAME NSQ gorm etcd token 訂閱通知 延遲隊列


備忘

人臉結構化數據: function/intelli/face

平台數據庫 192.168.1.204:31196 root testing對嗎

有疑惑的地方

  1. 是什么,定義接口規范,完成了一部分注冊和校時功能,待完成保活和注銷。

ga1400

1400標准有4部分:

GA-T 1400.1-2017 公安視頻圖像信息應用系統 第1部分:通用技術要求;

GA-T 1400.2-2017 公安視頻圖像信息應用系統 第2部分:應用平台技術要求;

GA-T 1400.3-2017 公安視頻圖像信息應用系統 第3部分:數據庫技術要求;

GA-T 1400.4-2017 公安視頻圖像信息應用系統 第4部分 接口協議要求;

1400與28181有共性的地方,比如設備編碼規范、信令交互規范等,膚淺一點說,28181定義的是視頻聯網,1400定義的圖片傳輸,目前幾乎沒有安防廠家能完全吃透1400標准,應用最多的是ipc傳輸圖片及相關信息到后端設備/平台,以及視圖庫平台與平台對接等,比如人臉抓拍機傳輸人臉圖片、人臉特征等到人臉應用平台,車輛抓拍機傳輸車輛圖片、車牌信息到車輛卡口平台。

東方網力視頻圖像解析系統

GA/T 1400《公安視頻圖像信息應用系統》是公安部發布的公共安全行業標准,系統由應用平台、視圖庫、公安視頻圖像分析設備/系統以及在線視頻信息采集設備/系統等部分組成。東方網力視頻圖像解析系統在GA/T 1400的標准上提供多源、多級數據的接入、存儲、共享、分析,及對外標准化接口服務的能力。依托於物聯網多維感知采集技術、視圖智能結構化解析技術、混合雲計算技術、視圖大數據聚類挖掘技術等,對原始視頻、圖像信息進行內容解析,將獲得的結構化信息和其他感知數據(RFID、GPS)相結合,面向公安視頻圖像類的上層業務應用, 提供統一的視圖資源服務支持能力。

據悉,GA/T 1400.2 《公安視頻圖像信息應用系統 第2部分:應用平台技術要求》目前檢測中心已經開啟了摸底測試,東方網力即將開始進行摸底測試,未來,東方網力將繼續深耕視頻圖像解析系統核心技術研發與公共安全領域的應用與落地,切實解決市場需求,助力產業智能化升級。

GA/T1400《公安視頻圖像信息應用系統》標准說明:

GA/T 1400.3 規定了公安視頻圖像信息數據庫的組成、存儲對象、功能、性能、安全性等技術要求。

GA/T 1400.4 規定了公安視頻圖像信息應用系統的接口分類與協議結構、接口功能、接口資源描述、接口消息、關鍵消息交互流程、消息交互安全性等技術要求。

注冊

需要發送json數據 String sendJson = "{"RegisterObject":{"DeviceID":"41000000005030312222"}}";

第一次請求,json數據+header信息+發送post請求

{"RegisterObject":{"DeviceID":"33010299011190000253"}}

第二次請求,將請求次數轉為八位16進制 String noncecount = getHex(countList.size()); ?試了,不可以

digest摘要驗證

使用 Digest auth,客戶端向 API 發送第一個請求,服務器響應一些細節,包括只能使用一次的數字(現時)、領域值和401未經授權的響應。然后,您將包含用戶名和密碼的加密數據數組與在第一個請求中從服務器收到的數據一起發回。服務器使用傳遞的數據生成加密字符串,並將其與您發送的內容進行比較,以驗證您的請求。

在請求的授權選項卡中,從類型下拉列表中選擇摘要式身份驗證。Postman 將顯示身份驗證請求的兩個階段的字段 - 但是它會使用第一個請求從服務器返回的數據自動完成第二個請求的字段。為了讓 Postman 自動化流程,輸入用戶名密碼值(或變量),這些將與第二個請求一起發送。

摘要驗證

如果您不希望 Postman 自動提取數據,請選中該框以禁用重試請求。如果您這樣做,您將需要完成高級字段並手動運行每個請求。

高級字段是可選的,Postman 會在您的請求運行時嘗試自動填充它們。

  • 領域:服務器在WWW-Authenticate響應頭中指定的字符串。
  • Nonce:服務器在WWW-Authenticate響應頭中指定的唯一字符串。
  • 算法:一個字符串,表示用於生成摘要和校驗和的一對算法。郵遞員支持MD5SHA算法。
  • qop:應用於消息的保護質量。該值必須是服務器在WWW-Authenticate響應標頭中指定的備選方案之一。
  • Nonce Count:客戶端在本次請求中使用 nonce 值發送的請求(包括當前請求)數量的十六進制計數。
  • 客戶端隨機數:客戶端提供的不透明引用字符串值,客戶端和服務器都使用它來避免選擇明文攻擊,提供相互身份驗證,並提供一些消息完整性保護。
  • Opaque:服務器在WWW-Authenticate響應頭中指定的一串數據,在相同的保護空間中與URIs一起使用時應保持不變。

實現RoundTripper接口更規范

  1. 先發送post請求,等待返回
  2. 響應頭里面取響應碼401,md5加密
  3. 再次請求,攜帶Authenticate頭信息
        Response execute = OkGo.post(url_register)
//                            .headers("DeviceID", DEVICEID)
//                            .headers(HttpHeaders.HEAD_KEY_CONNECTION,HttpHeaders.HEAD_VALUE_CONNECTION_KEEP_ALIVE)
                            .execute();

                    int code = execute.code();
                    Log.i(HEAD,"register code >> " + code);

                    if (code == 401){
                        Headers headers =  execute.headers();

                        int size = headers.size();

                        Set<String> names = headers.names();
                        Log.i(HEAD,"register cacheResponse headers size >> " + size + " ; names size >> " + names.size());
                        for (String name : names) {
                            String value = headers.get(name);
                            Log.i(HEAD,"key = " + name + " ; value = " + value);
                        }
                        String authValue = headers.get(KEY_AUTHENTICATE);
                        Log.i(HEAD,"authValue >> " + authValue);
                        String[] split = authValue.split(",");
                        AuthenticateBean authenticateBean = new AuthenticateBean();
                        for (String s : split) {
                            Log.i(HEAD,"split v >> " + s);
                            String[] vv = s.split("=");
                            String key = vv[0];
                            String value = vv[1];
                            value = value.replace("\"","");
                            Log.i(HEAD,"split vv key >> " + key + " ; value >> " +value);
                            if (TextUtils.equals(key.trim(),"Digest realm")){
                                authenticateBean.setDigest_realm(value);
                            }else if (TextUtils.equals(key.trim(),"qop")){
                                authenticateBean.setQop(value);
                            }else if (TextUtils.equals(key.trim(),"nonce")){
                                authenticateBean.setNonce(value);
                            }
                         }
                        Log.i(HEAD,"authenticateBean to string >> " + authenticateBean);

                        String nc = "00000001";
                        String cnonce = DigestUtils.generateSalt2(8);
                        String response = DigestUtils.getResponse(username, authenticateBean.getDigest_realm(), password, authenticateBean.getNonce(),
                                nc, cnonce, authenticateBean.getQop(), "POST","/VIID/System/Register");

                        String authorization = DigestUtils.getAuthorization(username, authenticateBean.getDigest_realm(),
                                authenticateBean.getNonce(), "/VIID/System/Register",
                                authenticateBean.getQop(), nc, cnonce, response, "");

                        //FPsBdyB5iEN/w4Ja74DyKw==
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("DeviceID",DEVICEID);
                        JSONObject js = new JSONObject();
                        js.put("RegisterObject",jsonObject);
                        String s = js.toString();
                        Log.i(HEAD,"js str >> " + s);
                        Response execute1 = OkGo.post(url_register)
                                .upJson(s)
                                .headers("Authorization", authorization)
//                                .headers(HttpHeaders.HEAD_KEY_CONNECTION, HttpHeaders.HEAD_VALUE_CONNECTION_KEEP_ALIVE)
                                .execute();

                        int code1 = execute1.code();
                        Log.i(HEAD,"register2 code >> " + code1 );

Digest realm="me@kennethreitz.com", nonce="9205409fee3d96ef3a9090ab1364ac5e", qop="auth, auth-int", opaque="fe09c530c66582e99b0cebefb7db37bf", algorithm=MD5, stale=FALSE

Authorization: Digest username="2", realm="me@kennethreitz.com", nonce="9ad1c018c7002b7e513e0f421ec3e461", uri="/digest-auth/2/2/2", algorithm=MD5, response="3038ff9503a7fb9b792ae7850a6e935c", opaque="bd85ce08f4b10fe5ffea5fc72dce218c", qop=auth, nc=00000002, cnonce="f4ae4e77421cbac8"

response: 客戶端根據算法算出的摘要值

cnonce(clinetNonce): 客戶端發送給服務器的隨機字符串

qop: 保護質量參數,一般是auth,或auth-int,這會影響摘要的算法

nc(nonceCount):請求的次數,用於標記,計數,防止重放攻擊

保活 keep-alive

https://blog.csdn.net/xiaoduanayu/article/details/78386508

1.為什么要有Connection: keep-alive?

在早期的HTTP/1.0中,每次http請求都要創建一個連接,而創建連接的過程需要消耗資源和時間,為了減少資源消耗,縮短響應時間,就需要重用連接。在后來的HTTP/1.0中以及HTTP/1.1中,引入了重用連接的機制,就是在http請求頭中加入Connection: keep-alive來告訴對方這個請求響應完成后不要關閉,下一次咱們還用這個請求繼續交流。
谷歌瀏覽器默認總會帶上Connection: keep-alive,另外通過httpclient使用HTTP/1.0協議去請求tomcat時,即使帶上Connection: keep-alive請求頭也保持不了長連接。如果HTTP/1.1版本的http請求報文不希望使用長連接,則要在請求頭中加上Connection: close,接收到這個請求頭的對端服務就會主動關閉連接。

但是http長連接會一直保持嗎?肯定是不會的。一般服務端都會設置keep-alive超時時間。超過指定的時間間隔,服務端就會主動關閉連接。同時服務端還會設置一個參數叫最大請求數,比如當最大請求數是300時,只要請求次數超過300次,即使還沒到超時時間,服務端也會主動關閉連接。

image-20210826094159015

人臉分析

face_dev.go

GetTrackResult 獲取智能分析結果

face.go

GetTrackResult 獲取人臉跟蹤結果

http://192.168.1.140/v1/intelli/face/analyse/search/caps

{
  "Code": 200,
  "Message": "msg: success",
  "Translate": "操作成功",
  "Detail": "",
  "Data": {
    "Channels": [
      0,
      1
    ],
    "Region": null,
    "Gender": [
      {
        "Key": 0,
        "Value": "未知"
      },
      {
        "Key": 1,
        "Value": "男"
      },
      {
        "Key": 2,
        "Value": "女"
      }
    ],
    "Age": [
      {
        "Key": 1,
        "Value": "兒童"
      },
      {
        "Key": 2,
        "Value": "少年"
      },
      {
        "Key": 3,
        "Value": "青年"
      },
      {
        "Key": 4,
        "Value": "中年"
      },
      {
        "Key": 5,
        "Value": "老年"
      }
    ],
    "Hair": [
      {
        "Key": 0,
        "Value": "未知"
      },
      {
        "Key": 1,
        "Value": "禿頭"
      },
      {
        "Key": 2,
        "Value": "頭發稀疏"
      },
      {
        "Key": 3,
        "Value": "短發"
      },
      {
        "Key": 4,
        "Value": "長發"
      },
      {
        "Key": 5,
        "Value": "其他發型"
      }
    ],
    "Hat": [
      {
        "Key": 0,
        "Value": "未知"
      },
      {
        "Key": 1,
        "Value": "有"
      },
      {
        "Key": 2,
        "Value": "無"
      }
    ],
    "Respirator": [
      {
        "Key": 0,
        "Value": "未知"
      },
      {
        "Key": 1,
        "Value": "有"
      },
      {
        "Key": 2,
        "Value": "無"
      }
    ],
    "Glasses": [
      {
        "Key": 0,
        "Value": "未知"
      },
      {
        "Key": 1,
        "Value": "有"
      },
      {
        "Key": 2,
        "Value": "無"
      }
    ]
  }
}

http://192.168.1.140/v1/intelli/face/analyse/search/struct?starttime=2021-08-25+15:11:57&endtime=2021-08-25+17:11:57&offset=0&count=12&chns=0,1&temperature=undefined,undefined

{
  "Code": 200,
  "Message": "msg: success",
  "Translate": "操作成功",
  "Detail": "",
  "Data": {
    "Total": 1,
    "Num": 1,
    "Info": [
      {
        "ID": 112,
        "Chn": 0,
        "Time": 1629884310257,
        "Rect": {
          "Left": 193,
          "Top": 264,
          "Right": 229,
          "Bottom": 306
        },
        "Region": 0,
        "Type": 0,
        "Gender": 1,
        "Age": 3,
        "Hair": 3,
        "Hat": 2,
        "Respirator": 2,
        "Glasses": 1,
        "Temperature": 36.4,
        "TempAlarm": false,
        "ObjPicPath": "/tmp/mmcblk1p7/0/1629884310257.jpg",
        "FullPicPath": "/tmp/mmcblk1p7/0/1629884310256.jpg"
      }
    ]
  }
}

recognition_arm.go

GetRecognitionResult 獲取人臉識別結果

http patch請求

patch是對put的補充,更新部分資源,使用patch時候就不是了,默認是以x-www-form-urlencoded的contentType來發送信息,並且信息內容是放在request的body里。

redis 訂閱通知

https://blog.csdn.net/weixin_44187730/article/details/95061139?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163048039516780271526478%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163048039516780271526478&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-3-95061139.first_rank_v2_pc_rank_v29&utm_term=redis+%E8%AE%A2%E9%98%85&spm=1018.2226.3001.4187

在這里插入圖片描述

NSQ

https://www.liwenzhou.com/posts/Go/go_nsq/

分布式的消息隊列(中間件)

組件

nsqd:是一個守護進程,它接收、排隊並向客戶端發送消息

nsqlookupd:是維護所有nsqd狀態、提供服務發現的守護進程。

nsqadmin:一個實時監控集群狀態、執行各種管理任務的web管理平台。

架構

nsq架構設計

nsq架構設計

nsq架構設計

nsq啟動

E:\1study\nsq\nsq-1.2.1.windows-amd64.go1.16.6\bin

nsqd.exe -broadcast-address=192.168.1.12 -lookupd-tcp-address=192.168.1.12:4160
nsqlookupd.exe
nsqadmin.exe -lookupd-http-address=192.168.1.12:4161

etcd

https://www.liwenzhou.com/posts/Go/go_etcd/

b站月球豬豬教程 https://www.bilibili.com/video/BV19J41147uT?p=2

etcd是使用go語言開發的一個開源的、高可用的分布式key-value存儲系統,可以用於配置共享和服務的注冊和發現。

自動建表
```xml

GORM

注意gorm查找struct名對應數據庫中的表名的時候會默認把你的struct中的大寫字母轉換為小寫並加上“s”,所以可以加上 db.SingularTable(true) 讓grom轉義struct名字的時候不用加上s。

package main

import (
	"fmt"

	"time"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql" //這個一定要引入哦!!
)

//返回datatime
func dateTime() (formatTimeStr string) {
	NowTimeZone := time.FixedZone("CST", 8*3600)                             //東八區,返回時區指針
	formatTimeStr = time.Now().In(NowTimeZone).Format("2006-01-02 15:04:05") //2020-04-28 23:27:50
	return formatTimeStr
}

type Animal struct {
	Id          uint32
	Name        string
	Password    string
	Create_time string
}

type AutoGenerated struct {
	FaceListObject struct {
		FaceObject []struct {
			Name       string `json:"Name"`
			Password   string `json:"Password"`
			CreateTime string `json:"Create_time"`
		} `json:"FaceObject"`
	} `json:"FaceListObject"`
}

// A.19 訂閱對象 Subscribe

type Subscribe struct {
	SubscribeID string `description:"訂閱標識符"`

	Title string `description:"訂閱標題"`

	SubscribeDetail string `description:"訂閱類別"`

	ResourceURI string `description:"訂閱資源路徑"`

	ApplicantName string `description:"申請人"`

	ApplicantOrg string `description:"申請單位"`

	Begint64ime string `description:"開始時間"`

	EndTime string `description:"結束時間"`

	ReceiveAddr string `description:"信息接收地址"`

	ReportInt64erval int `description:"信息上報間隔時間"`

	Reason string `description:"理由"`

	OperateType int `description:"操作類型"`

	SubscribeStatus int `description:"訂閱執行狀態"`

	SubscribeCancelOrg string `description:"訂閱取消單位"`

	SubscribeCancelPerson string `description:"訂閱取消人"`

	CancelTime string `description:"取消時間"`

	CancelReason string `description:"取消原因"`
}

// A.20 通知對象 Notification

type Notification struct {
	NotificationID string `gorm:"type:varchar(255) primary key";description:"通知標識"`

	SubscribeID string `description:"訂閱標識"`

	Title string `description:"訂閱標題"`

	TriggerTime string `description:"觸發時間"`

	InfoIDs string `description:"信息標識"`

	CaseObjectList string `description:"視頻案事件"`

	Tollgate string `description:"視頻卡口"`

	Lane string `description:"車道"`

	DeviceList string `description:"設備"`

	DeviceStatusList string `description:"設備狀態"`

	APSObjectList string `description:"采集系統"`

	APSStatusObjectList string `description:"采集系統狀態"`

	PersonObjectList string `description:"人員信息"`

	FaceObjectList string `description:"人臉信息"`

	MotorVehicleObjectList string `description:"機動車信息"`

	NonMotorVehicleObjectList string `description:"非機動車信息"`

	ThingObjectList string `description:"物品信息"`

	SceneObjectList string `description:"場景信息"`
}

func main() {
	db, errDb := gorm.Open("mysql", "root:123123@(127.0.0.1)/test?charset=utf8mb4&loc=Local")

	if errDb != nil {
		fmt.Println(errDb)
	}
	defer db.Close() //用完之后關閉數據庫連接

	db.LogMode(true) //開啟sql debug 模式

	
	// 根據結構體,自動建表
	// table := Subscribe{}
	table2 := Notification{}
	// db.AutoMigrate(&table)
	db.AutoMigrate(&table2)

	// 讓grom轉義struct名字的時候不用加上s
	// db.SingularTable(true)

	// jsonData := []byte(`{
	// 	"FaceListObject": {
	// 		"FaceObject": [
	// 			{
	// 				"1Name1": "ling",
	// 				"Password": "2342342",
	// 				"Create_time": "2021-09-06 00:00:00"
	// 			}
	// 		]
	// 	}
	// }`)
	// animalJson := AutoGenerated{}
	// err := json.Unmarshal(jsonData, &animalJson)
	// fmt.Println(err)
	// fmt.Println(animalJson.FaceListObject.FaceObject[0].Name)
	// fmt.Println()

	// animalInsert := Animal{
	// 	Name: animalJson.FaceListObject.FaceObject[0].Name,
	// 	Password: animalJson.FaceListObject.FaceObject[0].Password,
	// 	Create_time: animalJson.FaceListObject.FaceObject[0].CreateTime}
	// // // 檢查主鍵是否為空
	// db.Create(&animalInsert)
	// fmt.Println(db.NewRecord(animalInsert))

	// db.Table("animas")
	// animalSelect := &Animal{}
	// db.Where("name = ?", "ling12").Find(animalSelect)

	// j, _ := json.Marshal(animalSelect)
	// fmt.Println(string(j))
	// fmt.Println(animalSelect.Id, animalSelect.Name, animalSelect.Password)

	// var animalSelect2 []Animal
	// db.Where("Id in (?)",[]uint{1,2,3}).Find(&animalSelect2)
	// fmt.Println(animalSelect2)
	//  fmt.Println(len(animalSelect2))

	// animalUpdate := Animal{Name: "ling1", Password: "1111111111", Create_time: dateTime()}
	// db.First(&animalUpdate)
	// animalUpdate.Name="update11111"
	// animalUpdate.Password="password"
	// db.Save(&animalUpdate)

	// animalUpdate := Animal{}
	// db.Model(&animalUpdate).Where("password = ?","5745765").Update("password","666666")

	// animalUpdate := Animal{Id: 1,}
	// db.Model(&animalUpdate).Updates(map[string]interface{}{"name":"jjjjjjjjj","password":"jjjjjjjj",})
	// animalUpdate := Animal{Id: 2}
	// db.Model(&animalUpdate).Updates(Animal{Name: "eeeeee", Password: "eeeeeeee"})

	// animalDel:=Animal{}
	// db.Delete(Animal{}, "id > 2000")

}
func main1() {

	db, errDb := gorm.Open("mysql", "root:123123@(127.0.0.1)/test?charset=utf8mb4&loc=Local")

	if errDb != nil {
		fmt.Println(errDb)
	}
	defer db.Close() //用完之后關閉數據庫連接

	db.Delete("id", 2941)

	// db.LogMode(true) //開啟sql debug 模式

	//SELECT * FROM `animals`  WHERE (id>0 and id<999) ORDER BY id desc LIMIT 2 OFFSET 1
	var owls []Animal
	db.Where("id>? and id<?", 0, 999).Order("id desc").Offset(2).Limit(2).Find(&owls)
	fmt.Println(owls)

	//獲取條數
	total := 0
	db.Model(&Animal{}).Count(&total)
	fmt.Println(total)

	//插入數據1
	var animal = Animal{Password: "123456", Name: "monkey", Create_time: dateTime()}
	db.Create(&animal)

	//插入數據2 結構體這種的表名稱是結構體名后面+s
	insErr := db.Create(&Animal{Password: "123", Name: "boy", Create_time: dateTime()}).Error
	fmt.Println(insErr)

	//插入數據3 指定表名稱:animals
	insErr3 := db.Table("animals").Create(&Animal{Name: "吳亦凡", Create_time: dateTime()}).Error
	fmt.Println(insErr3)

	animal2 := &Animal{} //獲取結構體
	//查詢數據1  SELECT * FROM `animals`  WHERE (Id=1)
	db.Where("Id=?", 1).Find(animal2) //結果集存放在animal這個struct里面
	fmt.Println(animal2, animal2.Id, animal2.Name, animal2.Create_time)

	var infos []Animal //定義一個數組來接收多條結果
	db.Where("Id in (?)", []uint32{1, 2, 3}).Find(&infos)
	fmt.Println(infos)
	fmt.Println(len(infos)) //結果條數

	var notValue []Animal
	db.Where("id=?", 3).Find(&notValue)
	if len(notValue) == 0 {
		fmt.Println("沒有查詢到數據!")
	} else {
		fmt.Println(notValue)
	}

	//http://gorm.book.jasperxu.com/crud.html#q
	//https://gorm.io/zh_CN/docs/create.html
}

圖片、視頻、文件

http://192.168.1.179/v2/picture?path=/tmp/hda21/1/1630654142023000001.jpg

GoFrame

generated: app/dao/face_objects.go
generated: app/dao/internal/face_objects.go
generated: app/model/model.go
done!

string和int類型相互轉換

string轉成int:
int, err := strconv.Atoi(string)
string轉成int64:
int64, err := strconv.ParseInt(string, 10, 64)
int轉成string:
string := strconv.Itoa(int)
int64轉成string:
string := strconv.FormatInt(int64,10)

dao代碼生成

配置config.toml或yaml

# HTTP Server
[server]
	Address     = ":8199"
	ServerRoot  = "public"
	ServerAgent = "gf-app"
	LogPath     = "/tmp/log/gf-app/server"

# Logger.
[logger]
    Path        = "/tmp/log/gf-app"
    Level       = "all"
    Stdout      = true

# Template.
[viewer]
    Path        = "template"
    DefaultFile = "index.html"
    Delimiters  =  ["{{", "}}"]

# Database.
[database]
    link  = "mysql:root:123123@tcp(192.168.1.12:3306)/test"
    debug = true
    # Database logger.
    [database.logger]
        Path   = "/tmp/log/gf-app/sql"
        Level  = "all"
        Stdout = true

# GF-CLI工具配置
[gfcli]
    # 自定義DAO生成配置(默認是讀取database配置)
    [[gfcli.gen.dao]]
        link   = "mysql:root:123123@tcp(192.168.1.12:3306)/test"
        tables = "people"
gf gen dao -h /查看幫助
gf gen dao

image-20211011101401025

model代碼生成

gf gen model ./model -c config/config.toml -p sys_ -t sys_user
2020-04-26 23:35:31.682 [DEBU] [ 51 ms] SHOW FULL COLUMNS FROM `sys_user`
generated: ./model\user\user.go
generated: ./model\user\user_entity.go
generated: ./model\user\user_model.go
done!

JWT-token

package main

import (
    "fmt"
    "net/http"
    "time"

    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
)

//自定義一個字符串
var jwtkey = []byte("www.topg1oer.com")
var str string

type Claims struct {
    UserId uint
    jwt.StandardClaims
}

func main() {
    r := gin.Default()
    r.GET("/set", setting)
    r.GET("/get", getting)
    //監聽端口默認為8080
    r.Run(":8080")
}

//頒發token
func setting(ctx *gin.Context) {
    expireTime := time.Now().Add(7 * 24 * time.Hour)
    claims := &Claims{
        UserId: 2,
        StandardClaims: jwt.StandardClaims{
            ExpiresAt: expireTime.Unix(), //過期時間
            IssuedAt:  time.Now().Unix(),
            Issuer:    "127.0.0.1",  // 簽名頒發者
            Subject:   "usertoken11", //簽名主題
        },
    }
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    // fmt.Println(token)
    tokenString, err := token.SignedString(jwtkey)
    if err != nil {
        fmt.Println(err)
    }
    str = tokenString
    ctx.JSON(200, gin.H{"token": tokenString})
}

//解析token
func getting(ctx *gin.Context) {
    tokenString := ctx.GetHeader("Authorization")
    //vcalidate token formate
    if tokenString == "" {
        ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "權限不足"})
        ctx.Abort()
        return
    }

    token, claims, err := ParseToken(tokenString)
    if err != nil || !token.Valid {
        ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "權限不足"})
        ctx.Abort()
        returnnvr
        
    }
    fmt.Println(111)
    fmt.Println(claims.UserId)
}

func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
    Claims := &Claims{}
    token, err := jwt.ParseWithClaims(tokenString, Claims, func(token *jwt.Token) (i interface{}, err error) {
        return jwtkey, nil
    })
    return token, Claims, err
}

image-20211021094400558

訂閱通知

新增訂閱

10:20發送的請求
工作時間 10:30~10:50

10分鍾后開始(600秒) 任務執行20分鍾(1200秒) 條件:每秒循環判斷data是否為空,不為空把數據發出去

10秒內

這里用的time.sleep()顯然不適用於修改和刪除;改用time.NewTImer(),支持Reset()

修改訂閱

updateTime:=time.NewTImer(5*time.Second)

updateTime.Reset(3*time.Second)

	// 修改延遲時間
	if updataDelayTime > 0 {
		Jobtime.Reset(time.Duration(updataDelayTime) * time.Second)
	}

刪除訂閱

deleteTime:=time.NewTImer(5*time.Second)

deleteTime.Reset(0)

	// 刪除延遲時間
	if deleteDelayTime > 0 {
		Jobtime.Stop()
	}

延遲隊列

https://github.com/ouqiang/delay-queue


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM