@@ -14,6 +14,7 @@ type Config struct { | |||||
RabbitMqAddr string `yaml:"rabbitMq_addr"` | RabbitMqAddr string `yaml:"rabbitMq_addr"` | ||||
RabbitMqAddrTest string `yaml:"rabbitMq_addr_test"` | RabbitMqAddrTest string `yaml:"rabbitMq_addr_test"` | ||||
DB DBCfg `yaml:"db"` | DB DBCfg `yaml:"db"` | ||||
DataDB DBCfg `yaml:"data_db"` | |||||
MQ MQCfg `yaml:"mq"` | MQ MQCfg `yaml:"mq"` | ||||
ES ESCfg `yaml:"es"` | ES ESCfg `yaml:"es"` | ||||
Log LogCfg `yaml:"log"` | Log LogCfg `yaml:"log"` | ||||
@@ -15,6 +15,7 @@ var ( | |||||
SrvAddr string | SrvAddr string | ||||
RedisAddr string | RedisAddr string | ||||
DB *DBCfg | DB *DBCfg | ||||
DataDB *DBCfg | |||||
MQ *MQCfg | MQ *MQCfg | ||||
ES *ESCfg | ES *ESCfg | ||||
Log *LogCfg | Log *LogCfg | ||||
@@ -53,6 +54,7 @@ func InitCfg() { | |||||
Local = conf.Local | Local = conf.Local | ||||
CurlDebug = conf.CurlDebug | CurlDebug = conf.CurlDebug | ||||
DB = &conf.DB | DB = &conf.DB | ||||
DataDB = &conf.DataDB | |||||
Log = &conf.Log | Log = &conf.Log | ||||
ArkID = &conf.ArkID | ArkID = &conf.ArkID | ||||
RedisAddr = conf.RedisAddr | RedisAddr = conf.RedisAddr | ||||
@@ -27,6 +27,7 @@ func InitTaskCfg() { | |||||
Prd = conf.Prd | Prd = conf.Prd | ||||
Debug = conf.Debug | Debug = conf.Debug | ||||
DB = &conf.DB | DB = &conf.DB | ||||
DataDB = &conf.DataDB | |||||
Log = &conf.Log | Log = &conf.Log | ||||
Admin = &conf.Admin | Admin = &conf.Admin | ||||
RedisAddr = conf.RedisAddr | RedisAddr = conf.RedisAddr | ||||
@@ -0,0 +1,50 @@ | |||||
package db | |||||
import ( | |||||
"fmt" | |||||
"os" | |||||
"time" | |||||
_ "github.com/go-sql-driver/mysql" //必须导入mysql驱动,否则会panic | |||||
"xorm.io/xorm" | |||||
"xorm.io/xorm/log" | |||||
"applet/app/cfg" | |||||
) | |||||
var DataDb *xorm.Engine | |||||
//根据DB配置文件初始化数据库 | |||||
func InitDataDB(c *cfg.DBCfg) error { | |||||
var ( | |||||
err error | |||||
f *os.File | |||||
) | |||||
//创建Orm引擎 | |||||
if DataDb, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", c.User, c.Psw, c.Host, c.Name)); err != nil { | |||||
return err | |||||
} | |||||
DataDb.SetConnMaxLifetime(c.MaxLifetime * time.Second) //设置最长连接时间 | |||||
DataDb.SetMaxOpenConns(c.MaxOpenConns) //设置最大打开连接数 | |||||
DataDb.SetMaxIdleConns(c.MaxIdleConns) //设置连接池的空闲数大小 | |||||
if err = DataDb.Ping(); err != nil { //尝试ping数据库 | |||||
return err | |||||
} | |||||
if c.ShowLog { //根据配置文件设置日志 | |||||
DataDb.ShowSQL(true) //设置是否打印sql | |||||
DataDb.Logger().SetLevel(0) //设置日志等级 | |||||
//修改日志文件存放路径文件名是%s.log | |||||
path := fmt.Sprintf(c.Path, c.Name) | |||||
f, err = os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777) | |||||
if err != nil { | |||||
os.RemoveAll(c.Path) | |||||
if f, err = os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777); err != nil { | |||||
return err | |||||
} | |||||
} | |||||
logger := log.NewSimpleLogger(f) | |||||
logger.ShowSQL(true) | |||||
DataDb.SetLogger(logger) | |||||
} | |||||
return nil | |||||
} |
@@ -28,6 +28,17 @@ func CityGetOne(key string) (*model.City, error) { | |||||
return &City, nil | return &City, nil | ||||
} | } | ||||
func CityGetOneByName(name string) (*model.City, error) { | |||||
var City model.City | |||||
if has, err := Db.Where("name LIKE ?", "%"+name+"%").Get(&City); err != nil || has == false { | |||||
if has == false { | |||||
return &City, nil | |||||
} | |||||
return nil, logx.Error(err) | |||||
} | |||||
return &City, nil | |||||
} | |||||
//单条记录获取DB | //单条记录获取DB | ||||
func CityGetWithDb(HKey string) string { | func CityGetWithDb(HKey string) string { | ||||
cacheKey := md.OfficialCityCacheKey | cacheKey := md.OfficialCityCacheKey | ||||
@@ -0,0 +1,117 @@ | |||||
package db | |||||
import ( | |||||
"applet/app/db/model" | |||||
"applet/app/utils" | |||||
"applet/app/utils/logx" | |||||
"errors" | |||||
"fmt" | |||||
"reflect" | |||||
"xorm.io/xorm" | |||||
) | |||||
// BatchSelectMasterAreaVisitsFlows 批量查询数据 TODO::和下面的方法重复了,建议采用下面的 `MasterAreaVisitsFlowsFindByParams` 方法 | |||||
func BatchSelectMasterAreaVisitsFlows(Db *xorm.Engine, params map[string]interface{}) (*[]model.MasterAreaVisitsFlows, error) { | |||||
var MasterAreaVisitsFlowsData []model.MasterAreaVisitsFlows | |||||
if err := Db.In(utils.AnyToString(params["key"]), params["value"]). | |||||
Find(&MasterAreaVisitsFlowsData); err != nil { | |||||
return nil, logx.Warn(err) | |||||
} | |||||
return &MasterAreaVisitsFlowsData, nil | |||||
} | |||||
// MasterAreaVisitsFlowsInsert 插入单条数据 | |||||
func MasterAreaVisitsFlowsInsert(Db *xorm.Engine, MasterAreaVisitsFlows *model.MasterAreaVisitsFlows) (int, error) { | |||||
_, err := Db.InsertOne(MasterAreaVisitsFlows) | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return MasterAreaVisitsFlows.Id, nil | |||||
} | |||||
// BatchAddMasterAreaVisitsFlowss 批量新增数据 | |||||
func BatchAddMasterAreaVisitsFlowss(Db *xorm.Engine, MasterAreaVisitsFlowsData []*model.MasterAreaVisitsFlows) (int64, error) { | |||||
affected, err := Db.Insert(MasterAreaVisitsFlowsData) | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return affected, nil | |||||
} | |||||
func GetMasterAreaVisitsFlowsCount(Db *xorm.Engine) int { | |||||
var MasterAreaVisitsFlows model.MasterAreaVisitsFlows | |||||
session := Db.Where("") | |||||
count, err := session.Count(&MasterAreaVisitsFlows) | |||||
if err != nil { | |||||
return 0 | |||||
} | |||||
return int(count) | |||||
} | |||||
// MasterAreaVisitsFlowsDelete 删除记录 | |||||
func MasterAreaVisitsFlowsDelete(Db *xorm.Engine, id interface{}) (int64, error) { | |||||
if reflect.TypeOf(id).Kind() == reflect.Slice { | |||||
return Db.In("id", id).Delete(model.MasterAreaVisitsFlows{}) | |||||
} else { | |||||
return Db.Where("id = ?", id).Delete(model.MasterAreaVisitsFlows{}) | |||||
} | |||||
} | |||||
// MasterAreaVisitsFlowsUpdate 更新记录 | |||||
func MasterAreaVisitsFlowsUpdate(Db *xorm.Engine, id interface{}, MasterAreaVisitsFlows *model.MasterAreaVisitsFlows, forceColums ...string) (int64, error) { | |||||
var ( | |||||
affected int64 | |||||
err error | |||||
) | |||||
if forceColums != nil { | |||||
affected, err = Db.Where("id=?", id).Cols(forceColums...).Update(MasterAreaVisitsFlows) | |||||
} else { | |||||
affected, err = Db.Where("id=?", id).Update(MasterAreaVisitsFlows) | |||||
} | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return affected, nil | |||||
} | |||||
// MasterAreaVisitsFlowsGetOneByParams 通过传入的参数查询数据(单条) | |||||
func MasterAreaVisitsFlowsGetOneByParams(Db *xorm.Engine, params map[string]interface{}) (*model.MasterAreaVisitsFlows, error) { | |||||
var m model.MasterAreaVisitsFlows | |||||
var query = fmt.Sprintf("%s =?", params["key"]) | |||||
if has, err := Db.Where(query, params["value"]).Get(&m); err != nil || has == false { | |||||
return nil, logx.Error(err) | |||||
} | |||||
return &m, nil | |||||
} | |||||
// MasterAreaVisitsFlowsFindByParams 通过传入的参数查询数据(多条) | |||||
func MasterAreaVisitsFlowsFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.MasterAreaVisitsFlows, error) { | |||||
var m []model.MasterAreaVisitsFlows | |||||
if params["value"] == nil { | |||||
return nil, errors.New("参数有误") | |||||
} | |||||
if params["key"] == nil { | |||||
//查询全部数据 | |||||
err := Db.Find(&m) | |||||
if err != nil { | |||||
return nil, logx.Error(err) | |||||
} | |||||
return &m, nil | |||||
} else { | |||||
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice { | |||||
//指定In查询 | |||||
if err := Db.In(utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil { | |||||
return nil, logx.Warn(err) | |||||
} | |||||
return &m, nil | |||||
} else { | |||||
var query = fmt.Sprintf("%s =?", params["key"]) | |||||
err := Db.Where(query, params["value"]).Find(&m) | |||||
if err != nil { | |||||
return nil, logx.Error(err) | |||||
} | |||||
return &m, nil | |||||
} | |||||
} | |||||
} |
@@ -28,6 +28,18 @@ func ProvinceGetOne(key string) (*model.Province, error) { | |||||
return &province, nil | return &province, nil | ||||
} | } | ||||
func ProvinceGetOneByName(name string) (*model.Province, error) { | |||||
var province model.Province | |||||
if has, err := Db.Where("name LIKE ?", "%"+name+"%").Get(&province); err != nil || has == false { | |||||
if has == false { | |||||
return &province, nil | |||||
} | |||||
return nil, logx.Error(err) | |||||
} | |||||
return &province, nil | |||||
} | |||||
//单条记录获取DB | //单条记录获取DB | ||||
func ProvinceGetWithDb(HKey string) string { | func ProvinceGetWithDb(HKey string) string { | ||||
cacheKey := md.OfficialProvinceCacheKey | cacheKey := md.OfficialProvinceCacheKey | ||||
@@ -0,0 +1,17 @@ | |||||
package model | |||||
import "time" | |||||
type MasterAreaVisitsFlows struct { | |||||
Id int `json:"id"` | |||||
Ip string `json:"ip"` | |||||
MasterId int `json:"master_id"` | |||||
Date string `json:"date"` | |||||
CountryName string `json:"country_name"` | |||||
ProvinceName string `json:"province_name"` | |||||
ProvinceId string `json:"province_id"` | |||||
CityName string `json:"city_name"` | |||||
CityId string `json:"city_id"` | |||||
CreateAt time.Time `json:"create_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` | |||||
UpdateAt time.Time `json:"update_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` | |||||
} |
@@ -25,6 +25,11 @@ func init() { | |||||
if err := db.InitDB(&baseDb); err != nil { | if err := db.InitDB(&baseDb); err != nil { | ||||
panic(err) | panic(err) | ||||
} | } | ||||
dataDb := *cfg.DataDB | |||||
dataDb.Path = fmt.Sprintf(cfg.DataDB.Path, cfg.DataDB.Name) | |||||
if err := db.InitDataDB(&dataDb); err != nil { | |||||
panic(err) | |||||
} | |||||
utils.CurlDebug = true | utils.CurlDebug = true | ||||
//cfg.InitMemCache() | //cfg.InitMemCache() | ||||
} | } | ||||
@@ -19,6 +19,7 @@ func Init() { | |||||
func initConsumes() { | func initConsumes() { | ||||
jobs[consumeMd.CanalOrderConsumeFunName] = CanalOrderConsume | jobs[consumeMd.CanalOrderConsumeFunName] = CanalOrderConsume | ||||
jobs[consumeMd.CanalGuideOrderConsumeFunName] = CanalGuideOrderConsume | jobs[consumeMd.CanalGuideOrderConsumeFunName] = CanalGuideOrderConsume | ||||
jobs[consumeMd.ZhiOsUserVisitIpAddressConsumeFunName] = ZhiOsUserVisitIpAddressConsume | |||||
} | } | ||||
func Run() { | func Run() { | ||||
@@ -29,9 +29,19 @@ var RabbitMqQueueKeyList = []*MqQueue{ | |||||
BindKey: "", | BindKey: "", | ||||
ConsumeFunName: "CanalGuideOrderConsume", | ConsumeFunName: "CanalGuideOrderConsume", | ||||
}, | }, | ||||
{ | |||||
ExchangeName: "zhios.app.user.visit.ip.address.exchange", | |||||
Name: "zhios_user_visit_ip_address_queue", | |||||
Type: FanOutQueueType, | |||||
IsPersistent: false, | |||||
RoutKey: "queue_one", | |||||
BindKey: "", | |||||
ConsumeFunName: "ZhiOsUserVisitIpAddressConsume", | |||||
}, | |||||
} | } | ||||
const ( | const ( | ||||
CanalOrderConsumeFunName = "CanalOrderConsume" | |||||
CanalGuideOrderConsumeFunName = "CanalGuideOrderConsume" | |||||
CanalOrderConsumeFunName = "CanalOrderConsume" | |||||
CanalGuideOrderConsumeFunName = "CanalGuideOrderConsume" | |||||
ZhiOsUserVisitIpAddressConsumeFunName = "ZhiOsUserVisitIpAddressConsume" | |||||
) | ) |
@@ -0,0 +1,12 @@ | |||||
package md | |||||
type ZhiOsUserVisitIpAddressMessage struct { | |||||
Country string `json:"country"` | |||||
Province string `json:"province"` | |||||
City string `json:"city"` | |||||
Ip string `json:"ip"` | |||||
MasterId string `json:"master_id"` | |||||
} | |||||
const ZhiOsUserVisitIpAddressHashMapCacheKey = "zhiOs_user_visit_ip_address_hash_map_cache:%s:%s" //访问ip缓存hashMap键zhiOs_user_visit_ip_address_hash_map_cache:masterId:date | |||||
const ZhiOsUserVisitIpAddressHashMapCacheTime = 60 * 60 * 24 //1天 |
@@ -7,6 +7,7 @@ const ( | |||||
BroadQueueType = "BroadQueue" | BroadQueueType = "BroadQueue" | ||||
DirectQueueType = "DirectQueue" | DirectQueueType = "DirectQueue" | ||||
TopicQueueType = "TopicQueue" | TopicQueueType = "TopicQueue" | ||||
FanOutQueueType = "FanOutQueue" | |||||
) | ) | ||||
type MsgClient struct { | type MsgClient struct { | ||||
@@ -0,0 +1,123 @@ | |||||
package consume | |||||
import ( | |||||
"applet/app/db" | |||||
"applet/app/db/model" | |||||
"applet/app/utils" | |||||
"applet/app/utils/cache" | |||||
"applet/app/utils/logx" | |||||
"applet/consume/md" | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit" | |||||
"encoding/json" | |||||
"errors" | |||||
"fmt" | |||||
"github.com/streadway/amqp" | |||||
"time" | |||||
"xorm.io/xorm" | |||||
) | |||||
func ZhiOsUserVisitIpAddressConsume(queue md.MqQueue) { | |||||
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>") | |||||
ch, err := rabbit.Cfg.Pool.GetChannel() | |||||
if err != nil { | |||||
logx.Error(err) | |||||
return | |||||
} | |||||
defer ch.Release() | |||||
//1、将自己绑定到交换机上 | |||||
ch.Bind(queue.Name, queue.ExchangeName, queue.RoutKey) | |||||
//2、取出数据进行消费 | |||||
ch.Qos(1) | |||||
delivery := ch.Consume(queue.Name) | |||||
var res amqp.Delivery | |||||
var ok bool | |||||
for { | |||||
res, ok = <-delivery | |||||
if ok == true { | |||||
//fmt.Println(string(res.Body)) | |||||
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") | |||||
err = handleUserVisitIpAddress(res.Body) | |||||
//_ = res.Reject(false) | |||||
_ = res.Ack(true) | |||||
} else { | |||||
panic(errors.New("error getting message")) | |||||
} | |||||
} | |||||
fmt.Println("get msg done") | |||||
} | |||||
func handleUserVisitIpAddress(msg []byte) error { | |||||
now := time.Now() | |||||
today := now.Format("2006-01-02") | |||||
var tmpString string | |||||
err := json.Unmarshal(msg, &tmpString) | |||||
if err != nil { | |||||
fmt.Println(err.Error()) | |||||
return err | |||||
} | |||||
var msgStruct md.ZhiOsUserVisitIpAddressMessage | |||||
err = json.Unmarshal([]byte(tmpString), &msgStruct) | |||||
if err != nil { | |||||
fmt.Println(err.Error()) | |||||
return err | |||||
} | |||||
//1、判断ip是否已统计 | |||||
cacheKey := fmt.Sprintf(md.ZhiOsUserVisitIpAddressHashMapCacheKey, msgStruct.MasterId, today) | |||||
get, _ := cache.HGetString(cacheKey, msgStruct.Ip) | |||||
if get == "" { | |||||
//2、分析ip归属地 | |||||
countryName, provinceId, cityId, provinceName, cityName := getIpAddress(db.DBs[msgStruct.MasterId], msgStruct) | |||||
if provinceId != "" || cityId != "" || countryName != "" || provinceName != "" || cityName != "" { | |||||
//3、插入`master_area_visits_flows` 表 | |||||
if provinceName == "" { | |||||
provinceName = msgStruct.Province | |||||
} | |||||
if cityName == "" { | |||||
cityName = msgStruct.City | |||||
} | |||||
db.MasterAreaVisitsFlowsInsert(db.DataDb, &model.MasterAreaVisitsFlows{ | |||||
Ip: msgStruct.Ip, | |||||
MasterId: utils.StrToInt(msgStruct.MasterId), | |||||
Date: today, | |||||
CountryName: countryName, | |||||
ProvinceName: provinceName, | |||||
ProvinceId: provinceId, | |||||
CityName: cityName, | |||||
CityId: cityId, | |||||
CreateAt: now, | |||||
UpdateAt: now, | |||||
}) | |||||
} | |||||
//4、加入到缓存map中 | |||||
cache.HSet(cacheKey, msgStruct.Ip, msgStruct.MasterId) | |||||
cache.Expire(cacheKey, md.ZhiOsUserVisitIpAddressHashMapCacheTime) | |||||
} | |||||
return nil | |||||
} | |||||
func getIpAddress(Db *xorm.Engine, message md.ZhiOsUserVisitIpAddressMessage) (countryName, provinceId, cityId, provinceName, cityName string) { | |||||
countryName = message.Country | |||||
if countryName == "中国" && message.Province != "" { | |||||
if message.Province == "闽" { | |||||
message.Province = "福建" | |||||
} | |||||
province, err := db.ProvinceGetOneByName(message.Province) | |||||
if err != nil { | |||||
return "", "", "", "", "" | |||||
} | |||||
provinceId = province.Id | |||||
provinceName = province.Name | |||||
if message.City != "" { | |||||
city, err := db.CityGetOneByName(message.City) | |||||
if err != nil { | |||||
return "", "", "", "", "" | |||||
} | |||||
cityId = city.Id | |||||
cityName = city.Name | |||||
} | |||||
} | |||||
return | |||||
} |
@@ -39,6 +39,18 @@ db: | |||||
max_idle_conns: 100 | max_idle_conns: 100 | ||||
path: 'tmp/%s.log' | path: 'tmp/%s.log' | ||||
# 连接 big_data_screen 数据库 | |||||
data_db: | |||||
host: '119.23.182.117:3306' | |||||
name: 'big_data_screen' | |||||
user: 'root' | |||||
psw: 'Fnuo123com@' | |||||
show_log: true | |||||
max_lifetime: 30 | |||||
max_open_conns: 100 | |||||
max_idle_conns: 100 | |||||
path: 'tmp/%s.log' | |||||
# 日志 | # 日志 | ||||
log: | log: | ||||
app_name: 'applet' | app_name: 'applet' | ||||
@@ -23,6 +23,9 @@ func init() { | |||||
if err := db.InitDB(cfg.DB); err != nil { //主数据库初始化 | if err := db.InitDB(cfg.DB); err != nil { //主数据库初始化 | ||||
panic(err) | panic(err) | ||||
} | } | ||||
if err := db.InitDataDB(cfg.DataDB); err != nil { //数据大屏本身库初始化 | |||||
panic(err) | |||||
} | |||||
channel := make(chan int, 0) //开辟管道,缓冲为 | channel := make(chan int, 0) //开辟管道,缓冲为 | ||||
go db.InitDBs(channel) | go db.InitDBs(channel) | ||||
<-channel | <-channel | ||||