460 lines
11 KiB
Go
460 lines
11 KiB
Go
|
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)
|
|||
|
}
|