package util import ( "crypto/md5" cryptoRand "crypto/rand" "encoding/hex" "encoding/json" "encoding/xml" "fmt" bson "gopkg.in/mgo.v2/bson" "io" "log" "math" "math/big" mathRand "math/rand" "net/url" "reflect" "regexp" "runtime" "sort" "strconv" "strings" "time" "github.com/dchest/captcha" ) const ( tmp = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678900" ) //短地址加密 func EncodeArticleId(keys ...string) string { kstr := strings.Join(keys, ",") return SE.EncodeString(kstr) } //短地址解密 func DecodeArticleId(id string) []string { return strings.Split(SE.DecodeString(id), ",") } //短地址加密,二次加密带校验和 func EncodeArticleId2ByCheck(keys ...string) string { kstr := strings.Join(keys, ",") kstr = SE.EncodeStringByCheck(kstr) return url.QueryEscape("ABC" + SE2.EncodeStringByCheck(kstr)) } //短地址解密,二次解密带校验和 func DecodeArticleId2ByCheck(id string) []string { if !strings.Contains(id, "+") { //新加密算法解密 id, _ = url.QueryUnescape(id) } if id[:3] == "ABC" { //前三位为ABC是新加密数据 kstr := SE2.DecodeStringByCheck(id[3:]) return strings.Split(SE.DecodeStringByCheck(kstr), ",") } else { //历史数据 rep := DecodeArticleId(id) oldpushid := "58f87a9561a0721f157bc74d" //剑鱼1.9发版前最后一次推送信息id if rep[0] > oldpushid { return []string{""} } else { return rep } } } func Uuid(length int) string { ret := []string{} r := mathRand.New(mathRand.NewSource(time.Now().UnixNano())) for i := 0; i < length; i++ { index := r.Intn(62) ret = append(ret, tmp[index:index+1]) } return strings.Join(ret, "") } //计算字符串和值 func Sumstring(code string) (sum int) { tmp := []rune(code) for _, v := range tmp { sum = sum + int(v) } return } //获取随机数 func GetRandom(n int) string { var idChars = []byte("0123456789") b := captcha.RandomDigits(n) for i, c := range b { b[i] = idChars[c] } return string(b) } //获取复杂的随机数 func GetLetterRandom(length int, flag ...bool) string { var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") var mod byte = 52 if len(flag) > 0 && flag[0] { idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ") mod = 26 } b := make([]byte, length) maxrb := byte(256 - (256 % int(mod))) i := 0 EXIT: for { r := make([]byte, length+(length/4)) if _, err := io.ReadFull(cryptoRand.Reader, r); err != nil { panic("captcha: error reading random source: " + err.Error()) } for _, c := range r { if c > maxrb { continue } b[i] = c % mod i++ if i == length { break EXIT } } } for i, c := range b { b[i] = idChars[c] } return string(b) } /*获取复杂的随机数,数字和字母的组合 * c > 2 数字的个数和字母的个数随机分配 * n 数字的个数 * l 字母的个数 */ func GetComplexRandom(c, n, l int) string { if c < 2 && (n < 1 || l < 1) { return "--" } r := mathRand.New(mathRand.NewSource(time.Now().UnixNano())) myCommonMethod := func(flag bool) int { if flag { return r.Intn(c-1) + 1 } else { return r.Intn(c) } } if c >= 2 { n = myCommonMethod(true) l = c - n } else { c = l + n } value := GetRandom(n) + GetLetterRandom(l) var array = strings.Split(value, "") for i := 0; i < c/2; i++ { r1 := myCommonMethod(false) r2 := myCommonMethod(false) o := array[r1] array[r1] = array[r2] array[r2] = o } return strings.Join(array, "") } /*隐藏部分账号 *返回手机号:150...70765 邮箱:...shenjun@vip.qq.com */ func EncryCode(value string) string { if len(value) == 0 { return value } else if strings.Contains(value, "@") { start := strings.Index(value, "@") / 2 if start == 0 { start++ } value = "...." + string(value[start:]) } else { value = string(value[0:3]) + "..." + string(value[len(value)-4:]) } return value } //生成32位md5字串 func GetMd5String(s string) string { h := md5.New() h.Write([]byte(s)) return hex.EncodeToString(h.Sum(nil)) } //obj(string,M)转M,查询用到 func ObjToMap(obj interface{}) *map[string]interface{} { data := make(map[string]interface{}) if s, ok := obj.(string); ok { json.Unmarshal([]byte(strings.Replace(s, "'", "\"", -1)), &data) } else if s1, ok1 := obj.(map[string]interface{}); ok1 { data = s1 } else if s1, ok1 := obj.(*map[string]interface{}); ok1 { return s1 } else { data = nil } return &data } /*UTC类型时间转字符串 *flag==true,日期格式yyyy-mm-dd hh:mm:ss *flag==false,日期格式yyyy-mm-dd */ func LongToDate(date interface{}, flag bool) string { var int64Date int64 if l1, ok1 := date.(float64); ok1 { int64Date = int64(l1) } else if l2, ok2 := date.(int64); ok2 { int64Date = l2 } else if l3, ok3 := date.(int); ok3 { int64Date = int64(l3) } t := time.Unix(int64Date, 0) if flag { return t.Format("2006-01-02 15:04:05") } else { return t.Format("2006-01-02") } } func IntAll(num interface{}) int { return IntAllDef(num, 0) } func Int64All(num interface{}) int64 { if i, ok := num.(int64); ok { return int64(i) } else if i0, ok0 := num.(int32); ok0 { return int64(i0) } else if i1, ok1 := num.(float64); ok1 { return int64(i1) } else if i2, ok2 := num.(int); ok2 { return int64(i2) } else if i3, ok3 := num.(float32); ok3 { return int64(i3) } else if i4, ok4 := num.(string); ok4 { i64, _ := strconv.ParseInt(i4, 10, 64) //in, _ := strconv.Atoi(i4) return i64 } else if i5, ok5 := num.(int16); ok5 { return int64(i5) } else if i6, ok6 := num.(int8); ok6 { return int64(i6) } else if i7, ok7 := num.(*big.Int); ok7 { in, _ := strconv.ParseInt(fmt.Sprint(i7), 10, 64) return int64(in) } else if i8, ok8 := num.(*big.Float); ok8 { in, _ := strconv.ParseInt(fmt.Sprint(i8), 10, 64) return int64(in) } else { return 0 } } func Float64All(num interface{}) float64 { if i, ok := num.(float64); ok { return float64(i) } else if i0, ok0 := num.(int32); ok0 { return float64(i0) } else if i1, ok1 := num.(int64); ok1 { return float64(i1) } else if i2, ok2 := num.(int); ok2 { return float64(i2) } else if i3, ok3 := num.(float32); ok3 { return float64(i3) } else if i4, ok4 := num.(string); ok4 { in, _ := strconv.ParseFloat(i4, 64) return in } else if i5, ok5 := num.(int16); ok5 { return float64(i5) } else if i6, ok6 := num.(int8); ok6 { return float64(i6) } else if i6, ok6 := num.(uint); ok6 { return float64(i6) } else if i6, ok6 := num.(uint8); ok6 { return float64(i6) } else if i6, ok6 := num.(uint16); ok6 { return float64(i6) } else if i6, ok6 := num.(uint32); ok6 { return float64(i6) } else if i6, ok6 := num.(uint64); ok6 { return float64(i6) } else if i7, ok7 := num.(*big.Float); ok7 { in, _ := strconv.ParseFloat(fmt.Sprint(i7), 64) return float64(in) } else if i8, ok8 := num.(*big.Int); ok8 { in, _ := strconv.ParseFloat(fmt.Sprint(i8), 64) return float64(in) } else { return 0 } } func IntAllDef(num interface{}, defaultNum int) int { if i, ok := num.(int); ok { return int(i) } else if i0, ok0 := num.(int32); ok0 { return int(i0) } else if i1, ok1 := num.(float64); ok1 { return int(i1) } else if i2, ok2 := num.(int64); ok2 { return int(i2) } else if i3, ok3 := num.(float32); ok3 { return int(i3) } else if i4, ok4 := num.(string); ok4 { in, _ := strconv.Atoi(i4) return int(in) } else if i5, ok5 := num.(int16); ok5 { return int(i5) } else if i6, ok6 := num.(int8); ok6 { return int(i6) } else if i7, ok7 := num.(*big.Int); ok7 { in, _ := strconv.Atoi(fmt.Sprint(i7)) return int(in) } else if i8, ok8 := num.(*big.Float); ok8 { in, _ := strconv.Atoi(fmt.Sprint(i8)) return int(in) } else { return defaultNum } } func ObjToString(old interface{}) string { if nil == old { return "" } else { r, _ := old.(string) return r } } func ObjToStringDef(old interface{}, defaultstr string) string { if nil == old { return defaultstr } else { r, _ := old.(string) if r == "" { return defaultstr } return r } } //对象数组转成string数组 func ObjArrToStringArr(old []interface{}) []string { if old != nil { new := make([]string, len(old)) for i, v := range old { new[i] = v.(string) } return new } else { return nil } } //对象数组转成map数组 func ObjArrToMapArr(old []interface{}) []map[string]interface{} { if old != nil { new := make([]map[string]interface{}, len(old)) for i, v := range old { new[i] = v.(map[string]interface{}) } return new } else { return nil } } //map数组转成对象数组 func MapArrToObjArr(old []map[string]interface{}) []interface{} { if old != nil { new := make([]interface{}, len(old)) for i, v := range old { new[i] = v } return new } else { return nil } } func SubstrByByte(str string, length int) string { bs := []byte(str)[:length] bl := 0 for i := len(bs) - 1; i >= 0; i-- { switch { case bs[i] >= 0 && bs[i] <= 127: return string(bs[:i+1]) case bs[i] >= 128 && bs[i] <= 191: bl++ case bs[i] >= 192 && bs[i] <= 253: cl := 0 switch { case bs[i]&252 == 252: cl = 6 case bs[i]&248 == 248: cl = 5 case bs[i]&240 == 240: cl = 4 case bs[i]&224 == 224: cl = 3 default: cl = 2 } if bl+1 == cl { return string(bs[:i+cl]) } return string(bs[:i]) } } return "" } func SubString(str string, begin, length int) (substr string) { // 将字符串的转换成[]rune rs := []rune(str) lth := len(rs) // 简单的越界判断 if begin < 0 { begin = 0 } if begin >= lth { begin = lth } end := begin + length if end > lth { end = lth } // 返回子串 return string(rs[begin:end]) } //捕获异常 func Try(fun func(), handler func(interface{})) { defer func() { if err := recover(); err != nil { for skip := 1; ; skip++ { _, file, line, ok := runtime.Caller(skip) if !ok { break } go log.Printf("%v,%v\n", file, line) } handler(err) } }() fun() } //3目运算 func If(b bool, to, fo interface{}) interface{} { if b { return to } else { return fo } } //HashCode值 func HashCode(uid string) int { var h uint32 = 0 rs := []rune(uid) for i := 0; i < len(rs); i++ { h = 31*h + uint32(rs[i]) } return int(h) } //获取离n天的秒差 func GetDayStartSecond(n int) int64 { now := time.Now() tom := time.Date(now.Year(), now.Month(), now.Day()+n, 0, 0, 0, 0, time.Local) return tom.Unix() } func InterfaceArrTointArr(arr []interface{}) []int { tmp := make([]int, 0) for _, v := range arr { tmp = append(tmp, int(v.(float64))) } return tmp } func InterfaceArrToint64Arr(arr []interface{}) []int64 { tmp := make([]int64, 0) for _, v := range arr { tmp = append(tmp, int64(v.(float64))) } return tmp } //根据bsonID转string func BsonIdToSId(uid interface{}) string { if uid == nil { return "" } else if u, ok := uid.(string); ok { return u } else { return fmt.Sprintf("%x", string(uid.(bson.ObjectId))) } } func StringTOBsonId(id string) (bid bson.ObjectId) { defer Catch() if id != "" { bid = bson.ObjectIdHex(id) } return } func GetSubDay(t1 int64) int { tt1 := time.Unix(t1, 0) tt2 := time.Now() nt1 := time.Date(tt1.Year(), tt1.Month(), tt1.Day(), 0, 0, 0, 0, time.Local) nt2 := time.Date(tt2.Year(), tt2.Month(), tt2.Day(), 0, 0, 0, 0, time.Local) return int((nt1.Unix() - nt2.Unix()) / 86400) } func StartWith(value, str string) bool { ok, _ := regexp.MatchString("^"+str, value) return ok } func EndWith(value, str string) bool { ok, _ := regexp.MatchString(str+"$", value) return ok } //出错拦截 func Catch() { if r := recover(); r != nil { log.Println(r) for skip := 0; ; skip++ { _, file, line, ok := runtime.Caller(skip) if !ok { break } go log.Printf("%v,%v\n", file, line) } } } func ConvertFileSize(s int) string { size := float64(s) var kb float64 = 1024 var mb float64 = kb * 1024 var gb float64 = mb * 1024 if size >= gb { return fmt.Sprintf("%.1f GB", float64(size/gb)) } else if size >= mb { f := float64(size / mb) if f > 100 { return fmt.Sprintf("%.0f MB", f) } return fmt.Sprintf("%.1f MB", f) } else if size >= kb { f := float64(size / kb) if f > 100 { return fmt.Sprintf("%.0f KB", f) } return fmt.Sprintf("%.1f KB", f) } return fmt.Sprintf("%d B", s) } //MD5签名 func WxSign(format string, param ...interface{}) string { data := fmt.Sprintf(format, param...) h := md5.New() h.Write([]byte(data)) sign := strings.ToUpper(hex.EncodeToString(h.Sum(nil))) return sign } //计算时差 func TimeDiff(date time.Time) string { var date1 = date //开始时间 var date2 = time.Now() //结束时间 var date3 = date2.Unix() - date1.Unix() //时间差的毫秒数 //计算出相差天数 var days = math.Floor(float64(date3 / (24 * 3600))) //计算出小时数 var leave1 = date3 % (24 * 3600) //计算天数后剩余的毫秒数 var hours = math.Floor(float64(leave1 / (3600))) //计算相差分钟数 var leave2 = leave1 % (3600) //计算小时数后剩余的毫秒数 var minutes = math.Floor(float64(leave2 / (60))) //计算相差秒数 var td = "30秒前" if days > 0 { if days > 10 { if date1.Year() < date2.Year() { td = FormatDate(&date, Date_Short_Layout) } else { td = FormatDate(&date, Date_Small_Layout) } } else { td = fmt.Sprint(days) + "天前" } } else if hours > 0 { td = fmt.Sprint(hours) + "小时前" } else if minutes > 0 { td = fmt.Sprint(minutes) + "分钟前" } return td } func FloatFormat(tmp float64, n int) float64 { fs := fmt.Sprintf("%."+fmt.Sprint(n)+"f", tmp) f, _ := strconv.ParseFloat(fs, 64) return f } //生成微信支付的签名 func CreateWxSign(afterStr string, obj interface{}, filter ...string) string { filter = append(filter, "sign", "xml") keys := []string{} m := make(map[string]string) t := reflect.TypeOf(obj) v := reflect.ValueOf(obj) k := t.Kind() if t.Kind() == reflect.Ptr { t = t.Elem() k = t.Kind() v = v.Elem() } if k == reflect.Map { for _, key := range v.MapKeys() { keys = append(keys, key.String()) m[key.String()] = fmt.Sprint(v.MapIndex(key).Interface()) } } else if k == reflect.Struct { for n := 0; n < t.NumField(); n++ { tagName := t.Field(n).Tag.Get("xml") if tagName == "" { tagName = t.Field(n).Tag.Get("json") } if tagName == "" { tagName = t.Field(n).Name } keys = append(keys, tagName) m[tagName] = fmt.Sprint(v.Field(n)) } } sort.Strings(keys) vs := []string{} L: for _, v := range keys { for _, f := range filter { if f == v { continue L } } if strings.TrimSpace(m[v]) == "" { continue } vs = append(vs, fmt.Sprintf("%s=%s", v, m[v])) } return WxSign(strings.Join(vs, "&") + afterStr) } //简单的xml转map,只有一个层级,没有多层嵌套 func XmlToMap(input string) map[string]string { var t xml.Token var err error inputReader := strings.NewReader(input) decoder := xml.NewDecoder(inputReader) isStart := false nodeName := "" m := make(map[string]string) for t, err = decoder.Token(); err == nil; t, err = decoder.Token() { switch token := t.(type) { // 处理元素开始(标签) case xml.StartElement: isStart = true nodeName = token.Name.Local // 处理元素结束(标签) case xml.EndElement: isStart = false // 处理字符数据(这里就是元素的文本) case xml.CharData: if isStart { m[nodeName] = string([]byte(token)) } default: // ... } } return m } // DeepCopy //@Description map 深拷贝 // @Author J 2022/8/24 19:11 func DeepCopy(value interface{}) interface{} { if valueMap, ok := value.(map[string]interface{}); ok { newMap := make(map[string]interface{}) for k, v := range valueMap { newMap[k] = DeepCopy(v) } return newMap } else if valueSlice, ok := value.([]interface{}); ok { newSlice := make([]interface{}, len(valueSlice)) for k, v := range valueSlice { newSlice[k] = DeepCopy(v) } return newSlice } else if valueMap, ok := value.(bson.M); ok { newMap := make(bson.M) for k, v := range valueMap { newMap[k] = DeepCopy(v) } } return value } // 保留两位小数,舍弃尾数,无进位运算 // 主要逻辑就是先乘,trunc之后再除回去,就达到了保留N位小数的效果 func FormatFloat(num float64, decimal int) (float64, error) { // 默认乘1 d := float64(1) if decimal > 0 { // 10的N次方 d = math.Pow10(decimal) } // math.trunc作用就是返回浮点数的整数部分 // 再除回去,小数点后无效的0也就不存在了 res := strconv.FormatFloat(math.Trunc(num*d)/d, 'f', -1, 64) return strconv.ParseFloat(res, 64) } // 舍弃的尾数不为0,强制进位 func FormatFloatCeil(num float64, decimal int) (float64, error) { // 默认乘1 d := float64(1) if decimal > 0 { // 10的N次方 d = math.Pow10(decimal) } // math.trunc作用就是返回浮点数的整数部分 // 再除回去,小数点后无效的0也就不存在了 res := strconv.FormatFloat(math.Ceil(num*d)/d, 'f', -1, 64) return strconv.ParseFloat(res, 64) } // 强制舍弃尾数 func FormatFloatFloor(num float64, decimal int) (float64, error) { // 默认乘1 d := float64(1) if decimal > 0 { // 10的N次方 d = math.Pow10(decimal) } // math.trunc作用就是返回浮点数的整数部分 // 再除回去,小数点后无效的0也就不存在了 res := strconv.FormatFloat(math.Floor(num*d)/d, 'f', -1, 64) return strconv.ParseFloat(res, 64) }