package utils import ( "archive/zip" "bytes" "crypto/md5" "crypto/sha256" "dubbo.apache.org/dubbo-go/v3/common/logger" "encoding/hex" "encoding/json" "errors" "fmt" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" "io" "io/ioutil" "net/http" "net/url" "os" "path/filepath" "reflect" "strconv" "strings" "time" "github.com/fonchain_enterprise/fonchain-main/pkg/e" "github.com/gin-gonic/gin" "github.com/tealeg/xlsx" "go.uber.org/zap" "unsafe" ) const ( ExcelPrefix = "xlsx" ) // ToString 转string func ToString(value interface{}) string { switch v := value.(type) { case string: return v case int: return strconv.FormatInt(int64(v), 10) case int8: return strconv.FormatInt(int64(v), 10) case int16: return strconv.FormatInt(int64(v), 10) case int32: return strconv.FormatInt(int64(v), 10) case int64: return strconv.FormatInt(v, 10) case uint: return strconv.FormatUint(uint64(v), 10) case uint8: return strconv.FormatUint(uint64(v), 10) case uint16: return strconv.FormatUint(uint64(v), 10) case uint32: return strconv.FormatUint(uint64(v), 10) case uint64: return strconv.FormatUint(v, 10) } return "" } // Contains 是否包含 func Contains[T comparable](elems []T, elem T) bool { for _, e := range elems { if elem == e { return true } } return false } // CheckTruth 检测字符串是不是真 func CheckTruth(vals ...string) bool { for _, val := range vals { if val != "" && !strings.EqualFold(val, "false") { return true } } return false } func CheckDirPath(path string, create bool) (exists bool, err error) { exists = false if path == "" { err = errors.New(e.GetMsg(e.InvalidParams)) return } if _, err = os.Stat(path); os.IsNotExist(err) { if !create { return } if err = os.MkdirAll(path, os.ModePerm); err != nil { return } } exists = true return } func ToExcel(titleList []string, dataList []interface{}, dataType string) (content io.ReadSeeker) { // 生成一个新的文件 file := xlsx.NewFile() // 添加sheet页 sheet, _ := file.AddSheet("Sheet1") // 插入表头 titleRow := sheet.AddRow() for _, v := range titleList { cell := titleRow.AddCell() cell.Value = v } // 插入内容 for _, v := range dataList { row := sheet.AddRow() if dataType == "struct" { row.WriteStruct(v, -1) } else if dataType == "slice" { row.WriteSlice(v, -1) } } var buffer bytes.Buffer _ = file.Write(&buffer) content = bytes.NewReader(buffer.Bytes()) return } // ToExcelByType 转成Excel类型 func ToExcelByType(titleList []string, dataList []interface{}, dataType string, filePath string) (content io.ReadSeeker, err error) { // 生成一个新的文件 file := xlsx.NewFile() // 添加sheet页 sheet, _ := file.AddSheet("Sheet1") // 插入表头 titleRow := sheet.AddRow() for _, v := range titleList { cell := titleRow.AddCell() cell.Value = v } // 插入内容 for _, v := range dataList { row := sheet.AddRow() if dataType == "struct" { row.WriteStruct(v, -1) } else if dataType == "slice" { row.WriteSlice(v, -1) } } var buffer bytes.Buffer _ = file.Write(&buffer) if filePath != "" { if err = file.Save(filePath); err != nil { return } } else { content = bytes.NewReader(buffer.Bytes()) } return } // ResponseXls content 为上面生成的io.ReadSeeker, fileTag 为返回前端的文件名 func ResponseXls(c *gin.Context, content io.ReadSeeker, fileTag string) { fileName := fmt.Sprintf("%s.%s", fileTag, ExcelPrefix) c.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName)) c.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") http.ServeContent(c.Writer, c.Request, fileName, time.Now(), content) } func SHA256V(str []byte) string { h := sha256.New() h.Write(str) return hex.EncodeToString(h.Sum(nil)) } func GenerateSHA256Hash(path string) (string, error) { b, err := os.ReadFile(path) if err != nil { zap.L().Error("GenerateSHA256Hash err", zap.Error(err)) return "", err } return SHA256V(b), nil } // SimpleStructField 将结构体转成 map kv func SimpleStructField(v interface{}) (data map[string]interface{}, err error) { data = map[string]interface{}{} dataType := reflect.TypeOf(v) dataValue := reflect.ValueOf(v) if dataType.Kind() == reflect.Ptr { if dataValue.IsNil() { logger.Errorf("dataValue.IsNil") err = errors.New(e.GetMsg(e.Error)) } // 如果是指针,则要判断一下是否为struct originType := reflect.ValueOf(v).Elem().Type() if originType.Kind() != reflect.Struct { logger.Errorf("dataValue.Kind") err = errors.New(e.GetMsg(e.Error)) return } // 解引用 dataValue = dataValue.Elem() dataType = dataType.Elem() } else { logger.Errorf("non ptr") err = errors.New(e.GetMsg(e.Error)) return } num := dataType.NumField() for i := 0; i < num; i++ { field := dataType.Field(i) fieldName := field.Name fieldValue := dataValue.FieldByName(fieldName) if !fieldValue.IsValid() { continue } if fieldValue.CanInterface() { data[fieldName] = fieldValue.Interface() if fieldValue.CanSet() && fieldValue.Kind() == reflect.String { oldValue := fieldValue.Interface().(string) fieldValue.SetString(oldValue) } } else { // 强行取址 forceValue := reflect.NewAt(fieldValue.Type(), unsafe.Pointer(fieldValue.UnsafeAddr())).Elem() data[fieldName] = forceValue } } return } // CreateDirPath 递归创建文件夹 func CreateDirPath(path string) (err error) { if _, err = os.Stat(path); os.IsNotExist(err) { if err = os.MkdirAll(path, os.ModePerm); err != nil { return } } return } // SaveUrlFileDisk 保存图片到本地 func SaveUrlFileDisk(url string, path string, filename string) (fullPath string, err error) { if err = CreateDirPath(path); err != nil { zap.L().Error("SaveUrlFileDisk err ", zap.Error(err)) return } if filename == "" { stepName := strings.Split(url, "/") if len(stepName) > 1 { filename = stepName[len(stepName)-1] } } resp, err := http.Get(url) if err != nil { logger.Errorf("SaveUrlFileDisk get err", err) err = errors.New(e.GetMsg(e.ERROR_DOWNLOAD_FILE)) return } defer func() { if err := recover(); err != nil { logger.Errorf("SaveUrlFileDisk close err", err) } resp.Body.Close() }() bytes, err := ioutil.ReadAll(resp.Body) fullPath = fmt.Sprintf("%s/%s", path, filename) // 写入数据 err = ioutil.WriteFile(fullPath, bytes, 0777) return } // Unzip 解压zip func Unzip(zipFilePath string, destDir string) error { zipReader, err := zip.OpenReader(zipFilePath) if err != nil { return err } defer zipReader.Close() var decodeName string for _, f := range zipReader.File { if f.Flags == 0 { //如果标致位是0 则是默认的本地编码 默认为gbk i := bytes.NewReader([]byte(f.Name)) decoder := transform.NewReader(i, simplifiedchinese.GB18030.NewDecoder()) content, _ := ioutil.ReadAll(decoder) decodeName = string(content) } else { //如果标志为是 1 << 11也就是 2048 则是utf-8编码 decodeName = f.Name } fpath := filepath.Join(destDir, decodeName) if f.FileInfo().IsDir() { _ = os.MkdirAll(fpath, os.ModePerm) } else { if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { return err } inFile, errS := f.Open() if errS != nil { return errS } defer inFile.Close() outFile, errA := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) if errA != nil { return errA } defer outFile.Close() _, err = io.Copy(outFile, inFile) if err != nil { return err } } } return nil } // ZipFile 打包成zip文件 // @title ZipDir // @description 将文件夹下的文件打包成zip // @auth dyb 时间 // @param src string 文件夹路径 // @return err error 错误内容 func ZipFile(srcDir string, zipFilePath string) (err error) { // 预防:旧文件无法覆盖 os.RemoveAll(zipFilePath) // 创建:zip文件 zipfile, _ := os.Create(zipFilePath) defer zipfile.Close() // 打开:zip文件 archive := zip.NewWriter(zipfile) defer archive.Close() // 遍历路径信息 filepath.Walk(srcDir, func(path string, info os.FileInfo, _ error) error { // 如果是源路径,提前进行下一个遍历 if path == srcDir { return nil } // 获取:文件头信息 header, _ := zip.FileInfoHeader(info) header.Name = strings.TrimPrefix(path, srcDir+`\`) header.Name = strings.Replace(path, srcDir, "", 1) if header.Name[:1] == "\\" || header.Name[:1] == "/" { header.Name = header.Name[1:] } // 判断:文件是不是文件夹 if info.IsDir() { header.Name += `/` } else { // 设置:zip的文件压缩算法 header.Method = zip.Deflate } // 创建:压缩包头部信息 writer, _ := archive.CreateHeader(header) if !info.IsDir() { file, _ := os.Open(path) defer file.Close() io.Copy(writer, file) } return nil }) return } // PostForm 发送post请求 func PostForm(urlStr string, data url.Values) (string, error) { resp, err := http.PostForm(urlStr, data) if err != nil { // handle error } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { // handle error } return string(body), err } func PostBody(url string, data interface{}) (httpCode int, respBody string, err error) { var payload []byte payload, err = json.Marshal(data) if err != nil { zap.L().Error("PostBody Marshal", zap.Error(err)) err = errors.New(e.GetMsg(e.JsonUnmarshal)) return } // 创建一个请求 req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload)) if err != nil { zap.L().Error("NewRequest err", zap.Error(err)) err = errors.New(e.GetMsg(e.ErrorHttp)) return } // 设置请求头 req.Header.Set("Content-Type", "application/json") client := http.Client{} resp, err := client.Do(req) if err != nil { zap.L().Error("client.Do err", zap.Error(err)) err = errors.New(e.GetMsg(e.ErrorHttp)) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { zap.L().Error("ReadAll err", zap.Error(err)) err = errors.New(e.GetMsg(e.ErrorBody)) return } httpCode = resp.StatusCode respBody = string(body) return } func Get(url string) string { client := &http.Client{Timeout: 5 * time.Second} resp, err := client.Get(url) if err != nil { panic(err) } defer resp.Body.Close() var buffer [512]byte result := bytes.NewBuffer(nil) for { n, err := resp.Body.Read(buffer[0:]) result.Write(buffer[0:n]) if err != nil && err == io.EOF { break } else if err != nil { panic(err) } } return result.String() } func StructToMap(obj interface{}) map[string]interface{} { objMap := make(map[string]interface{}) objVal := reflect.ValueOf(obj) for i := 0; i < objVal.NumField(); i++ { field := objVal.Type().Field(i) value := objVal.Field(i).Interface() objMap[field.Name] = value } return objMap } func Md5Str(input string) string { hashNew := md5.New() hashNew.Write([]byte(input)) hashBytes := hashNew.Sum(nil) return hex.EncodeToString(hashBytes) }