init project

This commit is contained in:
2023-04-24 17:19:41 +08:00
parent 84729ebb66
commit cdb5a4f9cd
51 changed files with 3328 additions and 1 deletions

16
utils/desensitization.go Normal file
View File

@@ -0,0 +1,16 @@
package utils
type desensitization struct{}
// Desensitization 暴露接口 - 脱敏相关
func Desensitization() *desensitization {
return &desensitization{}
}
// Phone 脱敏手机号
func (desensitization) Phone(phone string) string {
if len(phone) == 11 {
return phone[:3] + "****" + phone[7:]
}
return phone
}

63
utils/file.go Normal file
View File

@@ -0,0 +1,63 @@
package utils
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
"os"
)
type fileUtils struct{}
func FileUtils() *fileUtils {
return &fileUtils{}
}
func (f fileUtils) CheckIsExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
// CheckAndCreate 判断文件名是否存在,不存在就创建
func (f fileUtils) CheckAndCreate(path string) error {
exists, err := f.CheckIsExists(path)
if err != nil {
return err
}
if !exists {
err = os.MkdirAll(path, os.ModePerm)
if err != nil {
return err
}
}
return nil
}
// DelPath 删除目录下的所有文件和目录本身
func (f fileUtils) DelPath(path string) error {
files, err := fileutil.ListFileNames(path)
if err != nil {
return err
}
for _, file := range files {
// 如果是目录,则递归删除
if fileutil.IsDir(file) {
err = f.DelPath(file)
if err != nil {
return err
}
} else {
err = fileutil.RemoveFile(fmt.Sprintf("%s/%s", path, file))
if err != nil {
return err
}
}
}
_ = fileutil.RemoveFile(path)
return nil
}

79
utils/http.go Normal file
View File

@@ -0,0 +1,79 @@
package utils
import (
"net/http"
"net/http/httputil"
"net/url"
"strings"
)
type httpUtil struct {
}
// Http 暴露接口
func Http() *httpUtil {
return &httpUtil{}
}
// NewProxy 重写创建代理函数,加入 Host 信息
func (hu httpUtil) NewProxy(target *url.URL) *httputil.ReverseProxy {
targetQuery := target.RawQuery
director := func(req *http.Request) {
req.Host = target.Host
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
req.URL.Path, req.URL.RawPath = hu.joinURLPath(target, req.URL)
// 过滤掉参数
if uri, err := url.Parse(req.URL.Path); err == nil {
req.URL.Path = uri.Path
}
var rawQuery string
if targetQuery == "" || req.URL.RawQuery == "" {
rawQuery = targetQuery + req.URL.RawQuery
} else {
rawQuery = targetQuery + "&" + req.URL.RawQuery
}
req.URL.RawQuery = rawQuery
if _, ok := req.Header["User-Agent"]; !ok {
// explicitly disable User-Agent so it's not set to default value
req.Header.Set("User-Agent", "")
}
// 补充内部调用Header
req.Header.Set("X-Request-From", "internal")
}
return &httputil.ReverseProxy{Director: director}
}
func (hu httpUtil) joinURLPath(a, b *url.URL) (path, rawpath string) {
if a.RawPath == "" && b.RawPath == "" {
return hu.singleJoiningSlash(a.Path, b.Path), ""
}
// Same as singleJoiningSlash, but uses EscapedPath to determine
// whether a slash should be added
apath := a.EscapedPath()
bpath := b.EscapedPath()
aslash := strings.HasSuffix(apath, "/")
bslash := strings.HasPrefix(bpath, "/")
switch {
case aslash && bslash:
return a.Path + b.Path[1:], apath + bpath[1:]
case !aslash && !bslash:
return a.Path + "/" + b.Path, apath + "/" + bpath
}
return a.Path + b.Path, apath + bpath
}
func (hu httpUtil) singleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}

71
utils/jwt.go Normal file
View File

