Files
baseapi/utils/typeconv.go
2019-12-25 11:50:45 +08:00

541 lines
12 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 utils
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"math"
"net/url"
"reflect"
"strconv"
"strings"
"time"
"git.rosy.net.cn/baseapi"
"github.com/gazeboxu/mapstructure"
"github.com/gazeboxu/structs"
)
const MaxTimeSecond = 9573800254 // 正常最大的秒数
var (
DefaultTimeValue = Str2Time("1970-01-01 00:00:00")
ZeroTimeValue = time.Time{}
)
func UnmarshalUseNumber(data []byte, result interface{}) error {
err := TryUnmarshalUseNumber(data, result)
if err != nil {
baseapi.SugarLogger.Infof("decode data:%v, error:%v", string(data), err)
}
return err
}
func TryUnmarshalUseNumber(data []byte, result interface{}) error {
d := json.NewDecoder(bytes.NewReader(data))
d.UseNumber()
return d.Decode(result)
}
// 这个函数将解析json返回的map中的字段类型与structObj中的完全一样的
func Unmarshal2Map(data []byte, structObj interface{}) (resultMap map[string]interface{}, err error) {
if err = json.Unmarshal(data, structObj); err == nil {
if err = json.Unmarshal(data, &resultMap); err == nil {
m := Struct2MapByJson(structObj)
for k := range resultMap {
if value, ok := m[k]; ok {
resultMap[k] = value
} else {
delete(resultMap, k)
}
}
}
}
return resultMap, err
}
func MustMarshal(obj interface{}) []byte {
byteArr, err := json.Marshal(obj)
if err != nil {
panic(fmt.Sprintf("err when Marshal obj:%v with error:%v", obj, err))
}
return byteArr
}
func TryInterface2Int64(data interface{}) (num int64, err error) {
if data == nil {
return num, errors.New("data is nil")
}
if dataNumber, ok := data.(int64); ok {
return dataNumber, nil
}
if dataNumber, ok := data.(int); ok {
return int64(dataNumber), nil
}
if dataNumber, ok := data.(int32); ok {
return int64(dataNumber), nil
}
if dataNumber, ok := data.(int16); ok {
return int64(dataNumber), nil
}
if dataNumber, ok := data.(int8); ok {
return int64(dataNumber), nil
}
if dataNumber, ok := data.(json.Number); ok {
return dataNumber.Int64()
}
if str, ok := data.(string); ok {
return Str2Int64WithDefault(str, 0), nil
}
return 0, fmt.Errorf("data is not json.Number, it's %s, value:%v", reflect.TypeOf(data).String(), data)
}
func MustInterface2Int64(data interface{}) int64 {
retVal, err := TryInterface2Int64(data)
if err != nil {
panic(err.Error())
}
return retVal
}
func Interface2Int64WithDefault(data interface{}, defValue int64) int64 {
retVal, err := TryInterface2Int64(data)
if err != nil {
return defValue
}
return retVal
}
func ForceInterface2Int64(data interface{}) int64 {
if dataStr, ok := data.(string); ok {
return Str2Int64(dataStr)
}
return Interface2Int64WithDefault(data, 0)
}
func TryInterface2Float64(data interface{}) (num float64, err error) {
if data == nil {
return num, errors.New("data is nil")
}
if dataNumber, ok := data.(float64); ok {
return dataNumber, nil
}
if dataNumber, ok := data.(float32); ok {
return float64(dataNumber), nil
}
if dataNumber, ok := data.(json.Number); ok {
return dataNumber.Float64()
}
if str, ok := data.(string); ok {
return Str2Float64WithDefault(str, 0), nil
}
return 0, fmt.Errorf("data is not json.Number, it's %s, value:%v", reflect.TypeOf(data).String(), data)
}
func MustInterface2Float64(data interface{}) float64 {
retVal, err := TryInterface2Float64(data)
if err != nil {
panic(err.Error())
}
return retVal
}
func Interface2Float64WithDefault(data interface{}, defValue float64) (retVal float64) {
retVal, err := TryInterface2Float64(data)
if err != nil {
return defValue
}
return retVal
}
func Interface2String(data interface{}) string {
if data == nil {
return ""
}
return data.(string)
}
func Interface2Int64List(data interface{}) []int64 {
if data == nil {
return nil
}
list := data.([]interface{})
retVal := make([]int64, len(list))
for k, v := range list {
retVal[k] = MustInterface2Int64(v)
}
return retVal
}
func Interface2StringList(data interface{}) []string {
if data == nil {
return nil
}
list := data.([]interface{})
retVal := make([]string, len(list))
for k, v := range list {
retVal[k] = Interface2String(v)
}
return retVal
}
func Slice2MapSlice(data []interface{}) []map[string]interface{} {
retVal := make([]map[string]interface{}, len(data))
for k, v := range data {
retVal[k] = v.(map[string]interface{})
}
return retVal
}
func Slice2int64Slice(data []interface{}) []int64 {
retVal := make([]int64, len(data))
for k, v := range data {
retVal[k] = MustInterface2Int64(v)
}
return retVal
}
func Slice2StringSlice(data []interface{}) []string {
retVal := make([]string, len(data))
for k, v := range data {
retVal[k] = Interface2String(v)
}
return retVal
}
//
func Bool2String(value bool) string {
if value {
return "true"
}
return "false"
}
func Bool2Int(value bool) int {
if value {
return 1
}
return 0
}
func Str2Int64WithDefault(str string, defValue int64) int64 {
retVal, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return defValue
}
return retVal
}
func Str2Int64(str string) int64 {
retVal, err := strconv.ParseInt(str, 10, 64)
if err != nil {
baseapi.SugarLogger.Errorf("error when convert %s to int64", str)
}
return retVal
}
func Str2Float64WithDefault(str string, defValue float64) float64 {
retVal, err := strconv.ParseFloat(str, 64)
if err != nil {
retVal = defValue
}
return retVal
}
func Str2Float64(str string) float64 {
retVal, err := strconv.ParseFloat(str, 64)
if err != nil {
baseapi.SugarLogger.Errorf("error when convert %s to float64", str)
}
return retVal
}
func Int64ToStr(value int64) string {
return strconv.FormatInt(value, 10)
}
func Int64ToStrNoZero(value int64) string {
if value == 0 {
return ""
}
return strconv.FormatInt(value, 10)
}
func Int2Str(value int) string {
return strconv.Itoa(value)
}
func Float64TwoInt64(data float64) int64 {
return int64(math.Round(data))
}
func Float64ToStr(data float64) string {
return fmt.Sprint(data)
}
// timestamp is in second
func Timestamp2Str(timestamp int64) string {
return Time2Str(Timestamp2Time(timestamp))
}
// timestamp为秒或毫秒
func Timestamp2Time(timestamp int64) time.Time {
nsec := int64(0)
if timestamp > MaxTimeSecond { // 传成毫秒了
nsec = (timestamp % 1000) * 1000000
timestamp /= 1000
}
return time.Unix(timestamp, nsec)
}
func Time2Str(t time.Time) string {
return t.Format("2006-01-02 15:04:05")
}
func Time2TimeStr(t time.Time) string {
return t.Format("15:04:05")
}
func Time2Date(t time.Time) time.Time {
year, month, day := t.Date()
return time.Date(year, month, day, 0, 0, 0, 0, t.Location())
}
func Time2DateStr(t time.Time) string {
return t.Format("2006-01-02")
}
func Str2Time(timeStr string) time.Time {
retVal, err := TryStr2Time(timeStr)
if err != nil {
baseapi.SugarLogger.Errorf("time.ParseInLocation failed, timeStr:%v, error:%v", timeStr, err)
}
return retVal
}
func TryStr2Time(timeStr string) (time.Time, error) {
timeStr = strings.Replace(timeStr, "T", " ", 1)
if strings.Index(timeStr, " ") == -1 {
timeStr += " 00:00:00"
}
maxTimeStrLen := len("2018-05-03 09:18:40")
if len(timeStr) > maxTimeStrLen {
timeStr = timeStr[:maxTimeStrLen]
}
return time.ParseInLocation("2006-1-2 15:4:5", timeStr, time.Local)
}
func Str2TimeWithDefault(timeStr string, defValue time.Time) time.Time {
retVal, err := TryStr2Time(timeStr)
if err != nil {
return defValue
}
return retVal
}
func IsTimeZero(timeValue time.Time) bool {
return timeValue == DefaultTimeValue || timeValue == ZeroTimeValue
}
func IsPtrTimeZero(timePtr *time.Time) bool {
return timePtr == nil || *timePtr == DefaultTimeValue || *timePtr == ZeroTimeValue
}
func HTTPBody2Values(data []byte, needDecode bool) (url.Values, error) {
bodyStr := string(data)
if needDecode {
bodyStr1, err := url.QueryUnescape(bodyStr)
if err != nil {
baseapi.SugarLogger.Errorf("QueryUnescape error:%v, bodyStr:%v", err, bodyStr)
return nil, err
}
bodyStr = bodyStr1
}
result, err := url.ParseQuery(bodyStr)
if err != nil {
baseapi.SugarLogger.Errorf("ParseQuery error:%v, bodyStr:%v", err, bodyStr)
return nil, err
}
return result, nil
}
func Params2Map(key1, value1 interface{}, kv ...interface{}) (retVal map[string]interface{}) {
retVal = make(map[string]interface{})
retVal[key1.(string)] = value1
key := ""
for index, v := range kv {
if index%2 == 0 {
key = v.(string)
} else {
retVal[key] = v
}
}
return retVal
}
func URLValues2Map(values url.Values) (retVal map[string]interface{}) {
retVal = make(map[string]interface{})
for k := range values {
retVal[k], _ = url.QueryUnescape(values.Get(k))
}
return retVal
}
func Map2URLValues(mapData map[string]interface{}) (retVal url.Values) {
retVal = make(url.Values)
for k, v := range mapData {
retVal.Set(k, fmt.Sprint(v))
}
return retVal
}
func MapKV2List(mapData map[string]interface{}) []map[string]interface{} {
retVal := make([]map[string]interface{}, len(mapData))
index := 0
for _, v := range mapData {
retVal[index] = v.(map[string]interface{})
index++
}
return retVal
}
func MapKeys(mapData map[string]interface{}) (keys []string) {
for k := range mapData {
keys = append(keys, k)
}
return keys
}
func Format4Output(obj interface{}, isSingleLine bool) (retVal string) {
retVal, ok := obj.(string)
if !ok {
var (
result []byte
err error
)
if isSingleLine {
if result, err = json.Marshal(obj); err == nil {
retVal = string(result)
}
} else {
if result, err = json.MarshalIndent(obj, "", "\t"); err == nil {
retVal = string(result)
}
}
if err != nil {
baseapi.SugarLogger.Infof("Format4Output Marshal:%v failed with error:%v", obj, err)
retVal = fmt.Sprintf("%v", obj)
}
}
return retVal
}
func Map2KeySlice(flagMap map[string]int) (keyList []string) {
for k, v := range flagMap {
if v != 0 {
keyList = append(keyList, k)
}
}
return keyList
}
// 合并map相同字段以前面的优先后来相同的字段忽略
func MergeMaps(firstMap map[string]interface{}, otherMaps ...map[string]interface{}) (retVal map[string]interface{}) {
retVal = make(map[string]interface{})
allMaps := append([]map[string]interface{}{firstMap}, otherMaps...)
mapCount := len(allMaps)
for index := range allMaps {
oneMap := allMaps[mapCount-index-1]
for k, v := range oneMap {
retVal[k] = v
}
}
return retVal
}
func Struct2Map(obj interface{}, tagName string, isFlattenAnonymous bool) (mapData map[string]interface{}) {
if tagName == "" {
tagName = "json"
}
structsObj := structs.New(obj)
structsObj.TagName = tagName
structsObj.IsFlattenAnonymous = true
return structsObj.Map()
}
func Struct2MapByJson(obj interface{}) (mapData map[string]interface{}) {
return Struct2Map(obj, "", false)
}
func Struct2FlatMap(obj interface{}) map[string]interface{} {
return Struct2Map(obj, "", true)
}
// !!! 此函数好像不支持struct是内嵌结构的
func Map2Struct(inObj interface{}, outObjAddr interface{}, weaklyTypedInput bool, tagName string, decodeHook interface{}) (err error) {
if tagName == "" {
tagName = "json"
}
if !weaklyTypedInput {
weaklyTypedInput = decodeHook != nil
}
decoder, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: tagName,
Result: outObjAddr,
WeaklyTypedInput: weaklyTypedInput,
DecodeHook: decodeHook,
})
return decoder.Decode(inObj)
}
func Map2StructByJson(inObj interface{}, outObjAddr interface{}, weaklyTypedInput bool) (err error) {
return Map2Struct(inObj, outObjAddr, weaklyTypedInput, "", nil)
}
func Int64Slice2String(intList []int64) (outList []string) {
if len(intList) > 0 {
outList = make([]string, len(intList))
for k, v := range intList {
outList[k] = Int64ToStr(v)
}
}
return outList
}
func StringSlice2Int64(intList []string) (outList []int64) {
if len(intList) > 0 {
outList = make([]int64, len(intList))
for k, v := range intList {
outList[k] = Str2Int64WithDefault(v, 0)
}
}
return outList
}
func StringSlice2Int(intList []string) (outList []int) {
if len(intList) > 0 {
outList = make([]int, len(intList))
for k, v := range intList {
outList[k] = int(Str2Int64WithDefault(v, 0))
}
}
return outList
}
func IntSlice2Int64(intList []int) (outList []int64) {
if len(intList) > 0 {
outList = make([]int64, len(intList))
for k, v := range intList {
outList[k] = int64(v)
}
}
return outList
}
func Int2Float64(i int) (f float64) {
return Str2Float64(Int64ToStr(int64(i)))
}