Files
baseapi/utils/typeconv.go
2019-04-10 13:52:17 +08:00

490 lines
11 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/fatih/structs"
"github.com/mitchellh/mapstructure"
)
var (
DefaultTimeValue = Str2Time("1970-01-01 00:00:00")
ZeroTimeValue = time.Time{}
)
func GetConcretValue(value reflect.Value) reflect.Value {
for {
if value.Kind() == reflect.Interface || value.Kind() == reflect.Ptr {
value = value.Elem()
} else {
break
}
}
return value
}
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
}
dataNumber, ok := data.(json.Number)
if !ok {
return 0, fmt.Errorf("data is not json.Number:%v to int64", data)
}
retVal, err := dataNumber.Int64()
if err != nil {
return num, err
}
return retVal, nil
}
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 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
}
dataNumber, ok := data.(json.Number)
if !ok {
return num, fmt.Errorf("data is not json.Number:%v", data)
}
retVal, err := dataNumber.Float64()
if err != nil {
return num, err
}
return retVal, nil
}
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 Interface2Slice(value interface{}) (retVal []interface{}) {
typeInfo := reflect.TypeOf(value)
if typeInfo.Kind() != reflect.Slice {
panic("list must be slice type!")
}
if value != nil {
valueInfo := reflect.ValueOf(value)
retVal = make([]interface{}, valueInfo.Len())
for i := 0; i < valueInfo.Len(); i++ {
retVal[i] = valueInfo.Index(i).Interface()
}
}
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 Int2Str(value int) string {
return strconv.Itoa(value)
}
func Float64TwoInt64(data float64) int64 {
return int64(math.Round(data))
}
// timestamp is in second
func Timestamp2Str(timestamp int64) string {
return Time2Str(Timestamp2Time(timestamp))
}
func Timestamp2Time(timestamp int64) time.Time {
const normalTimestamp = 1533709322
if timestamp > normalTimestamp*100 { // 传成毫秒了
baseapi.SugarLogger.Errorf("Timestamp2Time wrong timestamp:%d", timestamp)
timestamp = timestamp / 1000
}
return time.Unix(timestamp, 0)
}
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 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 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 Struct2MapByJson(obj interface{}) (mapData map[string]interface{}) {
structsObj := structs.New(obj)
structsObj.TagName = "json"
return structsObj.Map()
}
// 此函数将MAP中所有的子MAP中的数据提升到最上层相同字段会覆盖父MAP的
func FlatMap(in map[string]interface{}) map[string]interface{} {
keys := []string{}
maps := []map[string]interface{}{}
for k, v := range in {
if vMap, ok := v.(map[string]interface{}); ok {
vMap = FlatMap(vMap)
maps = append(maps, vMap)
keys = append(keys, k)
}
}
if len(maps) > 0 {
retVal := MergeMaps(in, maps...)
for _, v := range keys {
delete(retVal, v)
}
return retVal
}
return in
}
func Struct2FlatMap(obj interface{}) map[string]interface{} {
m := Struct2MapByJson(obj)
return FlatMap(m)
}
func Map2StructByJson(inObj interface{}, outObjAddr interface{}, weaklyTypedInput bool) (err error) {
decoder, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: "json",
Result: outObjAddr,
WeaklyTypedInput: weaklyTypedInput,
})
return decoder.Decode(inObj)
}