@@ -0,0 +1,71 @@
package utils
import (
"Lee-WineList/config"
"time"
"github.com/golang-jwt/jwt"
)
type JWT struct {
claims jwt.MapClaims
}
// GenerateToken 根据UserId生成并返回Token
func GenerateToken(userId uint64) string {
jwtConfig := config.Scd.JWT
now := time.Now().Unix()
claims := make(jwt.MapClaims)
claims["exp"] = now + jwtConfig.AccessExpire
claims["iat"] = now
claims["rft"] = now + jwtConfig.RefreshAfter
claims["userId"] = userId
token := jwt.New(jwt.SigningMethodHS256)
token.Claims = claims
tokenStr, _ := token.SignedString([]byte(jwtConfig.AccessSecret))
return tokenStr
}
// ParseToken 解析Token
func ParseToken(tokenStr string) (*JWT, error) {
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
return []byte(config.Scd.JWT.AccessSecret), nil
})
if err != nil {
return nil, err
}
return &JWT{claims: token.Claims.(jwt.MapClaims)}, nil
}
// Valid 验证token是否有效
func (jwt *JWT) Valid() bool {
if err := jwt.claims.Valid(); err != nil {
return false
}
return true
}
// CheckRefresh 检查是否可以刷新
func (jwt *JWT) CheckRefresh() bool {
if time.Now().Unix() > jwt.GetRefreshTime() {
return true
}
return false
}
func (jwt *JWT) RefreshToken() string {
return GenerateToken(jwt.GetUserId())
}
// GetUserId 从Token中解析userId
func (jwt *JWT) GetUserId() uint64 {
return uint64(jwt.claims["userId"].(float64))
}
// GetRefreshTime 从Token中解析refreshTime
func (jwt *JWT) GetRefreshTime() int64 {
return int64(jwt.claims["rft"].(float64))
}

62
utils/oss.go Normal file
View File

@@ -0,0 +1,62 @@
package utils
import (
"Lee-WineList/config"
"fmt"
"git.echol.cn/loser/logger/log"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"io"
)
type ossUtils struct{}
func OssUtils() *ossUtils {
return &ossUtils{}
}
// UploadReader 上传文件 - io.Reader
func (o ossUtils) UploadReader(fileName string, data io.Reader) (string, error) {
// 创建OSSClient实例。
client, err := oss.New(config.Scd.Aliyun.Oss.Endpoint, config.Scd.Aliyun.Oss.AccessKeyId, config.Scd.Aliyun.Oss.AccessKeySecret)
if err != nil {
log.Errorf("创建OSSClient实例失败: %s", err)
return "", err
}
// 获取存储空间。
bucket, err := client.Bucket(config.Scd.Aliyun.Oss.Bucket)
if err != nil {
log.Errorf("获取存储空间失败: %s", err)
return "", err
}
// 指定存储类型为标准存储,默认为标准存储。
storageType := oss.ObjectStorageClass(oss.StorageStandard)
// 指定访问权限为公共读默认为继承bucket的权限。
objectAcl := oss.ObjectACL(oss.ACLPublicRead)
// 上传文件
err = bucket.PutObject(fileName, data, storageType, objectAcl)
if err != nil {
log.Errorf("上传文件失败: %s", err)
return "", err
}
fileUrl := fmt.Sprintf("https://%s.%s/%s", config.Scd.Aliyun.Oss.Bucket, config.Scd.Aliyun.Oss.Endpoint, fileName)
return fileUrl, err
}
func (o ossUtils) GetFile(fileName, localFilePath string) error {
client, err := oss.New(config.Scd.Aliyun.Oss.Endpoint, config.Scd.Aliyun.Oss.AccessKeyId, config.Scd.Aliyun.Oss.AccessKeySecret)
if err != nil {
log.Errorf("创建OSSClient实例失败: %s", err)
return err
}
// 获取存储空间。
bucket, err := client.Bucket(config.Scd.Aliyun.Oss.Bucket)
if err != nil {
log.Errorf("获取存储空间失败: %s", err)
return err
}
err = bucket.GetObjectToFile(fileName, localFilePath)
if err != nil {
return err
}
return nil
}

14
utils/page.go Normal file
View File

@@ -0,0 +1,14 @@
package utils
// GenTotalPage 计算总页数
func GenTotalPage(count int64, size int) int {
totalPage := 0
if count > 0 {
upPage := 0
if int(count)%size > 0 {
upPage = 1
}
totalPage = (int(count) / size) + upPage
}
return totalPage
}

