mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-11-14 05:03:49 +08:00
发布代码生成、更新20+表单组件,优化数据字典,gf版本更新到2.3.1
This commit is contained in:
@@ -16,7 +16,7 @@ import (
|
||||
func IsExceptAuth(ctx context.Context, path string) bool {
|
||||
var pathList []string
|
||||
|
||||
except, _ := g.Cfg().Get(ctx, "router.admin.exceptAuth")
|
||||
except := g.Cfg().MustGet(ctx, "router.admin.exceptAuth")
|
||||
pathList = except.Strings()
|
||||
|
||||
for i := 0; i < len(pathList); i++ {
|
||||
@@ -32,7 +32,7 @@ func IsExceptAuth(ctx context.Context, path string) bool {
|
||||
func IsExceptLogin(ctx context.Context, path string) bool {
|
||||
var pathList []string
|
||||
|
||||
except, _ := g.Cfg().Get(ctx, "router.admin.exceptLogin")
|
||||
except := g.Cfg().MustGet(ctx, "router.admin.exceptLogin")
|
||||
pathList = except.Strings()
|
||||
|
||||
for i := 0; i < len(pathList); i++ {
|
||||
|
||||
@@ -69,12 +69,11 @@ func RandomCreateBytes(n int, alphabets ...byte) []byte {
|
||||
|
||||
// GetStack 格式化错误的堆栈信息
|
||||
func GetStack(err error) []string {
|
||||
stackList := gstr.Split(gerror.Stack(err), "\n")
|
||||
for i := 0; i < len(stackList); i++ {
|
||||
stackList[i] = gstr.Replace(stackList[i], "\t", "--> ")
|
||||
stack := gstr.Split(gerror.Stack(err), "\n")
|
||||
for i := 0; i < len(stack); i++ {
|
||||
stack[i] = gstr.Replace(stack[i], "\t", "--> ")
|
||||
}
|
||||
|
||||
return stackList
|
||||
return stack
|
||||
}
|
||||
|
||||
// SubstrAfter 截取指定字符后的内容
|
||||
|
||||
@@ -6,12 +6,25 @@
|
||||
//
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"hotgo/utility/validate"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var (
|
||||
descTags = []string{"description", "dc", "json"} // 实体描述标签
|
||||
fieldTags = []string{"json"} // 实体字段名称映射
|
||||
)
|
||||
|
||||
// UniqueSliceInt64 切片去重
|
||||
func UniqueSliceInt64(languages []int64) []int64 {
|
||||
result := make([]int64, 0, len(languages))
|
||||
temp := map[int64]struct{}{}
|
||||
for _, item := range languages {
|
||||
if _, ok := temp[item]; !ok { //如果字典中找不到元素,ok=false,!ok为true,就往切片中append元素。
|
||||
if _, ok := temp[item]; !ok {
|
||||
temp[item] = struct{}{}
|
||||
result = append(result, item)
|
||||
}
|
||||
@@ -19,28 +32,130 @@ func UniqueSliceInt64(languages []int64) []int64 {
|
||||
return result
|
||||
}
|
||||
|
||||
// InSliceInt64 元素是否存在于切片中
|
||||
func InSliceInt64(slice []int64, key int64) bool {
|
||||
if len(slice) == 0 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(slice); i++ {
|
||||
if slice[i] == key {
|
||||
return true
|
||||
// UniqueSliceString 切片去重
|
||||
func UniqueSliceString(languages []string) []string {
|
||||
result := make([]string, 0, len(languages))
|
||||
temp := map[string]struct{}{}
|
||||
for _, item := range languages {
|
||||
if _, ok := temp[item]; !ok {
|
||||
temp[item] = struct{}{}
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return false
|
||||
return result
|
||||
}
|
||||
|
||||
// InSliceInt 元素是否存在于切片中
|
||||
func InSliceInt(slice []int, key int) bool {
|
||||
if len(slice) == 0 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(slice); i++ {
|
||||
if slice[i] == key {
|
||||
return true
|
||||
// UnderlineToUpperCamelCase 下划线单词转为大写驼峰单词
|
||||
func UnderlineToUpperCamelCase(s string) string {
|
||||
s = strings.Replace(s, "_", " ", -1)
|
||||
s = strings.Title(s)
|
||||
return strings.Replace(s, " ", "", -1)
|
||||
}
|
||||
|
||||
// UnderlineToLowerCamelCase 下划线单词转为小写驼峰单词
|
||||
func UnderlineToLowerCamelCase(s string) string {
|
||||
s = UnderlineToUpperCamelCase(s)
|
||||
return string(unicode.ToLower(rune(s[0]))) + s[1:]
|
||||
}
|
||||
|
||||
//CamelCaseToUnderline 驼峰单词转下划线单词
|
||||
func CamelCaseToUnderline(s string) string {
|
||||
var output []rune
|
||||
for i, r := range s {
|
||||
if i == 0 {
|
||||
output = append(output, unicode.ToLower(r))
|
||||
} else {
|
||||
if unicode.IsUpper(r) {
|
||||
output = append(output, '_')
|
||||
}
|
||||
|
||||
output = append(output, unicode.ToLower(r))
|
||||
}
|
||||
}
|
||||
return false
|
||||
return string(output)
|
||||
}
|
||||
|
||||
// GetEntityFieldTags 获取实体中的字段名称
|
||||
func GetEntityFieldTags(entity interface{}) (tags []string, err error) {
|
||||
var formRef = reflect.TypeOf(entity)
|
||||
for i := 0; i < formRef.NumField(); i++ {
|
||||
field := formRef.Field(i)
|
||||
if field.Type.Kind() == reflect.Struct {
|
||||
addTags, err := reflectTag(field.Type, fieldTags, []string{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tags = append(tags, addTags...)
|
||||
continue
|
||||
}
|
||||
tags = append(tags, reflectTagName(field, fieldTags, true))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetEntityDescTags 获取实体中的描述标签
|
||||
func GetEntityDescTags(entity interface{}) (tags []string, err error) {
|
||||
var formRef = reflect.TypeOf(entity)
|
||||
for i := 0; i < formRef.NumField(); i++ {
|
||||
field := formRef.Field(i)
|
||||
if field.Type.Kind() == reflect.Struct {
|
||||
addTags, err := reflectTag(field.Type, descTags, []string{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tags = append(tags, addTags...)
|
||||
continue
|
||||
}
|
||||
tags = append(tags, reflectTagName(field, descTags, true))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// reflectTag 层级递增解析tag
|
||||
func reflectTag(reflectType reflect.Type, filterTags []string, tags []string) ([]string, error) {
|
||||
if reflectType.Kind() == reflect.Ptr {
|
||||
return nil, gerror.Newf("reflect type do not support reflect.Ptr yet, reflectType:%+v", reflectType)
|
||||
}
|
||||
if reflectType.Kind() != reflect.Struct {
|
||||
return nil, nil
|
||||
}
|
||||
for i := 0; i < reflectType.NumField(); i++ {
|
||||
tag := reflectTagName(reflectType.Field(i), filterTags, false)
|
||||
if tag == "" {
|
||||
addTags, err := reflectTag(reflectType.Field(i).Type, filterTags, tags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tags = append(tags, addTags...)
|
||||
continue
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
// reflectTagName 解析实体中的描述标签,优先级:description > dc > json > Name
|
||||
func reflectTagName(field reflect.StructField, filterTags []string, isDef bool) string {
|
||||
if validate.InSliceString(filterTags, "description") {
|
||||
if description, ok := field.Tag.Lookup("description"); ok && description != "" {
|
||||
return description
|
||||
}
|
||||
}
|
||||
|
||||
if validate.InSliceString(filterTags, "dc") {
|
||||
if dc, ok := field.Tag.Lookup("dc"); ok && dc != "" {
|
||||
return dc
|
||||
}
|
||||
}
|
||||
|
||||
if validate.InSliceString(filterTags, "json") {
|
||||
if jsonName, ok := field.Tag.Lookup("json"); ok && jsonName != "" {
|
||||
return jsonName
|
||||
}
|
||||
}
|
||||
|
||||
if !isDef {
|
||||
return ""
|
||||
}
|
||||
return field.Name
|
||||
}
|
||||
|
||||
42
server/utility/encrypt/aes.go
Normal file
42
server/utility/encrypt/aes.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// Package encrypt
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/forgoer/openssl"
|
||||
)
|
||||
|
||||
// AesECBEncrypt 加密
|
||||
func AesECBEncrypt(src, key []byte) (dst []byte, err error) {
|
||||
return openssl.AesECBEncrypt(src, key, openssl.PKCS7_PADDING)
|
||||
}
|
||||
|
||||
// AesECBDecrypt 解密
|
||||
func AesECBDecrypt(src, key []byte) (dst []byte, err error) {
|
||||
return openssl.AesECBDecrypt(src, key, openssl.PKCS7_PADDING)
|
||||
}
|
||||
|
||||
// MustAesECBEncryptToString
|
||||
// Return the encryption result directly. Panic error
|
||||
func MustAesECBEncryptToString(bytCipher, key string) string {
|
||||
dst, err := AesECBEncrypt([]byte(bytCipher), []byte(key))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(dst)
|
||||
}
|
||||
|
||||
// MustAesECBDecryptToString
|
||||
// Directly return decryption result, panic error
|
||||
func MustAesECBDecryptToString(bytCipher, key string) string {
|
||||
dst, err := AesECBDecrypt([]byte(bytCipher), []byte(key))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(dst)
|
||||
}
|
||||
@@ -17,6 +17,11 @@ func Md5ToString(str string) string {
|
||||
return fmt.Sprintf("%x", md5.Sum([]byte(str)))
|
||||
}
|
||||
|
||||
// Md5 生成md5
|
||||
func Md5(b []byte) string {
|
||||
return fmt.Sprintf("%x", md5.Sum(b))
|
||||
}
|
||||
|
||||
func Hash32(b []byte) uint32 {
|
||||
h := fnv.New32a()
|
||||
h.Write(b)
|
||||
|
||||
@@ -7,42 +7,63 @@
|
||||
package excel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/model"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExportByStruct(w *ghttp.ResponseWriter, titleList []string, data []interface{}, fileName string, sheetName string) error {
|
||||
var (
|
||||
// 单元格表头
|
||||
char = []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
|
||||
// 默认行样式
|
||||
defaultRowStyle = `{"font":{"color":"#666666","size":13,"family":"arial"},"alignment":{"vertical":"center","horizontal":"center"}}`
|
||||
)
|
||||
|
||||
// ExportByStructs 导出切片结构体
|
||||
func ExportByStructs(ctx context.Context, tags []string, list interface{}, fileName string, sheetName string) (err error) {
|
||||
f := excelize.NewFile()
|
||||
f.SetSheetName("Sheet1", sheetName)
|
||||
_ = f.SetRowHeight("Sheet1", 1, 30)
|
||||
header := make([]string, 0)
|
||||
for _, v := range titleList {
|
||||
for _, v := range tags {
|
||||
header = append(header, v)
|
||||
}
|
||||
|
||||
rowStyleID, _ := f.NewStyle(`{"font":{"color":"#666666","size":13,"family":"arial"},"alignment":{"vertical":"center","horizontal":"center"}}`)
|
||||
rowStyleID, _ := f.NewStyle(defaultRowStyle)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = f.SetSheetRow(sheetName, "A1", &header)
|
||||
_ = f.SetRowHeight("Sheet1", 1, 30)
|
||||
length := len(titleList)
|
||||
headStyle := letter(length)
|
||||
var lastRow string
|
||||
var widthRow string
|
||||
|
||||
var (
|
||||
length = len(tags)
|
||||
headStyle = letter(length)
|
||||
lastRow string
|
||||
widthRow string
|
||||
)
|
||||
|
||||
for k, v := range headStyle {
|
||||
if k == length-1 {
|
||||
lastRow = fmt.Sprintf("%s1", v)
|
||||
widthRow = v
|
||||
}
|
||||
}
|
||||
if err := f.SetColWidth(sheetName, "A", widthRow, 30); err != nil {
|
||||
if err = f.SetColWidth(sheetName, "A", widthRow, 30); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rowNum := 1
|
||||
for _, v := range data {
|
||||
var rowNum = 1
|
||||
for _, v := range gconv.Interfaces(list) {
|
||||
t := reflect.TypeOf(v)
|
||||
value := reflect.ValueOf(v)
|
||||
row := make([]interface{}, 0)
|
||||
@@ -51,32 +72,60 @@ func ExportByStruct(w *ghttp.ResponseWriter, titleList []string, data []interfac
|
||||
row = append(row, val)
|
||||
}
|
||||
rowNum++
|
||||
err := f.SetSheetRow(sheetName, "A"+gconv.String(rowNum), &row)
|
||||
_ = f.SetCellStyle(sheetName, fmt.Sprintf("A%d", rowNum), fmt.Sprintf("%s", lastRow), rowStyleID)
|
||||
if err != nil {
|
||||
if err = f.SetSheetRow(sheetName, "A"+gconv.String(rowNum), &row); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = f.SetCellStyle(sheetName, fmt.Sprintf("A%d", rowNum), fmt.Sprintf("%s", lastRow), rowStyleID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
disposition := fmt.Sprintf("attachment; filename=%s.xlsx", url.QueryEscape(fileName))
|
||||
|
||||
// 强转类型
|
||||
writer := ghttp.RequestFromCtx(ctx).Response.Writer
|
||||
w, ok := interface{}(writer).(*ghttp.ResponseWriter)
|
||||
if !ok {
|
||||
return gerror.New("Response.Writer uninitialized!")
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", disposition)
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s.xlsx", url.QueryEscape(fileName)))
|
||||
w.Header().Set("Content-Transfer-Encoding", "binary")
|
||||
w.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
|
||||
|
||||
err := f.Write(w)
|
||||
if err != nil {
|
||||
if err := f.Write(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 加入到上下文
|
||||
contexts.SetResponse(ctx, &model.Response{
|
||||
Code: gcode.CodeOK.Code(),
|
||||
Message: "export successfully!",
|
||||
Timestamp: time.Now().Unix(),
|
||||
TraceID: gctx.CtxId(ctx),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Letter 遍历a-z
|
||||
// letter 生成完整的表头
|
||||
func letter(length int) []string {
|
||||
var str []string
|
||||
for i := 0; i < length; i++ {
|
||||
str = append(str, string(rune('A'+i)))
|
||||
str = append(str, numToChars(i))
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// numToChars 将数字转换为具体的表格表头名称
|
||||
func numToChars(num int) string {
|
||||
var cols string
|
||||
v := num
|
||||
for v > 0 {
|
||||
k := v % 26
|
||||
if k == 0 {
|
||||
k = 26
|
||||
}
|
||||
v = (v - k) / 26
|
||||
cols = char[k] + cols
|
||||
}
|
||||
return cols
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"hotgo/utility/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -111,3 +112,9 @@ func DirSize(dirname string) string {
|
||||
|
||||
return format.FileSize(ss)
|
||||
}
|
||||
|
||||
func MergeAbs(path string, fileName ...string) string {
|
||||
var paths = []string{gfile.RealPath(path)}
|
||||
paths = append(paths, fileName...)
|
||||
return gfile.Join(paths...)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ const (
|
||||
var (
|
||||
// 图片类型
|
||||
imgType = g.MapStrStr{
|
||||
"jpeg": "image/jpeg",
|
||||
"jpg": "image/jpeg",
|
||||
"png": "image/png",
|
||||
"gif": "image/gif",
|
||||
@@ -107,7 +108,7 @@ func GetFileType(ext string) (string, error) {
|
||||
if mime, ok := videoType[ext]; ok {
|
||||
return mime, nil
|
||||
}
|
||||
return "", gerror.New("Invalid file type")
|
||||
return "", gerror.Newf("Invalid file type:%v", ext)
|
||||
}
|
||||
|
||||
// GetFileKind 获取文件所属分类
|
||||
|
||||
@@ -1,18 +1,48 @@
|
||||
// Package tree
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var pidName = "pid"
|
||||
var (
|
||||
pidName = "pid"
|
||||
treeBeginCut = "tr_" // 树标识开头
|
||||
treeEndCut = " " // 树标识结尾
|
||||
)
|
||||
|
||||
// GenTree 生成关系树 参考:https://blog.csdn.net/weixin_51546892/article/details/122876793
|
||||
// GenLabel 生成关系树标识
|
||||
func GenLabel(basic string, appendId int64) string {
|
||||
return fmt.Sprintf("%v%v%v%v", basic, treeBeginCut, appendId, treeEndCut)
|
||||
}
|
||||
|
||||
// GetIds 获取上级ID集合
|
||||
func GetIds(tree string) (ids []int64) {
|
||||
idsStr := strings.Split(tree, treeEndCut)
|
||||
if len(idsStr) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range idsStr {
|
||||
newId := gconv.Int64(strings.ReplaceAll(v, treeBeginCut, ""))
|
||||
if newId > 0 {
|
||||
ids = append(ids, newId)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/////////////////////////// 转换类
|
||||
|
||||
// GenTree 生成关系树
|
||||
func GenTree(menus []map[string]interface{}) (realMenu []map[string]interface{}) {
|
||||
if len(menus) < 1 {
|
||||
return nil
|
||||
|
||||
69
server/utility/url/url.go
Normal file
69
server/utility/url/url.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package url
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/utility/validate"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UriToMap 将URL参数转为map
|
||||
func UriToMap(uri string) g.MapStrStr {
|
||||
m := make(map[string]string)
|
||||
if len(uri) < 1 {
|
||||
return nil
|
||||
}
|
||||
if uri[0:1] == "?" {
|
||||
uri = uri[1:]
|
||||
}
|
||||
pars := strings.Split(uri, "&")
|
||||
for _, par := range pars {
|
||||
kv := strings.Split(par, "=")
|
||||
m[kv[0]] = kv[1]
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MapToUri 将map转为URL参数
|
||||
func MapToUri(params g.MapStrStr) string {
|
||||
escape := ""
|
||||
for k, v := range params {
|
||||
if escape != "" {
|
||||
escape = escape + "&"
|
||||
}
|
||||
escape = escape + k + "=" + v
|
||||
}
|
||||
return escape
|
||||
}
|
||||
|
||||
// GetAddr 获取请求中的请求地址,协议+域名/IP:端口
|
||||
func GetAddr(ctx context.Context) string {
|
||||
r := ghttp.RequestFromCtx(ctx)
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
var (
|
||||
scheme = "http"
|
||||
proto = r.Header.Get("X-Forwarded-Proto")
|
||||
)
|
||||
if r.TLS != nil || gstr.Equal(proto, "https") {
|
||||
scheme = "https"
|
||||
}
|
||||
return fmt.Sprintf(`%s://%s`, scheme, r.Host)
|
||||
}
|
||||
|
||||
// GetDomain 获取请求中的域名,如果请求不是域名则返回空
|
||||
func GetDomain(ctx context.Context) string {
|
||||
r := ghttp.RequestFromCtx(ctx)
|
||||
if r == nil {
|
||||
g.Log().Warningf(ctx, "GetDomain ctx not request")
|
||||
return ""
|
||||
}
|
||||
if validate.IsDNSName(r.Host) {
|
||||
return r.Host
|
||||
}
|
||||
return ""
|
||||
}
|
||||
24
server/utility/validate/filter.go
Normal file
24
server/utility/validate/filter.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Package validate
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package validate
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type Filter interface {
|
||||
// Filter gf效验规则 https://goframe.org/pages/viewpage.action?pageId=1114367
|
||||
Filter(ctx context.Context) error
|
||||
}
|
||||
|
||||
// PreFilter 预过滤
|
||||
func PreFilter(ctx context.Context, in interface{}) error {
|
||||
if c, ok := in.(Filter); ok {
|
||||
return c.Filter(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
72
server/utility/validate/include.go
Normal file
72
server/utility/validate/include.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// Package validate
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package validate
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InSameDay 是否为同一天
|
||||
func InSameDay(t1, t2 int64) bool {
|
||||
y1, m1, d1 := time.Unix(t1, 0).Date()
|
||||
y2, m2, d2 := time.Unix(t2, 0).Date()
|
||||
return y1 == y2 && m1 == m2 && d1 == d2
|
||||
}
|
||||
|
||||
// InSameMinute 是否为同一分钟
|
||||
func InSameMinute(t1, t2 int64) bool {
|
||||
d1 := time.Unix(t1, 0).Format("2006-01-02 15:04")
|
||||
d2 := time.Unix(t2, 0).Format("2006-01-02 15:04")
|
||||
return d1 == d2
|
||||
}
|
||||
|
||||
// InSliceExistStr 判断字符或切片字符是否存在指定字符
|
||||
func InSliceExistStr(elems interface{}, search string) bool {
|
||||
switch elems.(type) {
|
||||
case []string:
|
||||
elem := gconv.Strings(elems)
|
||||
for i := 0; i < len(elem); i++ {
|
||||
if gconv.String(elem[i]) == search {
|
||||
return true
|
||||
}
|
||||
}
|
||||
default:
|
||||
return gconv.String(elems) == search
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InSliceInt64 元素是否存在于切片中
|
||||
func InSliceInt64(slice []int64, key int64) bool {
|
||||
if len(slice) == 0 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(slice); i++ {
|
||||
if slice[i] == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func InSliceInt(slice []int, key int) bool {
|
||||
if len(slice) == 0 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(slice); i++ {
|
||||
if slice[i] == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func InSliceString(slice []string, key string) bool {
|
||||
return gstr.InArray(slice, key)
|
||||
}
|
||||
@@ -7,13 +7,37 @@
|
||||
package validate
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"net"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
func IsDNSName(s string) bool {
|
||||
DNSName := `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$`
|
||||
rxDNSName := regexp.MustCompile(DNSName)
|
||||
return s != "" && rxDNSName.MatchString(s)
|
||||
}
|
||||
|
||||
func IsHTTPS(ctx context.Context) bool {
|
||||
r := ghttp.RequestFromCtx(ctx)
|
||||
if r == nil {
|
||||
g.Log().Warningf(ctx, "IsHTTPS ctx not request")
|
||||
return false
|
||||
}
|
||||
var (
|
||||
proto = r.Header.Get("X-Forwarded-Proto")
|
||||
)
|
||||
|
||||
if r.TLS != nil || gstr.Equal(proto, "https") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsIp 是否为ipv4
|
||||
func IsIp(ip string) bool {
|
||||
if net.ParseIP(ip) != nil {
|
||||
@@ -22,48 +46,37 @@ func IsIp(ip string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsPublicIp 是否是公网IP
|
||||
func IsPublicIp(Ip string) bool {
|
||||
ip := net.ParseIP(Ip)
|
||||
|
||||
if ip.IsLoopback() || ip.IsPrivate() || ip.IsMulticast() || ip.IsUnspecified() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
|
||||
return false
|
||||
}
|
||||
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
return !ip.Equal(net.IPv4bcast)
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
// IsMobile 是否为手机号码
|
||||
func IsMobile(mobile string) bool {
|
||||
pattern := `^(1[2|3|4|5|6|7|8|9][0-9]\d{4,8})$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
return reg.MatchString(mobile)
|
||||
}
|
||||
|
||||
// IsEmail 是否为邮箱地址
|
||||
func IsEmail(email string) bool {
|
||||
//pattern := `\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*` //匹配电子邮箱
|
||||
pattern := `^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z].){1,4}[a-z]{2,4}$`
|
||||
|
||||
reg := regexp.MustCompile(pattern)
|
||||
return reg.MatchString(email)
|
||||
}
|
||||
|
||||
// InSameDay 是否为同一天
|
||||
func InSameDay(t1, t2 int64) bool {
|
||||
y1, m1, d1 := time.Unix(t1, 0).Date()
|
||||
y2, m2, d2 := time.Unix(t2, 0).Date()
|
||||
|
||||
return y1 == y2 && m1 == m2 && d1 == d2
|
||||
}
|
||||
|
||||
// InSameMinute 是否为同一分钟
|
||||
func InSameMinute(t1, t2 int64) bool {
|
||||
d1 := time.Unix(t1, 0).Format("2006-01-02 15:04")
|
||||
d2 := time.Unix(t2, 0).Format("2006-01-02 15:04")
|
||||
|
||||
return d1 == d2
|
||||
}
|
||||
|
||||
// InSliceExistStr 判断字符或切片字符是否存在指定字符
|
||||
func InSliceExistStr(elems interface{}, search string) bool {
|
||||
switch elems.(type) {
|
||||
case []string:
|
||||
elem := gconv.Strings(elems)
|
||||
for i := 0; i < len(elem); i++ {
|
||||
if gconv.String(elem[i]) == search {
|
||||
return true
|
||||
}
|
||||
}
|
||||
default:
|
||||
return gconv.String(elems) == search
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsURL 是否是url地址
|
||||
func IsURL(u string) bool {
|
||||
_, err := url.ParseRequestURI(u)
|
||||
@@ -76,3 +89,19 @@ func IsURL(u string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsIDCard 是否为身份证
|
||||
func IsIDCard(idCard string) bool {
|
||||
sz := len(idCard)
|
||||
if sz != 18 {
|
||||
return false
|
||||
}
|
||||
weight := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
|
||||
validate := []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
|
||||
sum := 0
|
||||
for i := 0; i < len(weight); i++ {
|
||||
sum += weight[i] * int(byte(idCard[i])-'0')
|
||||
}
|
||||
m := sum % 11
|
||||
return validate[m] == idCard[sz-1]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user