Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f8f647c12a | |||
| d88178458d | |||
| 9b570c04c0 |
18
README.md
18
README.md
@@ -11,6 +11,16 @@ go env -w GOINSECURE=git.apinb.com/*
|
|||||||
go env -w GONOSUMDB=git.apinb.com/*
|
go env -w GONOSUMDB=git.apinb.com/*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 配置环境变量
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export BSM_Workspace=def
|
||||||
|
export BSM_JwtSecretKey=your_secret_key
|
||||||
|
export BSM_RuntimeMode=dev
|
||||||
|
export BSM_Prefix=/usr/local/bsm
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 核心功能模块
|
## 核心功能模块
|
||||||
|
|
||||||
### 1. 服务管理 (service)
|
### 1. 服务管理 (service)
|
||||||
@@ -321,14 +331,6 @@ go env -w GONOSUMDB=git.apinb.com/*
|
|||||||
- 支持许可证文件验证
|
- 支持许可证文件验证
|
||||||
|
|
||||||
|
|
||||||
### 配置环境变量
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export BSM_Workspace=def
|
|
||||||
export BSM_JwtSecretKey=your_secret_key
|
|
||||||
export BSM_RuntimeMode=dev
|
|
||||||
export BSM_Prefix=/usr/local/bsm
|
|
||||||
```
|
|
||||||
|
|
||||||
### 安全建议
|
### 安全建议
|
||||||
|
|
||||||
|
|||||||
14
cache/redis/cache.go
vendored
14
cache/redis/cache.go
vendored
@@ -5,6 +5,7 @@ package redis
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.apinb.com/bsm-sdk/core/errcode"
|
"git.apinb.com/bsm-sdk/core/errcode"
|
||||||
@@ -15,19 +16,20 @@ import (
|
|||||||
// prefix: 键前缀
|
// prefix: 键前缀
|
||||||
// params: 键参数
|
// params: 键参数
|
||||||
// 返回: 完整的缓存键
|
// 返回: 完整的缓存键
|
||||||
func (c *RedisClient) BuildKey(prefix string, params ...interface{}) string {
|
func (c *RedisClient) BuildKey(prefix string, params ...any) string {
|
||||||
key := vars.CacheKeyPrefix + prefix
|
var key strings.Builder
|
||||||
|
key.WriteString(vars.CacheKeyPrefix + prefix)
|
||||||
for _, param := range params {
|
for _, param := range params {
|
||||||
key += fmt.Sprintf(":%v", param)
|
key.WriteString(fmt.Sprintf(":%v", param))
|
||||||
}
|
}
|
||||||
return key
|
return key.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 获取缓存
|
// Get 获取缓存
|
||||||
// key: 缓存键
|
// key: 缓存键
|
||||||
// result: 存储结果的指针
|
// result: 存储结果的指针
|
||||||
// 返回: 错误信息
|
// 返回: 错误信息
|
||||||
func (c *RedisClient) Get(key string, result interface{}) error {
|
func (c *RedisClient) Get(key string, result any) error {
|
||||||
if c.Client == nil {
|
if c.Client == nil {
|
||||||
return errcode.ErrRedis
|
return errcode.ErrRedis
|
||||||
}
|
}
|
||||||
@@ -45,7 +47,7 @@ func (c *RedisClient) Get(key string, result interface{}) error {
|
|||||||
// value: 缓存值
|
// value: 缓存值
|
||||||
// ttl: 过期时间
|
// ttl: 过期时间
|
||||||
// 返回: 错误信息
|
// 返回: 错误信息
|
||||||
func (c *RedisClient) Set(key string, value interface{}, ttl time.Duration) error {
|
func (c *RedisClient) Set(key string, value any, ttl time.Duration) error {
|
||||||
if c.Client == nil {
|
if c.Client == nil {
|
||||||
return errcode.ErrRedis
|
return errcode.ErrRedis
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func (t *tokenJwt) GenerateJwt(id uint, identity, client, role string, owner any
|
|||||||
|
|
||||||
// 解析JWT
|
// 解析JWT
|
||||||
func (t *tokenJwt) ParseJwt(tokenstring string) (*Claims, error) {
|
func (t *tokenJwt) ParseJwt(tokenstring string) (*Claims, error) {
|
||||||
token, err := jwt.ParseWithClaims(tokenstring, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.ParseWithClaims(tokenstring, &Claims{}, func(token *jwt.Token) (any, error) {
|
||||||
return []byte(t.SecretKey), nil
|
return []byte(t.SecretKey), nil
|
||||||
})
|
})
|
||||||
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
|
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func NewElastic(endpoints []string, username, password string) (*ES, error) {
|
|||||||
// "time": time.Now().Unix(),
|
// "time": time.Now().Unix(),
|
||||||
// "date": time.Now(),
|
// "date": time.Now(),
|
||||||
// }
|
// }
|
||||||
func (es *ES) CreateDocument(index string, id string, doc *interface{}) {
|
func (es *ES) CreateDocument(index string, id string, doc *any) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := json.NewEncoder(&buf).Encode(doc); err != nil {
|
if err := json.NewEncoder(&buf).Encode(doc); err != nil {
|
||||||
log.Println("Elastic NewEncoder:", err)
|
log.Println("Elastic NewEncoder:", err)
|
||||||
@@ -75,7 +75,7 @@ func (es *ES) CreateDocument(index string, id string, doc *interface{}) {
|
|||||||
// index 如果文档不存在就创建,如果文档存在就更新
|
// index 如果文档不存在就创建,如果文档存在就更新
|
||||||
// update 更新一个文档,如果文档不存在就返回错误
|
// update 更新一个文档,如果文档不存在就返回错误
|
||||||
// delete 删除一个文档,如果要删除的文档id不存在,就返回错误
|
// delete 删除一个文档,如果要删除的文档id不存在,就返回错误
|
||||||
func (es *ES) Batch(index string, documens []map[string]interface{}, action string) {
|
func (es *ES) Batch(index string, documens []map[string]any, action string) {
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -162,7 +162,7 @@ func (es *ES) Batch(index string, documens []map[string]interface{}, action stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *ES) Search(index string, query map[string]interface{}) (res *esapi.Response, err error) {
|
func (es *ES) Search(index string, query map[string]any) (res *esapi.Response, err error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err = json.NewEncoder(&buf).Encode(query); err != nil {
|
if err = json.NewEncoder(&buf).Encode(query); err != nil {
|
||||||
return
|
return
|
||||||
@@ -201,7 +201,7 @@ func (es *ES) Delete(index, idx string) (res *esapi.Response, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *ES) DeleteByQuery(index []string, query map[string]interface{}) (res *esapi.Response, err error) {
|
func (es *ES) DeleteByQuery(index []string, query map[string]any) (res *esapi.Response, err error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err = json.NewEncoder(&buf).Encode(query); err != nil {
|
if err = json.NewEncoder(&buf).Encode(query); err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -1,3 +1,3 @@
|
|||||||
module git.apinb.com/bsm-sdk/core
|
module git.apinb.com/bsm-sdk/core
|
||||||
|
|
||||||
go 1.25.1
|
go 1.26.0
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -43,42 +44,54 @@ type MachineInfo struct {
|
|||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
// 授权信息
|
// 授权信息
|
||||||
type Licence struct {
|
type Licence struct {
|
||||||
CompanyName string `json:"licence_to"` // 授权公司
|
CompanyName string `json:"licence_to"` // 授权公司
|
||||||
CreateDate int `json:"create"` // 生效日期
|
CreateDate int `json:"create"` // 生效日期
|
||||||
ExpireDate int `json:"expire"` // 有效期
|
ExpireDate int `json:"expire"` // 有效期
|
||||||
MachineCodes []string `json:"machine_codes"` // 机器码列表
|
MachineCodes []string `json:"machine_codes"` // 机器码列表
|
||||||
|
Args map[string]string `json:"args"` // 许可证相关参数定义
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
var (
|
var (
|
||||||
des_key string
|
des_key string
|
||||||
des_iv string
|
des_iv string
|
||||||
|
args map[string]string
|
||||||
Check_Licence_File bool = true // 是否检查部署授权文件
|
Check_Licence_File bool = true // 是否检查部署授权文件
|
||||||
)
|
)
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
const (
|
const (
|
||||||
signKey = "1F36659EC27CFFF849E068EA80B1A4CA"
|
SignKey = "1F36659EC27CFFF849E068EA80B1A4CA"
|
||||||
LICENCE_KEY = "BLOCKS_KEY"
|
LicenceKey = "BLOCKS_KEY"
|
||||||
)
|
)
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
func init() {
|
func init() {
|
||||||
des_key = base64.StdEncoding.EncodeToString([]byte(signKey))
|
des_key = base64.StdEncoding.EncodeToString([]byte(SignKey))
|
||||||
des_iv = base64.StdEncoding.EncodeToString([]byte(signKey[:16]))
|
des_iv = base64.StdEncoding.EncodeToString([]byte(SignKey[:16]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func WatchCheckLicence(licPath, licName string) {
|
func WatchCheckLicence(licPath, licName string) {
|
||||||
utils.SetInterval(func() {
|
utils.SetInterval(func() {
|
||||||
if !CheckLicence(licPath, licName) {
|
if !CheckLicence(licPath, licName) {
|
||||||
log.Println("授权文件失效,请重新部署授权文件:", licPath)
|
exit()
|
||||||
os.Exit(99)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}, time.Hour*1)
|
}, time.Hour*1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetArgs(licPath, licName string) map[string]string {
|
||||||
|
if !CheckLicence(licPath, licName) {
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func exit() {
|
||||||
|
log.Println("授权文件失效,请重新部署授权文件!")
|
||||||
|
os.Exit(99)
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
func CheckLicence(licPath, licName string) bool {
|
func CheckLicence(licPath, licName string) bool {
|
||||||
// 加载授权文件
|
// 加载授权文件
|
||||||
@@ -97,6 +110,8 @@ func CheckLicence(licPath, licName string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args = l.Args
|
||||||
|
|
||||||
return l.VerifyLicence(licName)
|
return l.VerifyLicence(licName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,13 +136,7 @@ func (l *Licence) VerifyLicence(licName string) bool {
|
|||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
// 检查机器码是否存在授权列表中
|
// 检查机器码是否存在授权列表中
|
||||||
func (l *Licence) ValidMachineCode(code string) bool {
|
func (l *Licence) ValidMachineCode(code string) bool {
|
||||||
result := false
|
result := slices.Contains(l.MachineCodes, code)
|
||||||
for _, c := range l.MachineCodes {
|
|
||||||
if c == code {
|
|
||||||
result = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -195,13 +204,14 @@ func EncryptStr(txt string) string {
|
|||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
// 生成授权文件
|
// 生成授权文件
|
||||||
func BuildLicence(company_name string, Create_date int, expire_date int, machine_codes []string) (string, error) {
|
func BuildLicence(company_name string, Create_date int, expire_date int, machine_codes []string, args map[string]string) (string, error) {
|
||||||
// 构造licence
|
// 构造licence
|
||||||
licence := &Licence{
|
licence := &Licence{
|
||||||
CompanyName: company_name,
|
CompanyName: company_name,
|
||||||
CreateDate: Create_date,
|
CreateDate: Create_date,
|
||||||
ExpireDate: expire_date,
|
ExpireDate: expire_date,
|
||||||
MachineCodes: machine_codes,
|
MachineCodes: machine_codes,
|
||||||
|
Args: args,
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := json.Marshal(licence)
|
content, err := json.Marshal(licence)
|
||||||
@@ -216,7 +226,7 @@ func BuildLicence(company_name string, Create_date int, expire_date int, machine
|
|||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
// 生成激活码
|
// 生成激活码
|
||||||
func GetLicenceCode(machinceCode string) string {
|
func GetLicenceCode(machinceCode string) string {
|
||||||
return hash256(machinceCode + "&" + signKey)
|
return hash256(machinceCode + "&" + SignKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -250,7 +260,7 @@ func getMacAddrs() []string {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return macs
|
return macs
|
||||||
}
|
}
|
||||||
for i := 0; i < len(netfaces); i++ {
|
for i := range netfaces {
|
||||||
if (netfaces[i].Flags&net.FlagUp) != 0 && (netfaces[i].Flags&net.FlagLoopback) == 0 {
|
if (netfaces[i].Flags&net.FlagUp) != 0 && (netfaces[i].Flags&net.FlagLoopback) == 0 {
|
||||||
addrs, _ := netfaces[i].Addrs()
|
addrs, _ := netfaces[i].Addrs()
|
||||||
for _, address := range addrs {
|
for _, address := range addrs {
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ func (l *Logger) sendToRemote(level, name, out string) {
|
|||||||
if l.endpoint == "" {
|
if l.endpoint == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data := map[string]interface{}{
|
data := map[string]any{
|
||||||
"level": level,
|
"level": level,
|
||||||
"name": name,
|
"name": name,
|
||||||
"out": out,
|
"out": out,
|
||||||
@@ -169,7 +169,7 @@ func (l *Logger) sendToRemote(level, name, out string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Debug 输出调试信息
|
// Debug 输出调试信息
|
||||||
func (l *Logger) Debug(v ...interface{}) {
|
func (l *Logger) Debug(v ...any) {
|
||||||
if l.level <= vars.DEBUG {
|
if l.level <= vars.DEBUG {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprint(v...)
|
out := fmt.Sprint(v...)
|
||||||
@@ -181,7 +181,7 @@ func (l *Logger) Debug(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Debugf 格式化输出调试信息
|
// Debugf 格式化输出调试信息
|
||||||
func (l *Logger) Debugf(format string, v ...interface{}) {
|
func (l *Logger) Debugf(format string, v ...any) {
|
||||||
if l.level <= vars.DEBUG {
|
if l.level <= vars.DEBUG {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprintf(format, v...)
|
out := fmt.Sprintf(format, v...)
|
||||||
@@ -193,7 +193,7 @@ func (l *Logger) Debugf(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Info 输出信息
|
// Info 输出信息
|
||||||
func (l *Logger) Info(v ...interface{}) {
|
func (l *Logger) Info(v ...any) {
|
||||||
if l.level <= vars.INFO {
|
if l.level <= vars.INFO {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprint(v...)
|
out := fmt.Sprint(v...)
|
||||||
@@ -205,7 +205,7 @@ func (l *Logger) Info(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Infof 格式化输出信息
|
// Infof 格式化输出信息
|
||||||
func (l *Logger) Infof(format string, v ...interface{}) {
|
func (l *Logger) Infof(format string, v ...any) {
|
||||||
if l.level <= vars.INFO {
|
if l.level <= vars.INFO {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprintf(format, v...)
|
out := fmt.Sprintf(format, v...)
|
||||||
@@ -217,7 +217,7 @@ func (l *Logger) Infof(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Warn 输出警告
|
// Warn 输出警告
|
||||||
func (l *Logger) Warn(v ...interface{}) {
|
func (l *Logger) Warn(v ...any) {
|
||||||
if l.level <= vars.WARN {
|
if l.level <= vars.WARN {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprint(v...)
|
out := fmt.Sprint(v...)
|
||||||
@@ -229,7 +229,7 @@ func (l *Logger) Warn(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Warnf 格式化输出警告
|
// Warnf 格式化输出警告
|
||||||
func (l *Logger) Warnf(format string, v ...interface{}) {
|
func (l *Logger) Warnf(format string, v ...any) {
|
||||||
if l.level <= vars.WARN {
|
if l.level <= vars.WARN {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprintf(format, v...)
|
out := fmt.Sprintf(format, v...)
|
||||||
@@ -241,7 +241,7 @@ func (l *Logger) Warnf(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Error 输出错误
|
// Error 输出错误
|
||||||
func (l *Logger) Error(v ...interface{}) {
|
func (l *Logger) Error(v ...any) {
|
||||||
if l.level <= vars.ERROR {
|
if l.level <= vars.ERROR {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprint(v...)
|
out := fmt.Sprint(v...)
|
||||||
@@ -253,7 +253,7 @@ func (l *Logger) Error(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Errorf 格式化输出错误
|
// Errorf 格式化输出错误
|
||||||
func (l *Logger) Errorf(format string, v ...interface{}) {
|
func (l *Logger) Errorf(format string, v ...any) {
|
||||||
if l.level <= vars.ERROR {
|
if l.level <= vars.ERROR {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprintf(format, v...)
|
out := fmt.Sprintf(format, v...)
|
||||||
@@ -265,7 +265,7 @@ func (l *Logger) Errorf(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fatal 输出致命错误并退出程序
|
// Fatal 输出致命错误并退出程序
|
||||||
func (l *Logger) Fatal(v ...interface{}) {
|
func (l *Logger) Fatal(v ...any) {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprint(v...)
|
out := fmt.Sprint(v...)
|
||||||
if l.onRemote {
|
if l.onRemote {
|
||||||
@@ -276,7 +276,7 @@ func (l *Logger) Fatal(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf 格式化输出致命错误并退出程序
|
// Fatalf 格式化输出致命错误并退出程序
|
||||||
func (l *Logger) Fatalf(format string, v ...interface{}) {
|
func (l *Logger) Fatalf(format string, v ...any) {
|
||||||
l.checkAndRotateLog()
|
l.checkAndRotateLog()
|
||||||
out := fmt.Sprintf(format, v...)
|
out := fmt.Sprintf(format, v...)
|
||||||
if l.onRemote {
|
if l.onRemote {
|
||||||
@@ -287,17 +287,17 @@ func (l *Logger) Fatalf(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print 输出信息(兼容标准log包)
|
// Print 输出信息(兼容标准log包)
|
||||||
func (l *Logger) Print(v ...interface{}) {
|
func (l *Logger) Print(v ...any) {
|
||||||
l.Info(v...)
|
l.Info(v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Printf 格式化输出信息(兼容标准log包)
|
// Printf 格式化输出信息(兼容标准log包)
|
||||||
func (l *Logger) Printf(format string, v ...interface{}) {
|
func (l *Logger) Printf(format string, v ...any) {
|
||||||
l.Infof(format, v...)
|
l.Infof(format, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Println 输出信息并换行(兼容标准log包)
|
// Println 输出信息并换行(兼容标准log包)
|
||||||
func (l *Logger) Println(v ...interface{}) {
|
func (l *Logger) Println(v ...any) {
|
||||||
l.Info(v...)
|
l.Info(v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,91 +326,91 @@ func (l *Logger) Close() error {
|
|||||||
// 全局日志函数(兼容标准log包)
|
// 全局日志函数(兼容标准log包)
|
||||||
|
|
||||||
// Debug 全局调试日志
|
// Debug 全局调试日志
|
||||||
func Debug(v ...interface{}) {
|
func Debug(v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Debug(v...)
|
globalLogger.Debug(v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugf 全局调试日志
|
// Debugf 全局调试日志
|
||||||
func Debugf(format string, v ...interface{}) {
|
func Debugf(format string, v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Debugf(format, v...)
|
globalLogger.Debugf(format, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info 全局信息日志
|
// Info 全局信息日志
|
||||||
func Info(v ...interface{}) {
|
func Info(v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Info(v...)
|
globalLogger.Info(v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infof 全局信息日志
|
// Infof 全局信息日志
|
||||||
func Infof(format string, v ...interface{}) {
|
func Infof(format string, v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Infof(format, v...)
|
globalLogger.Infof(format, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn 全局警告日志
|
// Warn 全局警告日志
|
||||||
func Warn(v ...interface{}) {
|
func Warn(v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Warn(v...)
|
globalLogger.Warn(v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnf 全局警告日志
|
// Warnf 全局警告日志
|
||||||
func Warnf(format string, v ...interface{}) {
|
func Warnf(format string, v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Warnf(format, v...)
|
globalLogger.Warnf(format, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error 全局错误日志
|
// Error 全局错误日志
|
||||||
func Error(v ...interface{}) {
|
func Error(v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Error(v...)
|
globalLogger.Error(v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf 全局错误日志
|
// Errorf 全局错误日志
|
||||||
func Errorf(format string, v ...interface{}) {
|
func Errorf(format string, v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Errorf(format, v...)
|
globalLogger.Errorf(format, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal 全局致命错误日志
|
// Fatal 全局致命错误日志
|
||||||
func Fatal(v ...interface{}) {
|
func Fatal(v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Fatal(v...)
|
globalLogger.Fatal(v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf 全局致命错误日志
|
// Fatalf 全局致命错误日志
|
||||||
func Fatalf(format string, v ...interface{}) {
|
func Fatalf(format string, v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Fatalf(format, v...)
|
globalLogger.Fatalf(format, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print 全局打印日志(兼容标准log包)
|
// Print 全局打印日志(兼容标准log包)
|
||||||
func Print(v ...interface{}) {
|
func Print(v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Print(v...)
|
globalLogger.Print(v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Printf 全局打印日志(兼容标准log包)
|
// Printf 全局打印日志(兼容标准log包)
|
||||||
func Printf(format string, v ...interface{}) {
|
func Printf(format string, v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Printf(format, v...)
|
globalLogger.Printf(format, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Println 全局打印日志(兼容标准log包)
|
// Println 全局打印日志(兼容标准log包)
|
||||||
func Println(v ...interface{}) {
|
func Println(v ...any) {
|
||||||
if globalLogger != nil {
|
if globalLogger != nil {
|
||||||
globalLogger.Println(v...)
|
globalLogger.Println(v...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,25 +16,25 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// record INFO message. Color White
|
// record INFO message. Color White
|
||||||
func Info(format string, a ...interface{}) {
|
func Info(format string, a ...any) {
|
||||||
message := fmt.Sprintf("\033[37m[Info] "+format+"\033[0m\n", a...)
|
message := fmt.Sprintf("\033[37m[Info] "+format+"\033[0m\n", a...)
|
||||||
logger.Print(message)
|
logger.Print(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// record Warn message. Color Orange
|
// record Warn message. Color Orange
|
||||||
func Warn(format string, a ...interface{}) {
|
func Warn(format string, a ...any) {
|
||||||
message := fmt.Sprintf("\033[33m[Warn] "+format+"\033[0m\n", a...)
|
message := fmt.Sprintf("\033[33m[Warn] "+format+"\033[0m\n", a...)
|
||||||
logger.Print(message)
|
logger.Print(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// record Success message. Color Green
|
// record Success message. Color Green
|
||||||
func Success(format string, a ...interface{}) {
|
func Success(format string, a ...any) {
|
||||||
message := fmt.Sprintf("\033[32m[Succ] "+format+"\033[0m\n", a...)
|
message := fmt.Sprintf("\033[32m[Succ] "+format+"\033[0m\n", a...)
|
||||||
logger.Print(message)
|
logger.Print(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// record ERROR message. Color Red
|
// record ERROR message. Color Red
|
||||||
func Error(format string, a ...interface{}) {
|
func Error(format string, a ...any) {
|
||||||
message := fmt.Sprintf("\033[31m[Error] "+format+"\033[0m\n", a...)
|
message := fmt.Sprintf("\033[31m[Error] "+format+"\033[0m\n", a...)
|
||||||
logger.Print(message)
|
logger.Print(message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func WeChat_Pkcs7Unpad(data []byte, blockSize int) ([]byte, error) {
|
|||||||
if n == 0 || n > len(data) {
|
if n == 0 || n > len(data) {
|
||||||
return nil, ErrInvalidPKCS7Padding
|
return nil, ErrInvalidPKCS7Padding
|
||||||
}
|
}
|
||||||
for i := 0; i < n; i++ {
|
for i := range n {
|
||||||
if data[len(data)-n+i] != c {
|
if data[len(data)-n+i] != c {
|
||||||
return nil, ErrInvalidPKCS7Padding
|
return nil, ErrInvalidPKCS7Padding
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
import "slices"
|
||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
// ArrayInString 判断字符串是否存在于字符串切片中
|
// ArrayInString 判断字符串是否存在于字符串切片中
|
||||||
@@ -7,24 +9,14 @@ import "strings"
|
|||||||
// array: 需要查找的字符串切片
|
// array: 需要查找的字符串切片
|
||||||
func ArrayInString(target string, array []string) bool {
|
func ArrayInString(target string, array []string) bool {
|
||||||
target = strings.TrimSpace(target)
|
target = strings.TrimSpace(target)
|
||||||
for _, v := range array {
|
return slices.Contains(array, target)
|
||||||
if strings.TrimSpace(v) == target {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArrayInInt 判断整数是否存在于整型切片中
|
// ArrayInInt 判断整数是否存在于整型切片中
|
||||||
// target: 待匹配的目标整数
|
// target: 待匹配的目标整数
|
||||||
// array: 需要查找的整型切片
|
// array: 需要查找的整型切片
|
||||||
func ArrayInInt(target int, array []int) bool {
|
func ArrayInInt(target int, array []int) bool {
|
||||||
for _, v := range array {
|
return slices.Contains(array, target)
|
||||||
if v == target {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArrayRemoveRepeatString 去除字符串切片中的重复元素(保持原有顺序)
|
// ArrayRemoveRepeatString 去除字符串切片中的重复元素(保持原有顺序)
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ func BinaryToDecimal(bit string) (num int) {
|
|||||||
fields := strings.Split(bit, "")
|
fields := strings.Split(bit, "")
|
||||||
lens := len(fields)
|
lens := len(fields)
|
||||||
var tempF float64 = 0
|
var tempF float64 = 0
|
||||||
for i := 0; i < lens; i++ {
|
for i := range lens {
|
||||||
floatNum := String2Float64(fields[i])
|
floatNum := String2Float64(fields[i])
|
||||||
tempF += floatNum * math.Pow(2, float64(lens-i-1))
|
tempF += floatNum * math.Pow(2, float64(lens-i-1))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func If(condition bool, trueValue, falseValue interface{}) interface{} {
|
func If(condition bool, trueValue, falseValue any) any {
|
||||||
if condition {
|
if condition {
|
||||||
return trueValue
|
return trueValue
|
||||||
}
|
}
|
||||||
@@ -21,8 +21,8 @@ func FirstToUpper(str string) string {
|
|||||||
return strings.ToUpper(str[:1]) + strings.ToLower(str[1:])
|
return strings.ToUpper(str[:1]) + strings.ToLower(str[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseParams(in map[string]string) map[string]interface{} {
|
func ParseParams(in map[string]string) map[string]any {
|
||||||
out := make(map[string]interface{})
|
out := make(map[string]any)
|
||||||
for k, v := range in {
|
for k, v := range in {
|
||||||
fv, err := strconv.ParseFloat(v, 64)
|
fv, err := strconv.ParseFloat(v, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
914
utils/qrcode.go
914
utils/qrcode.go
@@ -1,457 +1,457 @@
|
|||||||
// Package utils 提供通用工具函数
|
// Package utils 提供通用工具函数
|
||||||
//
|
//
|
||||||
// 二维码生成功能模块
|
// 二维码生成功能模块
|
||||||
//
|
//
|
||||||
// 本模块提供了完整的二维码生成功能,支持:
|
// 本模块提供了完整的二维码生成功能,支持:
|
||||||
// - 基础二维码生成(保存为PNG文件)
|
// - 基础二维码生成(保存为PNG文件)
|
||||||
// - 生成字节数组(可用于HTTP响应、数据库存储等)
|
// - 生成字节数组(可用于HTTP响应、数据库存储等)
|
||||||
// - Base64编码输出(便于存储和传输)
|
// - Base64编码输出(便于存储和传输)
|
||||||
// - Data URL格式(可直接用于HTML <img>标签)
|
// - Data URL格式(可直接用于HTML <img>标签)
|
||||||
// - 自定义配置(尺寸、颜色、纠错级别)
|
// - 自定义配置(尺寸、颜色、纠错级别)
|
||||||
// - 带Logo的二维码
|
// - 带Logo的二维码
|
||||||
// - 批量生成二维码
|
// - 批量生成二维码
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/png"
|
"image/png"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/skip2/go-qrcode"
|
"github.com/skip2/go-qrcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// QRCodeErrorLevel 二维码纠错级别
|
// QRCodeErrorLevel 二维码纠错级别
|
||||||
//
|
//
|
||||||
// 纠错级别决定了二维码能容忍多少损坏:
|
// 纠错级别决定了二维码能容忍多少损坏:
|
||||||
// - 级别越高,容错能力越强,但二维码会更复杂
|
// - 级别越高,容错能力越强,但二维码会更复杂
|
||||||
// - 添加Logo时建议使用高级纠错
|
// - 添加Logo时建议使用高级纠错
|
||||||
// - 一般场景使用中级纠错即可
|
// - 一般场景使用中级纠错即可
|
||||||
type QRCodeErrorLevel int
|
type QRCodeErrorLevel int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// QRCodeErrorLevelLow 低级纠错(约7%容错)
|
// QRCodeErrorLevelLow 低级纠错(约7%容错)
|
||||||
// 适用场景:环境良好、追求小尺寸、内容较少
|
// 适用场景:环境良好、追求小尺寸、内容较少
|
||||||
QRCodeErrorLevelLow QRCodeErrorLevel = iota
|
QRCodeErrorLevelLow QRCodeErrorLevel = iota
|
||||||
|
|
||||||
// QRCodeErrorLevelMedium 中级纠错(约15%容错)
|
// QRCodeErrorLevelMedium 中级纠错(约15%容错)
|
||||||
// 适用场景:通用场景(默认推荐)
|
// 适用场景:通用场景(默认推荐)
|
||||||
QRCodeErrorLevelMedium
|
QRCodeErrorLevelMedium
|
||||||
|
|
||||||
// QRCodeErrorLevelQuartile 较高级纠错(约25%容错)
|
// QRCodeErrorLevelQuartile 较高级纠错(约25%容错)
|
||||||
// 适用场景:需要较高容错能力
|
// 适用场景:需要较高容错能力
|
||||||
QRCodeErrorLevelQuartile
|
QRCodeErrorLevelQuartile
|
||||||
|
|
||||||
// QRCodeErrorLevelHigh 高级纠错(约30%容错)
|
// QRCodeErrorLevelHigh 高级纠错(约30%容错)
|
||||||
// 适用场景:添加Logo、容易损坏的环境、长期使用
|
// 适用场景:添加Logo、容易损坏的环境、长期使用
|
||||||
QRCodeErrorLevelHigh
|
QRCodeErrorLevelHigh
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultQRCodeSize 默认二维码尺寸(像素)
|
// DefaultQRCodeSize 默认二维码尺寸(像素)
|
||||||
DefaultQRCodeSize = 256
|
DefaultQRCodeSize = 256
|
||||||
// MinQRCodeSize 最小二维码尺寸
|
// MinQRCodeSize 最小二维码尺寸
|
||||||
MinQRCodeSize = 21
|
MinQRCodeSize = 21
|
||||||
// MaxQRCodeSize 最大二维码尺寸
|
// MaxQRCodeSize 最大二维码尺寸
|
||||||
MaxQRCodeSize = 8192
|
MaxQRCodeSize = 8192
|
||||||
)
|
)
|
||||||
|
|
||||||
// QRCodeConfig 二维码配置结构
|
// QRCodeConfig 二维码配置结构
|
||||||
//
|
//
|
||||||
// 用于自定义二维码的外观和质量参数
|
// 用于自定义二维码的外观和质量参数
|
||||||
//
|
//
|
||||||
// 示例:
|
// 示例:
|
||||||
//
|
//
|
||||||
// config := &QRCodeConfig{
|
// config := &QRCodeConfig{
|
||||||
// Size: 512, // 尺寸512x512像素
|
// Size: 512, // 尺寸512x512像素
|
||||||
// ErrorLevel: QRCodeErrorLevelHigh, // 高级纠错
|
// ErrorLevel: QRCodeErrorLevelHigh, // 高级纠错
|
||||||
// ForegroundColor: color.RGBA{255, 0, 0, 255}, // 红色二维码
|
// ForegroundColor: color.RGBA{255, 0, 0, 255}, // 红色二维码
|
||||||
// BackgroundColor: color.White, // 白色背景
|
// BackgroundColor: color.White, // 白色背景
|
||||||
// }
|
// }
|
||||||
type QRCodeConfig struct {
|
type QRCodeConfig struct {
|
||||||
Size int // 尺寸(像素),范围:21-8192
|
Size int // 尺寸(像素),范围:21-8192
|
||||||
ErrorLevel QRCodeErrorLevel // 纠错级别,影响容错能力和复杂度
|
ErrorLevel QRCodeErrorLevel // 纠错级别,影响容错能力和复杂度
|
||||||
ForegroundColor color.Color // 前景色(二维码颜色),建议使用深色
|
ForegroundColor color.Color // 前景色(二维码颜色),建议使用深色
|
||||||
BackgroundColor color.Color // 背景色,建议使用浅色以保证对比度
|
BackgroundColor color.Color // 背景色,建议使用浅色以保证对比度
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultQRCodeConfig 返回默认配置
|
// DefaultQRCodeConfig 返回默认配置
|
||||||
//
|
//
|
||||||
// 默认配置适用于大多数场景:
|
// 默认配置适用于大多数场景:
|
||||||
// - 尺寸:256x256像素(适合手机扫描)
|
// - 尺寸:256x256像素(适合手机扫描)
|
||||||
// - 纠错级别:中级(15%容错)
|
// - 纠错级别:中级(15%容错)
|
||||||
// - 颜色:黑白配色(最佳识别率)
|
// - 颜色:黑白配色(最佳识别率)
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// *QRCodeConfig: 默认配置对象
|
// *QRCodeConfig: 默认配置对象
|
||||||
func DefaultQRCodeConfig() *QRCodeConfig {
|
func DefaultQRCodeConfig() *QRCodeConfig {
|
||||||
return &QRCodeConfig{
|
return &QRCodeConfig{
|
||||||
Size: DefaultQRCodeSize,
|
Size: DefaultQRCodeSize,
|
||||||
ErrorLevel: QRCodeErrorLevelMedium,
|
ErrorLevel: QRCodeErrorLevelMedium,
|
||||||
ForegroundColor: color.Black,
|
ForegroundColor: color.Black,
|
||||||
BackgroundColor: color.White,
|
BackgroundColor: color.White,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertErrorLevel 转换纠错级别为底层库的纠错级别
|
// convertErrorLevel 转换纠错级别为底层库的纠错级别
|
||||||
//
|
//
|
||||||
// 将自定义的纠错级别枚举转换为 go-qrcode 库所需的格式
|
// 将自定义的纠错级别枚举转换为 go-qrcode 库所需的格式
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// level: 自定义纠错级别
|
// level: 自定义纠错级别
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// qrcode.RecoveryLevel: go-qrcode库的纠错级别
|
// qrcode.RecoveryLevel: go-qrcode库的纠错级别
|
||||||
func convertErrorLevel(level QRCodeErrorLevel) qrcode.RecoveryLevel {
|
func convertErrorLevel(level QRCodeErrorLevel) qrcode.RecoveryLevel {
|
||||||
switch level {
|
switch level {
|
||||||
case QRCodeErrorLevelLow:
|
case QRCodeErrorLevelLow:
|
||||||
return qrcode.Low
|
return qrcode.Low
|
||||||
case QRCodeErrorLevelMedium:
|
case QRCodeErrorLevelMedium:
|
||||||
return qrcode.Medium
|
return qrcode.Medium
|
||||||
case QRCodeErrorLevelQuartile:
|
case QRCodeErrorLevelQuartile:
|
||||||
return qrcode.High
|
return qrcode.High
|
||||||
case QRCodeErrorLevelHigh:
|
case QRCodeErrorLevelHigh:
|
||||||
return qrcode.Highest
|
return qrcode.Highest
|
||||||
default:
|
default:
|
||||||
return qrcode.Medium
|
return qrcode.Medium
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateQRCode 生成二维码并保存为PNG文件
|
// GenerateQRCode 生成二维码并保存为PNG文件
|
||||||
//
|
//
|
||||||
// 这是最简单的二维码生成方法,适合快速生成标准黑白二维码。
|
// 这是最简单的二维码生成方法,适合快速生成标准黑白二维码。
|
||||||
// 使用中级纠错,黑白配色,PNG格式输出。
|
// 使用中级纠错,黑白配色,PNG格式输出。
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// content: 二维码内容(支持URL、文本、vCard、WiFi等格式)
|
// content: 二维码内容(支持URL、文本、vCard、WiFi等格式)
|
||||||
// filename: 保存的文件路径(.png文件)
|
// filename: 保存的文件路径(.png文件)
|
||||||
// size: 二维码尺寸(可选,单位:像素)
|
// size: 二维码尺寸(可选,单位:像素)
|
||||||
// - 不传参数:使用默认256x256
|
// - 不传参数:使用默认256x256
|
||||||
// - 传一个参数:使用指定尺寸
|
// - 传一个参数:使用指定尺寸
|
||||||
// - 有效范围:21-8192像素
|
// - 有效范围:21-8192像素
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// error: 错误信息,成功时返回nil
|
// error: 错误信息,成功时返回nil
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 内容越长,二维码越复杂,建议尺寸>=256
|
// - 内容越长,二维码越复杂,建议尺寸>=256
|
||||||
// - 文件权限为0644
|
// - 文件权限为0644
|
||||||
// - 会覆盖已存在的同名文件
|
// - 会覆盖已存在的同名文件
|
||||||
func GenerateQRCode(content, filename string, size ...int) error {
|
func GenerateQRCode(content, filename string, size ...int) error {
|
||||||
qrSize := DefaultQRCodeSize
|
qrSize := DefaultQRCodeSize
|
||||||
if len(size) > 0 {
|
if len(size) > 0 {
|
||||||
qrSize = size[0]
|
qrSize = size[0]
|
||||||
if qrSize < MinQRCodeSize || qrSize > MaxQRCodeSize {
|
if qrSize < MinQRCodeSize || qrSize > MaxQRCodeSize {
|
||||||
return fmt.Errorf("二维码尺寸必须在 %d 到 %d 之间", MinQRCodeSize, MaxQRCodeSize)
|
return fmt.Errorf("二维码尺寸必须在 %d 到 %d 之间", MinQRCodeSize, MaxQRCodeSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := qrcode.WriteFile(content, qrcode.Medium, qrSize, filename)
|
err := qrcode.WriteFile(content, qrcode.Medium, qrSize, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("生成二维码失败: %w", err)
|
return fmt.Errorf("生成二维码失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateQRCodeBytes 生成二维码字节数组(PNG格式)
|
// GenerateQRCodeBytes 生成二维码字节数组(PNG格式)
|
||||||
//
|
//
|
||||||
// 生成二维码的字节数组而不保存到文件,适合:
|
// 生成二维码的字节数组而不保存到文件,适合:
|
||||||
// - HTTP响应直接返回图片
|
// - HTTP响应直接返回图片
|
||||||
// - 存储到数据库
|
// - 存储到数据库
|
||||||
// - 通过网络传输
|
// - 通过网络传输
|
||||||
// - 进一步处理(如添加到PDF)
|
// - 进一步处理(如添加到PDF)
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// content: 二维码内容
|
// content: 二维码内容
|
||||||
// size: 二维码尺寸(可选,默认256)
|
// size: 二维码尺寸(可选,默认256)
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// []byte: PNG格式的图片字节数组
|
// []byte: PNG格式的图片字节数组
|
||||||
// error: 错误信息
|
// error: 错误信息
|
||||||
func GenerateQRCodeBytes(content string, size ...int) ([]byte, error) {
|
func GenerateQRCodeBytes(content string, size ...int) ([]byte, error) {
|
||||||
qrSize := DefaultQRCodeSize
|
qrSize := DefaultQRCodeSize
|
||||||
if len(size) > 0 {
|
if len(size) > 0 {
|
||||||
qrSize = size[0]
|
qrSize = size[0]
|
||||||
if qrSize < MinQRCodeSize || qrSize > MaxQRCodeSize {
|
if qrSize < MinQRCodeSize || qrSize > MaxQRCodeSize {
|
||||||
return nil, fmt.Errorf("二维码尺寸必须在 %d 到 %d 之间", MinQRCodeSize, MaxQRCodeSize)
|
return nil, fmt.Errorf("二维码尺寸必须在 %d 到 %d 之间", MinQRCodeSize, MaxQRCodeSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes, err := qrcode.Encode(content, qrcode.Medium, qrSize)
|
bytes, err := qrcode.Encode(content, qrcode.Medium, qrSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("生成二维码失败: %w", err)
|
return nil, fmt.Errorf("生成二维码失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes, nil
|
return bytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateQRCodeBase64 生成Base64编码的二维码字符串
|
// GenerateQRCodeBase64 生成Base64编码的二维码字符串
|
||||||
//
|
//
|
||||||
// 将二维码图片编码为Base64字符串,便于:
|
// 将二维码图片编码为Base64字符串,便于:
|
||||||
// - 存储到数据库的文本字段
|
// - 存储到数据库的文本字段
|
||||||
// - 通过JSON/XML传输
|
// - 通过JSON/XML传输
|
||||||
// - 避免二进制数据处理问题
|
// - 避免二进制数据处理问题
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// content: 二维码内容
|
// content: 二维码内容
|
||||||
// size: 二维码尺寸(可选,默认256)
|
// size: 二维码尺寸(可选,默认256)
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// string: Base64编码的字符串(不包含data:image/png;base64,前缀)
|
// string: Base64编码的字符串(不包含data:image/png;base64,前缀)
|
||||||
// error: 错误信息
|
// error: 错误信息
|
||||||
func GenerateQRCodeBase64(content string, size ...int) (string, error) {
|
func GenerateQRCodeBase64(content string, size ...int) (string, error) {
|
||||||
qrBytes, err := GenerateQRCodeBytes(content, size...)
|
qrBytes, err := GenerateQRCodeBytes(content, size...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
base64Str := base64.StdEncoding.EncodeToString(qrBytes)
|
base64Str := base64.StdEncoding.EncodeToString(qrBytes)
|
||||||
return base64Str, nil
|
return base64Str, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateQRCodeWithConfig 使用自定义配置生成二维码
|
// GenerateQRCodeWithConfig 使用自定义配置生成二维码
|
||||||
//
|
//
|
||||||
// 提供完全自定义的二维码生成能力,可以控制:
|
// 提供完全自定义的二维码生成能力,可以控制:
|
||||||
// - 尺寸大小
|
// - 尺寸大小
|
||||||
// - 纠错级别
|
// - 纠错级别
|
||||||
// - 前景色和背景色
|
// - 前景色和背景色
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// content: 二维码内容
|
// content: 二维码内容
|
||||||
// config: 二维码配置对象(nil时使用默认配置)
|
// config: 二维码配置对象(nil时使用默认配置)
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// []byte: PNG格式的字节数组
|
// []byte: PNG格式的字节数组
|
||||||
// error: 错误信息
|
// error: 错误信息
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 确保前景色和背景色有足够对比度
|
// - 确保前景色和背景色有足够对比度
|
||||||
// - 浅色前景配深色背景可能影响扫描
|
// - 浅色前景配深色背景可能影响扫描
|
||||||
func GenerateQRCodeWithConfig(content string, config *QRCodeConfig) ([]byte, error) {
|
func GenerateQRCodeWithConfig(content string, config *QRCodeConfig) ([]byte, error) {
|
||||||
if config == nil {
|
if config == nil {
|
||||||
config = DefaultQRCodeConfig()
|
config = DefaultQRCodeConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证尺寸
|
// 验证尺寸
|
||||||
if config.Size < MinQRCodeSize || config.Size > MaxQRCodeSize {
|
if config.Size < MinQRCodeSize || config.Size > MaxQRCodeSize {
|
||||||
return nil, fmt.Errorf("二维码尺寸必须在 %d 到 %d 之间", MinQRCodeSize, MaxQRCodeSize)
|
return nil, fmt.Errorf("二维码尺寸必须在 %d 到 %d 之间", MinQRCodeSize, MaxQRCodeSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建二维码对象
|
// 创建二维码对象
|
||||||
qr, err := qrcode.New(content, convertErrorLevel(config.ErrorLevel))
|
qr, err := qrcode.New(content, convertErrorLevel(config.ErrorLevel))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("创建二维码失败: %w", err)
|
return nil, fmt.Errorf("创建二维码失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置颜色
|
// 设置颜色
|
||||||
qr.ForegroundColor = config.ForegroundColor
|
qr.ForegroundColor = config.ForegroundColor
|
||||||
qr.BackgroundColor = config.BackgroundColor
|
qr.BackgroundColor = config.BackgroundColor
|
||||||
|
|
||||||
// 生成PNG
|
// 生成PNG
|
||||||
pngBytes, err := qr.PNG(config.Size)
|
pngBytes, err := qr.PNG(config.Size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("生成PNG失败: %w", err)
|
return nil, fmt.Errorf("生成PNG失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pngBytes, nil
|
return pngBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateQRCodeWithLogo 生成带Logo的二维码
|
// GenerateQRCodeWithLogo 生成带Logo的二维码
|
||||||
//
|
//
|
||||||
// 在二维码中心嵌入Logo图片,Logo会占据二维码约1/5的区域。
|
// 在二维码中心嵌入Logo图片,Logo会占据二维码约1/5的区域。
|
||||||
// 使用高级纠错以确保Logo不影响二维码的可读性。
|
// 使用高级纠错以确保Logo不影响二维码的可读性。
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// content: 二维码内容
|
// content: 二维码内容
|
||||||
// logoPath: Logo图片文件路径(支持PNG、JPEG等格式)
|
// logoPath: Logo图片文件路径(支持PNG、JPEG等格式)
|
||||||
// size: 二维码尺寸(可选,默认256,建议>=512以保证清晰度)
|
// size: 二维码尺寸(可选,默认256,建议>=512以保证清晰度)
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// []byte: PNG格式的字节数组
|
// []byte: PNG格式的字节数组
|
||||||
// error: 错误信息
|
// error: 错误信息
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - Logo会自动缩放到二维码的1/5大小
|
// - Logo会自动缩放到二维码的1/5大小
|
||||||
// - 建议Logo使用正方形图片
|
// - 建议Logo使用正方形图片
|
||||||
// - 使用高级纠错级别(~30%容错)
|
// - 使用高级纠错级别(~30%容错)
|
||||||
// - Logo会覆盖二维码中心区域
|
// - Logo会覆盖二维码中心区域
|
||||||
// - 建议二维码尺寸>=512以保证Logo清晰
|
// - 建议二维码尺寸>=512以保证Logo清晰
|
||||||
// - Logo文件必须存在且可读取
|
// - Logo文件必须存在且可读取
|
||||||
func GenerateQRCodeWithLogo(content, logoPath string, size ...int) ([]byte, error) {
|
func GenerateQRCodeWithLogo(content, logoPath string, size ...int) ([]byte, error) {
|
||||||
qrSize := DefaultQRCodeSize
|
qrSize := DefaultQRCodeSize
|
||||||
if len(size) > 0 {
|
if len(size) > 0 {
|
||||||
qrSize = size[0]
|
qrSize = size[0]
|
||||||
if qrSize < MinQRCodeSize || qrSize > MaxQRCodeSize {
|
if qrSize < MinQRCodeSize || qrSize > MaxQRCodeSize {
|
||||||
return nil, fmt.Errorf("二维码尺寸必须在 %d 到 %d 之间", MinQRCodeSize, MaxQRCodeSize)
|
return nil, fmt.Errorf("二维码尺寸必须在 %d 到 %d 之间", MinQRCodeSize, MaxQRCodeSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成基础二维码
|
// 生成基础二维码
|
||||||
qr, err := qrcode.New(content, qrcode.High)
|
qr, err := qrcode.New(content, qrcode.High)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("创建二维码失败: %w", err)
|
return nil, fmt.Errorf("创建二维码失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成二维码图像
|
// 生成二维码图像
|
||||||
qrImage := qr.Image(qrSize)
|
qrImage := qr.Image(qrSize)
|
||||||
|
|
||||||
// 读取Logo图片
|
// 读取Logo图片
|
||||||
logoFile, err := os.Open(logoPath)
|
logoFile, err := os.Open(logoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("打开Logo文件失败: %w", err)
|
return nil, fmt.Errorf("打开Logo文件失败: %w", err)
|
||||||
}
|
}
|
||||||
defer logoFile.Close()
|
defer logoFile.Close()
|
||||||
|
|
||||||
logoImage, _, err := image.Decode(logoFile)
|
logoImage, _, err := image.Decode(logoFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("解码Logo图片失败: %w", err)
|
return nil, fmt.Errorf("解码Logo图片失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算Logo位置和大小(Logo占二维码的1/5)
|
// 计算Logo位置和大小(Logo占二维码的1/5)
|
||||||
logoSize := qrSize / 5
|
logoSize := qrSize / 5
|
||||||
logoX := (qrSize - logoSize) / 2
|
logoX := (qrSize - logoSize) / 2
|
||||||
logoY := (qrSize - logoSize) / 2
|
logoY := (qrSize - logoSize) / 2
|
||||||
|
|
||||||
// 创建最终图像
|
// 创建最终图像
|
||||||
finalImage := image.NewRGBA(qrImage.Bounds())
|
finalImage := image.NewRGBA(qrImage.Bounds())
|
||||||
|
|
||||||
// 绘制二维码
|
// 绘制二维码
|
||||||
for y := 0; y < qrSize; y++ {
|
for y := 0; y < qrSize; y++ {
|
||||||
for x := 0; x < qrSize; x++ {
|
for x := 0; x < qrSize; x++ {
|
||||||
finalImage.Set(x, y, qrImage.At(x, y))
|
finalImage.Set(x, y, qrImage.At(x, y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制Logo
|
// 绘制Logo
|
||||||
logoOriginalBounds := logoImage.Bounds()
|
logoOriginalBounds := logoImage.Bounds()
|
||||||
for y := 0; y < logoSize; y++ {
|
for y := range logoSize {
|
||||||
for x := 0; x < logoSize; x++ {
|
for x := range logoSize {
|
||||||
// 计算原始Logo的对应像素
|
// 计算原始Logo的对应像素
|
||||||
origX := x * logoOriginalBounds.Dx() / logoSize
|
origX := x * logoOriginalBounds.Dx() / logoSize
|
||||||
origY := y * logoOriginalBounds.Dy() / logoSize
|
origY := y * logoOriginalBounds.Dy() / logoSize
|
||||||
finalImage.Set(logoX+x, logoY+y, logoImage.At(origX, origY))
|
finalImage.Set(logoX+x, logoY+y, logoImage.At(origX, origY))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 转换为PNG字节
|
// 转换为PNG字节
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := png.Encode(&buf, finalImage); err != nil {
|
if err := png.Encode(&buf, finalImage); err != nil {
|
||||||
return nil, fmt.Errorf("编码PNG失败: %w", err)
|
return nil, fmt.Errorf("编码PNG失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveQRCodeBytes 保存二维码字节数组到文件
|
// SaveQRCodeBytes 保存二维码字节数组到文件
|
||||||
//
|
//
|
||||||
// 将二维码字节数组保存为PNG文件,常与 GenerateQRCodeBytes 或
|
// 将二维码字节数组保存为PNG文件,常与 GenerateQRCodeBytes 或
|
||||||
// GenerateQRCodeWithConfig 配合使用。
|
// GenerateQRCodeWithConfig 配合使用。
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// data: PNG格式的二维码字节数组
|
// data: PNG格式的二维码字节数组
|
||||||
// filename: 保存的文件路径
|
// filename: 保存的文件路径
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// error: 错误信息
|
// error: 错误信息
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 文件权限为0644
|
// - 文件权限为0644
|
||||||
// - 会覆盖已存在的文件
|
// - 会覆盖已存在的文件
|
||||||
// - 确保目录已存在
|
// - 确保目录已存在
|
||||||
func SaveQRCodeBytes(data []byte, filename string) error {
|
func SaveQRCodeBytes(data []byte, filename string) error {
|
||||||
if err := os.WriteFile(filename, data, 0644); err != nil {
|
if err := os.WriteFile(filename, data, 0644); err != nil {
|
||||||
return fmt.Errorf("保存文件失败: %w", err)
|
return fmt.Errorf("保存文件失败: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateQRCodeDataURL 生成Data URL格式的二维码
|
// GenerateQRCodeDataURL 生成Data URL格式的二维码
|
||||||
//
|
//
|
||||||
// 生成可以直接用于HTML <img>标签的Data URL格式字符串。
|
// 生成可以直接用于HTML <img>标签的Data URL格式字符串。
|
||||||
// Data URL包含了完整的图片数据,无需额外的图片文件。
|
// Data URL包含了完整的图片数据,无需额外的图片文件。
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// content: 二维码内容
|
// content: 二维码内容
|
||||||
// size: 二维码尺寸(可选,默认256)
|
// size: 二维码尺寸(可选,默认256)
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// string: Data URL格式字符串(包含data:image/png;base64,前缀)
|
// string: Data URL格式字符串(包含data:image/png;base64,前缀)
|
||||||
// error: 错误信息
|
// error: 错误信息
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - Data URL字符串较长,不适合存储到数据库
|
// - Data URL字符串较长,不适合存储到数据库
|
||||||
// - 适合临时显示、前端渲染等场景
|
// - 适合临时显示、前端渲染等场景
|
||||||
// - 某些老旧浏览器可能不支持
|
// - 某些老旧浏览器可能不支持
|
||||||
func GenerateQRCodeDataURL(content string, size ...int) (string, error) {
|
func GenerateQRCodeDataURL(content string, size ...int) (string, error) {
|
||||||
qrBytes, err := GenerateQRCodeBytes(content, size...)
|
qrBytes, err := GenerateQRCodeBytes(content, size...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
base64Str := base64.StdEncoding.EncodeToString(qrBytes)
|
base64Str := base64.StdEncoding.EncodeToString(qrBytes)
|
||||||
dataURL := fmt.Sprintf("data:image/png;base64,%s", base64Str)
|
dataURL := fmt.Sprintf("data:image/png;base64,%s", base64Str)
|
||||||
return dataURL, nil
|
return dataURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchGenerateQRCode 批量生成二维码文件
|
// BatchGenerateQRCode 批量生成二维码文件
|
||||||
//
|
//
|
||||||
// 一次性生成多个二维码文件,适合:
|
// 一次性生成多个二维码文件,适合:
|
||||||
// - 批量生成产品二维码
|
// - 批量生成产品二维码
|
||||||
// - 生成多个用户的会员卡
|
// - 生成多个用户的会员卡
|
||||||
// - 批量生成门票、优惠券等
|
// - 批量生成门票、优惠券等
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// items: map[内容]文件名,例如:map["产品A":"qr_a.png", "产品B":"qr_b.png"]
|
// items: map[内容]文件名,例如:map["产品A":"qr_a.png", "产品B":"qr_b.png"]
|
||||||
// size: 二维码尺寸(可选,默认256,所有二维码使用相同尺寸)
|
// size: 二维码尺寸(可选,默认256,所有二维码使用相同尺寸)
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
//
|
//
|
||||||
// []string: 失败的文件名列表(成功时为nil)
|
// []string: 失败的文件名列表(成功时为nil)
|
||||||
// error: 错误信息(部分失败时返回错误,但成功的文件已生成)
|
// error: 错误信息(部分失败时返回错误,但成功的文件已生成)
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 即使部分失败,成功的二维码仍会生成
|
// - 即使部分失败,成功的二维码仍会生成
|
||||||
// - 建议检查返回的failed列表以确定哪些失败了
|
// - 建议检查返回的failed列表以确定哪些失败了
|
||||||
// - 大批量生成时注意磁盘空间
|
// - 大批量生成时注意磁盘空间
|
||||||
func BatchGenerateQRCode(items map[string]string, size ...int) ([]string, error) {
|
func BatchGenerateQRCode(items map[string]string, size ...int) ([]string, error) {
|
||||||
var failed []string
|
var failed []string
|
||||||
qrSize := DefaultQRCodeSize
|
qrSize := DefaultQRCodeSize
|
||||||
if len(size) > 0 {
|
if len(size) > 0 {
|
||||||
qrSize = size[0]
|
qrSize = size[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
for content, filename := range items {
|
for content, filename := range items {
|
||||||
err := GenerateQRCode(content, filename, qrSize)
|
err := GenerateQRCode(content, filename, qrSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failed = append(failed, filename)
|
failed = append(failed, filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(failed) > 0 {
|
if len(failed) > 0 {
|
||||||
return failed, fmt.Errorf("有 %d 个二维码生成失败", len(failed))
|
return failed, fmt.Errorf("有 %d 个二维码生成失败", len(failed))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ func RandomString(l int) string {
|
|||||||
str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
|
str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
|
||||||
bytes := []byte(str)
|
bytes := []byte(str)
|
||||||
var result []byte = make([]byte, 0, l)
|
var result []byte = make([]byte, 0, l)
|
||||||
for i := 0; i < l; i++ {
|
for range l {
|
||||||
result = append(result, bytes[rand.IntN(len(bytes))])
|
result = append(result, bytes[rand.IntN(len(bytes))])
|
||||||
}
|
}
|
||||||
return string(result)
|
return string(result)
|
||||||
@@ -20,7 +20,7 @@ func RandomPureString(l int) string {
|
|||||||
str := "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
|
str := "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
|
||||||
bytes := []byte(str)
|
bytes := []byte(str)
|
||||||
var result []byte = make([]byte, 0, l)
|
var result []byte = make([]byte, 0, l)
|
||||||
for i := 0; i < l; i++ {
|
for range l {
|
||||||
result = append(result, bytes[rand.IntN(len(bytes))])
|
result = append(result, bytes[rand.IntN(len(bytes))])
|
||||||
}
|
}
|
||||||
return string(result)
|
return string(result)
|
||||||
@@ -31,7 +31,7 @@ func RandomPureUpString(l int) string {
|
|||||||
str := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
str := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
bytes := []byte(str)
|
bytes := []byte(str)
|
||||||
var result []byte = make([]byte, 0, l)
|
var result []byte = make([]byte, 0, l)
|
||||||
for i := 0; i < l; i++ {
|
for range l {
|
||||||
result = append(result, bytes[rand.IntN(len(bytes))])
|
result = append(result, bytes[rand.IntN(len(bytes))])
|
||||||
}
|
}
|
||||||
return string(result)
|
return string(result)
|
||||||
@@ -42,7 +42,7 @@ func RandomNumber(l int) string {
|
|||||||
str := "0123456789"
|
str := "0123456789"
|
||||||
bytes := []byte(str)
|
bytes := []byte(str)
|
||||||
var result []byte
|
var result []byte
|
||||||
for i := 0; i < l; i++ {
|
for range l {
|
||||||
result = append(result, bytes[rand.IntN(len(bytes))])
|
result = append(result, bytes[rand.IntN(len(bytes))])
|
||||||
}
|
}
|
||||||
return string(result)
|
return string(result)
|
||||||
|
|||||||
Reference in New Issue
Block a user