28
utils/time.go Normal file
View File

@@ -0,0 +1,28 @@
package utils
import (
"fmt"
"strings"
"time"
)
type timeUtils struct{}
func TimeUtils() *timeUtils {
return &timeUtils{}
}
// DurationString Duration转自定义String
func (tu timeUtils) DurationString(d time.Duration) string {
if d.Seconds() == 0 {
return "00:00:00"
}
s := d.String()
s = strings.ReplaceAll(s, "h", "小时")
s = strings.ReplaceAll(s, "m", "分")
idx := strings.Index(s, ".")
if idx == -1 {
return fmt.Sprintf("%s秒", s)
}
return fmt.Sprintf("%s秒", s[:idx])
}

20
utils/token.go Normal file
View File

@@ -0,0 +1,20 @@
package utils
import (
"golang.org/x/crypto/bcrypt"
)
// 生成Token的密钥写死防止乱改
//var jwtSecret = "qSxw4fCBBBecPsws"
// HashPassword 加密密码
func HashPassword(pass *string) {
bytePass := []byte(*pass)
hPass, _ := bcrypt.GenerateFromPassword(bytePass, bcrypt.DefaultCost)
*pass = string(hPass)
}
// ComparePassword 校验密码
func ComparePassword(dbPass, pass string) bool {
return bcrypt.CompareHashAndPassword([]byte(dbPass), []byte(pass)) == nil
}

70
utils/wechat.go Normal file
View File

@@ -0,0 +1,70 @@
package utils
import (
"Lee-WineList/config"
"Lee-WineList/model/param"
"git.echol.cn/loser/logger/log"
"github.com/medivhzhan/weapp/v3"
"github.com/medivhzhan/weapp/v3/auth"
"github.com/medivhzhan/weapp/v3/phonenumber"
)
type wechat struct{}
func WeChatUtils() *wechat {
return &wechat{}
}
// GetWechatUnionId 获取微信用户基础信息
func (w wechat) GetWechatUnionId(code string) (unionId, openId, sessionKey string, err error) {
sdk := weapp.NewClient(config.Scd.Tencent.MiniApp.AppId, config.Scd.Tencent.MiniApp.AppSecret, weapp.WithLogger(nil))
cli := sdk.NewAuth()
p := auth.Code2SessionRequest{
Appid: config.Scd.Tencent.MiniApp.AppId,
Secret: config.Scd.Tencent.MiniApp.AppSecret,
JsCode: code,
GrantType: "authorization_code",
}
session, err := cli.Code2Session(&p)
if err != nil {
return
}
if session.GetResponseError() != nil {
log.Errorf("Code解析失败: %v", session.GetResponseError())
err = session.GetResponseError()
return
}
// 设置UnionId值
unionId = session.Unionid
openId = session.Openid
sessionKey = session.SessionKey
return
}
// GetWechatPhone 根据Code获取小程序用户手机号
// return 不带区号的手机号
func (w wechat) GetWechatPhone(param param.DecryptMobile) (string, error) {
sdk := weapp.NewClient(config.Scd.Tencent.MiniApp.AppId, config.Scd.Tencent.MiniApp.AppSecret)
mobile, err := sdk.DecryptMobile(param.SessionKey, param.EncryptedData, param.Iv)
if err != nil {
log.Errorf("解密手机号失败: %v", err)
return "", err
}
log.Debugf("解密后的手机号: %+v", mobile)
return mobile.PurePhoneNumber, nil
}
// GetPhoneNumber 获取手机号
func (w wechat) GetPhoneNumber(code string) (phone string, err error) {
sdk := weapp.NewClient(config.Scd.Tencent.MiniApp.AppId, config.Scd.Tencent.MiniApp.AppSecret)
resp, err := sdk.NewPhonenumber().GetPhoneNumber(&phonenumber.GetPhoneNumberRequest{Code: code})
if err != nil {
log.Errorf("获取手机号失败: %v", err)
return
}
// 获取手机号
phone = resp.Data.PurePhoneNumber
return
}