service/bizcommon/util/util.go

422 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package util
import (
"crypto/md5"
"encoding/json"
"fmt"
"io"
"math"
"math/rand"
"reflect"
"service/api/message"
"service/library/logger"
"sort"
"strconv"
"strings"
"time"
"unsafe"
"github.com/olivere/elastic/v7"
"github.com/qiniu/qmgo"
)
func ToJson(v any) string {
str, err := json.Marshal(v)
if err != nil {
logger.Info("%v marsha failed, err: %v", v, err)
}
return string(str)
}
func StringToMd5(s string) string {
m := md5.New()
_, _ = io.WriteString(m, s)
return fmt.Sprintf("%x", m.Sum(nil))
}
// 将实体类结构体指针转为bson.M采用反射
func EntityToM(p any) qmgo.M {
set := qmgo.M{}
pType := reflect.TypeOf(p).Elem()
pVal := reflect.ValueOf(p).Elem()
for i := 0; i < pType.NumField(); i++ {
name := pType.Field(i).Tag.Get("bson")
if name != "" {
field := pVal.Field(i)
if name != "_id" && !field.IsNil() {
value := field.Elem().Interface()
set[name] = value
}
}
}
return set
}
func DeepEntityToM(p any) qmgo.M {
set := qmgo.M{}
pType := reflect.TypeOf(p).Elem()
pVal := reflect.ValueOf(p).Elem()
for i := 0; i < pType.NumField(); i++ {
name := pType.Field(i).Tag.Get("bson")
if name != "" {
field := pVal.Field(i)
if name != "_id" && !field.IsNil() {
AddFieldToM(field, name, set)
}
}
}
return set
}
func AddFieldToM(field reflect.Value, parentNodeName string, set qmgo.M) {
if IsTypeStructPtr(field.Type()) {
p := field.Interface()
pType := reflect.TypeOf(p).Elem()
pVal := reflect.ValueOf(p).Elem()
for i := 0; i < pType.NumField(); i++ {
name := pType.Field(i).Tag.Get("bson")
if name != "" {
field := pVal.Field(i)
if name != "_id" && !field.IsNil() {
AddFieldToM(field, parentNodeName+"."+name, set)
}
}
}
} else {
value := field.Elem().Interface()
set[parentNodeName] = value
}
}
func StringsContains(elems []string, v string) bool {
for _, s := range elems {
if s == v {
return true
}
}
return false
}
func Int64Contains(elems []int64, v int64) bool {
for _, s := range elems {
if s == v {
return true
}
}
return false
}
// 下划线转大写驼峰
func UderscoreToUpperCamelCase(s string) string {
s = strings.Replace(s, "_", " ", -1)
s = strings.Title(s)
return strings.Replace(s, " ", "", -1)
}
// 数组转sql数组 []int{1, 2, 3) --> 1,2,3
func Convert2SqlArr(a ...any) string {
return strings.Replace(strings.Trim(fmt.Sprint(a), "[]"), " ", ",", -1)
}
// 获取整点时间戳
func GetHourStartTimeStamp(t time.Time) int64 {
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
loc = time.FixedZone("CST", 8*3600)
}
timeStr := fmt.Sprintf("%02d-%02d-%02d %02d:00:00", t.Year(), t.Month(), t.Day(), t.Hour())
duetimecst, err := time.ParseInLocation("2006-1-2 15:04:05", timeStr, loc)
if err != nil {
logger.Error("parse error : %v", err)
}
return duetimecst.Unix()
}
// 获取30分时间戳
func GetHourHalfTimeStamp(t time.Time) int64 {
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
loc = time.FixedZone("CST", 8*3600)
}
timeStr := fmt.Sprintf("%02d-%02d-%02d %02d:30:00", t.Year(), t.Month(), t.Day(), t.Hour())
duetimecst, err := time.ParseInLocation("2006-1-2 15:04:05", timeStr, loc)
if err != nil {
logger.Error("parse error : %v", err)
}
return duetimecst.Unix()
}
// 获取整分时间戳
func GetMinuteStartTimeStamp(t time.Time) int64 {
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
loc = time.FixedZone("CST", 8*3600)
}
timeStr := fmt.Sprintf("%02d-%02d-%02d %02d:%02d:00", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
duetimecst, err := time.ParseInLocation("2006-1-2 15:04:05", timeStr, loc)
if err != nil {
logger.Error("parse error : %v", err)
}
return duetimecst.Unix()
}
// 获取今天0点
func GetTodayZeroTime() time.Time {
currentTime := time.Now()
zeroTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, currentTime.Location())
return zeroTime
}
// 获取0点时间戳
func GetDayStartTimeStamp(t time.Time) int64 {
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
loc = time.FixedZone("CST", 8*3600)
}
timeStr := fmt.Sprintf("%02d-%02d-%02d 00:00:00", t.Year(), t.Month(), t.Day())
duetimecst, err := time.ParseInLocation("2006-1-2 15:04:05", timeStr, loc)
if err != nil {
logger.Error("parse error : %v", err)
}
return duetimecst.Unix()
}
// 获取当日该时间时间戳
func GetTimestampAtThisMomentForTime(t time.Time, layout string) int64 {
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
loc = time.FixedZone("CST", 8*3600)
}
timeStr := fmt.Sprintf("%02d-%02d-%02d %s", t.Year(), t.Month(), t.Day(), layout)
duetimecst, err := time.ParseInLocation("2006-1-2 15:04:05", timeStr, loc)
if err != nil {
logger.Error("parse error : %v", err)
}
return duetimecst.Unix()
}
// 随机生成字符串
func RandomString(l int) string {
str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
bytes := []byte(str)
var result []byte = make([]byte, 0, l)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return BytesToString(result)
}
// BytesToString 0 拷贝转换 slice byte 为 string
func BytesToString(b []byte) (s string) {
_bptr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
_sptr := (*reflect.StringHeader)(unsafe.Pointer(&s))
_sptr.Data = _bptr.Data
_sptr.Len = _bptr.Len
return s
}
func UnescapeJsonStr(s string) string {
s = strings.ReplaceAll(s, "\\u003c", "<")
s = strings.ReplaceAll(s, "\\u003e", ">")
s = strings.ReplaceAll(s, "\\u0026", "&")
return s
}
func AbsInt64(x int64) int64 {
return int64(math.Abs(float64(x)))
}
func String2Int(s string) int {
n, _ := strconv.Atoi(s)
return n
}
func String2Int32(s string) int32 {
return int32(String2Int(s))
}
func String2Int64(s string) int64 {
return int64(String2Int(s))
}
func VerisonCompare(ver1 string, ver2 string) (bool, error) {
ver1SeqNos := strings.Split(ver1, ".")
ver2SeqNos := strings.Split(ver2, ".")
if len(ver1SeqNos) != len(ver2SeqNos) {
logger.Error("version format error")
return false, fmt.Errorf("version format error")
}
for i := range ver1SeqNos {
ver1SeqNo, err := strconv.Atoi(ver1SeqNos[i])
if err != nil {
logger.Error("ver1 version format error:%v", err)
return false, err
}
ver2SeqNo, err := strconv.Atoi(ver2SeqNos[i])
if err != nil {
logger.Error("ver2 version format error:%v", err)
return false, err
}
if ver1SeqNo > ver2SeqNo {
return true, nil
} else if ver1SeqNo < ver2SeqNo {
return false, nil
}
}
return false, nil
}
func RoundUp(num float64) int64 {
return int64(math.Ceil(num))
}
func SortParam(argList []*message.JsonParamEntry) string {
var argsortable message.JsonParamEntrySortable = argList
sort.Sort(argsortable)
args := make([]string, 0)
for _, arg := range argsortable {
args = append(args, fmt.Sprintf("%s=%v", arg.Name, arg.Value))
}
return strings.Join(args, "&")
}
func TransferInt64SliceIntoValueCountMap(s []int64) map[int64]int {
mp := make(map[int64]int)
for _, integer := range s {
mp[integer] = mp[integer] + 1
}
return mp
}
func IsInt64SliceEqualAsSet(s1 []int64, s2 []int64) bool {
if len(s1) != len(s2) {
return false
}
mp1 := TransferInt64SliceIntoValueCountMap(s1)
mp2 := TransferInt64SliceIntoValueCountMap(s2)
for _, integer := range s1 {
if mp1[integer] != mp2[integer] {
return false
}
}
return true
}
func InInt64Slice(slice []int64, item int64) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}
func InInt32Slice(slice []int32, item int32) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}
func InIntSlice(slice []int, item int) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}
func InStrSlice(slice []string, item string) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}
func GetLastLessOrEqualForInt64(arr []int64, target int64) int {
low, high := 0, len(arr)-1
result := -1
for low <= high {
mid := (low + high) / 2
if arr[mid] <= target {
result = mid // 记录当前找到的索引
low = mid + 1 // 继续在右半部分查找
} else {
high = mid - 1 // 目标值在左半部分,缩小搜索范围
}
}
return result
}
func GetLastLessOrEqualForFloat64(arr []float64, target float64) int {
low, high := 0, len(arr)-1
result := -1
for low <= high {
mid := (low + high) / 2
if arr[mid] <= target {
result = mid // 记录当前找到的索引
low = mid + 1 // 继续在右半部分查找
} else {
high = mid - 1 // 目标值在左半部分,缩小搜索范围
}
}
return result
}
type Int64Filter struct {
LowerBound *int64 `json:"lower_bound" bson:"lower_bound"`
UpperBound *int64 `json:"upper_bound" bson:"upper_bound"`
Scale float64 `json:"scale" bson:"scale"`
Decay float64 `json:"decay" bson:"decay"`
Weight float64 `json:"weight" bson:"weight"`
}
func CreateEsInt64RangeQuery(name string, filter *Int64Filter) *elastic.RangeQuery {
if filter == nil {
return nil
}
query := elastic.NewRangeQuery(name)
if filter.LowerBound != nil {
query.Gte(DerefInt64(filter.LowerBound))
}
if filter.UpperBound != nil {
query.Lte(DerefInt64(filter.UpperBound))
}
return query
}
func CreateGaussDecayFunction(name string, filter *Int64Filter, refFilter *Int64Filter) *elastic.GaussDecayFunction {
if filter == nil {
return nil
}
lb := DerefInt64(filter.LowerBound)
ub := DerefInt64(filter.UpperBound)
if filter.LowerBound == nil {
lb = DerefInt64(refFilter.LowerBound)
}
if filter.UpperBound == nil {
ub = DerefInt64(refFilter.UpperBound)
}
origin := float64(lb+ub) / 2
offset := float64(-lb+ub) / 2
return elastic.NewGaussDecayFunction().FieldName(name).Origin(origin).Offset(offset).Scale(refFilter.Scale).Decay(refFilter.Decay).Weight(refFilter.Weight)
}
func CreateKeywordScriptScoreFunction(name string, value string, weight float64) *elastic.ScriptFunction {
scriptStr := "doc['%s'].value == '%s' ? %f : %f"
script := elastic.NewScript(fmt.Sprintf(scriptStr, name, value, 1.0, 0.0))
return elastic.NewScriptFunction(script).Weight(weight)
}