feat: omc原始代码
This commit is contained in:
54
lib/core/account/account.go
Normal file
54
lib/core/account/account.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package account
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
sysMenuService "nms_nbi/features/sys_menu/service"
|
||||
sysRoleService "nms_nbi/features/sys_role/service"
|
||||
"nms_nbi/lib/core/cache"
|
||||
"nms_nbi/lib/core/vo"
|
||||
"nms_nbi/lib/dborm"
|
||||
srcConfig "nms_nbi/src/framework/config"
|
||||
)
|
||||
|
||||
// 登录缓存用户信息
|
||||
func CacheLoginUser(user *dborm.User) {
|
||||
// 过期时间
|
||||
expiresStr, err := dborm.XormGetConfigValue("Security", "sessionExpires")
|
||||
if err != nil {
|
||||
expiresStr = "18000"
|
||||
}
|
||||
expiresValue, _ := strconv.Atoi(expiresStr)
|
||||
expireTime := time.Duration(expiresValue) * time.Second
|
||||
|
||||
nowTime := time.Now().UnixMilli()
|
||||
|
||||
// 登录用户
|
||||
loginUser := vo.LoginUser{
|
||||
UserID: fmt.Sprint(user.Id),
|
||||
UserName: user.Name,
|
||||
ExpireTime: nowTime + expireTime.Milliseconds(),
|
||||
LoginTime: nowTime,
|
||||
User: *user,
|
||||
}
|
||||
|
||||
// 是否管理员
|
||||
if srcConfig.IsAdmin(loginUser.UserID) {
|
||||
loginUser.Permissions = []string{"*:*:*"}
|
||||
} else {
|
||||
// 获取权限标识
|
||||
loginUser.Permissions = sysMenuService.NewRepoSysMenu.SelectMenuPermsByUserId(loginUser.UserID)
|
||||
// 获取角色信息
|
||||
loginUser.User.Roles = sysRoleService.NewRepoSysRole.SelectRoleListByUserId(loginUser.UserID)
|
||||
}
|
||||
|
||||
// 缓存时间
|
||||
cache.SetLocalTTL(user.AccountId, loginUser, time.Duration(expireTime))
|
||||
}
|
||||
|
||||
// 清除缓存用户信息
|
||||
func ClearLoginUser(accountId string) {
|
||||
cache.DeleteLocalTTL(accountId)
|
||||
}
|
||||
56
lib/core/cache/lcoal.go
vendored
Normal file
56
lib/core/cache/lcoal.go
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
// 创建一个全局的不过期缓存对象
|
||||
var cNoExpiration = cache.New(cache.NoExpiration, cache.NoExpiration)
|
||||
|
||||
// 将数据放入缓存,并设置永不过期
|
||||
func SetLocal(key string, value any) {
|
||||
cNoExpiration.Set(key, value, cache.NoExpiration)
|
||||
}
|
||||
|
||||
// 从缓存中获取数据
|
||||
func GetLocal(key string) (any, bool) {
|
||||
return cNoExpiration.Get(key)
|
||||
}
|
||||
|
||||
// 从缓存中删除数据
|
||||
func DeleteLocal(key string) {
|
||||
cNoExpiration.Delete(key)
|
||||
}
|
||||
|
||||
// 获取指定前缀的所有键
|
||||
func GetLocalKeys(prefix string) []string {
|
||||
prefix = strings.TrimSuffix(prefix, "*")
|
||||
var keys []string
|
||||
for key := range cNoExpiration.Items() {
|
||||
if strings.HasPrefix(key, prefix) {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// 创建一个全局的过期缓存对象
|
||||
var cTTL = cache.New(6*time.Hour, 12*time.Hour)
|
||||
|
||||
// 设置具有过期时间的缓存项
|
||||
func SetLocalTTL(key string, value any, expiration time.Duration) {
|
||||
cTTL.Set(key, value, expiration)
|
||||
}
|
||||
|
||||
// 从缓存中获取数据
|
||||
func GetLocalTTL(key string) (any, bool) {
|
||||
return cTTL.Get(key)
|
||||
}
|
||||
|
||||
// 从缓存中删除数据
|
||||
func DeleteLocalTTL(key string) {
|
||||
cTTL.Delete(key)
|
||||
}
|
||||
36
lib/core/conf/conf.go
Normal file
36
lib/core/conf/conf.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var v *viper.Viper
|
||||
|
||||
// 配置文件读取
|
||||
func InitConfig(configFile string) {
|
||||
v = viper.New()
|
||||
|
||||
// 设置配置文件路径
|
||||
v.SetConfigFile(configFile)
|
||||
|
||||
// 读取配置文件
|
||||
err := v.ReadInConfig()
|
||||
if err != nil {
|
||||
fmt.Printf("读取配置文件失败: %v \n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Get 获取配置信息
|
||||
//
|
||||
// Get("framework.name")
|
||||
func Get(key string) any {
|
||||
return v.Get(key)
|
||||
}
|
||||
|
||||
// AllSettings 全部配置信息
|
||||
func AllSettings() map[string]interface{} {
|
||||
return v.AllSettings()
|
||||
}
|
||||
24
lib/core/constants/cachekey/cachekey.go
Normal file
24
lib/core/constants/cachekey/cachekey.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package cachekey
|
||||
|
||||
// 缓存的key常量
|
||||
|
||||
// 登录用户
|
||||
const LOGIN_TOKEN_KEY = "login_tokens:"
|
||||
|
||||
// 验证码
|
||||
const CAPTCHA_CODE_KEY = "captcha_codes:"
|
||||
|
||||
// 参数管理
|
||||
const SYS_CONFIG_KEY = "sys_config:"
|
||||
|
||||
// 字典管理
|
||||
const SYS_DICT_KEY = "sys_dict:"
|
||||
|
||||
// 防重提交
|
||||
const REPEAT_SUBMIT_KEY = "repeat_submit:"
|
||||
|
||||
// 限流
|
||||
const RATE_LIMIT_KEY = "rate_limit:"
|
||||
|
||||
// 登录账户密码错误次数
|
||||
const PWD_ERR_CNT_KEY = "pwd_err_cnt:"
|
||||
50
lib/core/datasource/datasource.go
Normal file
50
lib/core/datasource/datasource.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package datasource
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"regexp"
|
||||
|
||||
"nms_nbi/lib/dborm"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// 获取默认数据源
|
||||
func DefaultDB() *xorm.Engine {
|
||||
return dborm.DbClient.XEngine
|
||||
}
|
||||
|
||||
// RawDB 原生查询语句
|
||||
func RawDB(source string, sql string, parameters []any) ([]map[string]any, error) {
|
||||
// 数据源
|
||||
db := DefaultDB()
|
||||
|
||||
// 使用正则表达式替换连续的空白字符为单个空格
|
||||
fmtSql := regexp.MustCompile(`\s+`).ReplaceAllString(sql, " ")
|
||||
|
||||
// log.Infof("sql=> %v", fmtSql)
|
||||
// log.Infof("parameters=> %v", parameters)
|
||||
|
||||
// 查询结果
|
||||
var rows []map[string]any
|
||||
err := db.SQL(fmtSql, parameters...).Find(&rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
// ExecDB 原生执行语句
|
||||
func ExecDB(source string, sql string, parameters []any) (sql.Result, error) {
|
||||
// 数据源
|
||||
db := DefaultDB()
|
||||
|
||||
// 使用正则表达式替换连续的空白字符为单个空格
|
||||
fmtSql := regexp.MustCompile(`\s+`).ReplaceAllString(sql, " ")
|
||||
// 执行结果
|
||||
res, err := db.Exec(append([]any{fmtSql}, parameters...)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
126
lib/core/datasource/repo.go
Normal file
126
lib/core/datasource/repo.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package datasource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PageNumSize 分页页码记录数
|
||||
func PageNumSize(pageNum, pageSize any) (int, int) {
|
||||
// 记录起始索引
|
||||
pageNumStr := fmt.Sprintf("%v", pageNum)
|
||||
num := 1
|
||||
if v, err := strconv.Atoi(pageNumStr); err == nil && v > 0 {
|
||||
num = v
|
||||
}
|
||||
|
||||
// 显示记录数
|
||||
pageSizeStr := fmt.Sprintf("%v", pageSize)
|
||||
size := 10
|
||||
if v, err := strconv.Atoi(pageSizeStr); err == nil && v > 0 {
|
||||
size = v
|
||||
}
|
||||
return num - 1, size
|
||||
}
|
||||
|
||||
// SetFieldValue 判断结构体内是否存在指定字段并设置值
|
||||
func SetFieldValue(obj any, fieldName string, value any) {
|
||||
// 获取结构体的反射值
|
||||
userValue := reflect.ValueOf(obj)
|
||||
|
||||
// 获取字段的反射值
|
||||
fieldValue := userValue.Elem().FieldByName(fieldName)
|
||||
|
||||
// 检查字段是否存在
|
||||
if fieldValue.IsValid() && fieldValue.CanSet() {
|
||||
// 获取字段的类型
|
||||
fieldType := fieldValue.Type()
|
||||
|
||||
// 转换传入的值类型为字段类型
|
||||
switch fieldType.Kind() {
|
||||
case reflect.String:
|
||||
if value == nil {
|
||||
fieldValue.SetString("")
|
||||
} else {
|
||||
fieldValue.SetString(fmt.Sprintf("%v", value))
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
intValue, err := strconv.ParseInt(fmt.Sprintf("%v", value), 10, 64)
|
||||
if err != nil {
|
||||
intValue = 0
|
||||
}
|
||||
fieldValue.SetInt(intValue)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
uintValue, err := strconv.ParseUint(fmt.Sprintf("%v", value), 10, 64)
|
||||
if err != nil {
|
||||
uintValue = 0
|
||||
}
|
||||
fieldValue.SetUint(uintValue)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
floatValue, err := strconv.ParseFloat(fmt.Sprintf("%v", value), 64)
|
||||
if err != nil {
|
||||
floatValue = 0
|
||||
}
|
||||
fieldValue.SetFloat(floatValue)
|
||||
default:
|
||||
// 设置字段的值
|
||||
fieldValue.Set(reflect.ValueOf(value).Convert(fieldValue.Type()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertIdsSlice 将 []string 转换为 []any
|
||||
func ConvertIdsSlice(ids []string) []any {
|
||||
// 将 []string 转换为 []any
|
||||
arr := make([]any, len(ids))
|
||||
for i, v := range ids {
|
||||
arr[i] = v
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// 查询-参数值的占位符
|
||||
func KeyPlaceholderByQuery(sum int) string {
|
||||
placeholders := make([]string, sum)
|
||||
for i := 0; i < sum; i++ {
|
||||
placeholders[i] = "?"
|
||||
}
|
||||
return strings.Join(placeholders, ",")
|
||||
}
|
||||
|
||||
// 插入-参数映射键值占位符 keys, placeholder, values
|
||||
func KeyPlaceholderValueByInsert(params map[string]any) ([]string, string, []any) {
|
||||
// 参数映射的键
|
||||
keys := make([]string, len(params))
|
||||
// 参数映射的值
|
||||
values := make([]any, len(params))
|
||||
sum := 0
|
||||
for k, v := range params {
|
||||
keys[sum] = k
|
||||
values[sum] = v
|
||||
sum++
|
||||
}
|
||||
// 参数值的占位符
|
||||
placeholders := make([]string, sum)
|
||||
for i := 0; i < sum; i++ {
|
||||
placeholders[i] = "?"
|
||||
}
|
||||
return keys, strings.Join(placeholders, ","), values
|
||||
}
|
||||
|
||||
// 更新-参数映射键值占位符 keys, values
|
||||
func KeyValueByUpdate(params map[string]any) ([]string, []any) {
|
||||
// 参数映射的键
|
||||
keys := make([]string, len(params))
|
||||
// 参数映射的值
|
||||
values := make([]any, len(params))
|
||||
sum := 0
|
||||
for k, v := range params {
|
||||
keys[sum] = k + "=?"
|
||||
values[sum] = v
|
||||
sum++
|
||||
}
|
||||
return keys, values
|
||||
}
|
||||
87
lib/core/mml_client/mml_client.go
Normal file
87
lib/core/mml_client/mml_client.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package mmlclient
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"nms_nbi/lib/core/conf"
|
||||
)
|
||||
|
||||
// 定义MMLClient结构体
|
||||
type MMLClient struct {
|
||||
awaitTime time.Duration // 等待时间
|
||||
conn net.Conn
|
||||
reader *bufio.Reader
|
||||
size int // 包含字符
|
||||
}
|
||||
|
||||
// 封装NewMMLClient函数,用于创建MMLClient实例
|
||||
// 网元UDM的IP地址 "198.51.100.1"
|
||||
func NewMMLClient(ip string) (*MMLClient, error) {
|
||||
// 创建TCP连接
|
||||
portMML := conf.Get("mml.port").(int)
|
||||
hostMML := fmt.Sprintf("%s:%d", ip, portMML)
|
||||
conn, err := net.Dial("tcp", hostMML)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 进行登录
|
||||
usernameMML := conf.Get("mml.user").(string)
|
||||
passwordMML := conf.Get("mml.password").(string)
|
||||
fmt.Fprintln(conn, usernameMML)
|
||||
fmt.Fprintln(conn, passwordMML)
|
||||
|
||||
// 发送后等待
|
||||
awaitTime := time.Duration(300) * time.Millisecond
|
||||
time.Sleep(awaitTime)
|
||||
|
||||
// 读取内容
|
||||
buf := make([]byte, 1024*1024*1)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建MMLClient实例
|
||||
client := &MMLClient{
|
||||
conn: conn,
|
||||
reader: bufio.NewReader(conn),
|
||||
awaitTime: awaitTime,
|
||||
size: n,
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// 封装Send函数,用于向TCP连接发送数据
|
||||
func (c *MMLClient) Send(msg string) error {
|
||||
_, err := fmt.Fprintln(c.conn, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(c.awaitTime)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 封装Receive函数,用于从TCP连接中接收数据
|
||||
func (c *MMLClient) Receive() (string, error) {
|
||||
buf := make([]byte, 1024*1024*1)
|
||||
n, err := c.reader.Read(buf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return "", fmt.Errorf("server closed the connection")
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
c.size += n
|
||||
return string(buf[0:n]), nil
|
||||
}
|
||||
|
||||
// 封装Close函数,用于关闭TCP连接
|
||||
func (c *MMLClient) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
105
lib/core/mml_client/send.go
Normal file
105
lib/core/mml_client/send.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package mmlclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 发送MML原始消息
|
||||
// ip 网元IP地址
|
||||
// msg 指令
|
||||
func MMLSendMsg(ip, msg string) (string, error) {
|
||||
// 创建MMLClient实例
|
||||
client, err := NewMMLClient(ip)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create MMLClient instance: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// 发送数据
|
||||
err = client.Send(msg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("sending data failed: %v", err)
|
||||
}
|
||||
|
||||
// 接收数据
|
||||
data, err := client.Receive()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to receive data: %v", err)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// 发送MML
|
||||
// ip 网元IP地址
|
||||
// msg 指令
|
||||
func MMLSendMsgToString(ip, msg string) (string, error) {
|
||||
// 发送获取数据
|
||||
str, err := MMLSendMsg(ip, msg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
str = strings.ToLower(str)
|
||||
|
||||
// 截断
|
||||
index := strings.Index(str, "\n")
|
||||
if index != -1 {
|
||||
str = str[:index]
|
||||
}
|
||||
|
||||
// 命令成功
|
||||
if strings.Contains(str, "ok") || strings.Contains(str, "success") {
|
||||
return str, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf(str)
|
||||
}
|
||||
|
||||
// 发送MML
|
||||
// ip 网元IP地址
|
||||
// msg 指令
|
||||
func MMLSendMsgToMap(ip, msg string) (map[string]string, error) {
|
||||
// 发送获取数据
|
||||
str, err := MMLSendMsg(ip, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 无数据
|
||||
if strings.HasPrefix(str, "No Auth Data") {
|
||||
return nil, fmt.Errorf("no auth data")
|
||||
}
|
||||
|
||||
// 初始化一个map用于存储拆分后的键值对
|
||||
m := make(map[string]string)
|
||||
|
||||
var items []string
|
||||
if strings.Contains(str, "\r\n") {
|
||||
// 按照分隔符"\r\n"进行拆分
|
||||
items = strings.Split(str, "\r\n")
|
||||
} else if strings.Contains(str, "\n") {
|
||||
// 按照分隔符"\n"进行拆分
|
||||
items = strings.Split(str, "\n")
|
||||
}
|
||||
|
||||
// 遍历拆分后的结果
|
||||
for _, item := range items {
|
||||
var pair []string
|
||||
|
||||
if strings.Contains(item, "=") {
|
||||
// 按照分隔符"="进行拆分键值对
|
||||
pair = strings.SplitN(item, "=", 2)
|
||||
} else if strings.Contains(item, ":") {
|
||||
// 按照分隔符":"进行拆分键值对
|
||||
pair = strings.SplitN(item, ":", 2)
|
||||
}
|
||||
|
||||
if len(pair) == 2 {
|
||||
// 将键值对存入map中
|
||||
m[pair[0]] = pair[1]
|
||||
}
|
||||
}
|
||||
return m, err
|
||||
}
|
||||
192
lib/core/utils/ctx/ctx.go
Normal file
192
lib/core/utils/ctx/ctx.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"nms_nbi/lib/core/vo"
|
||||
commonConstants "nms_nbi/src/framework/constants/common"
|
||||
tokenConst "nms_nbi/src/framework/constants/token"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// Param 地址栏参数{id}
|
||||
func Param(r *http.Request, key string) string {
|
||||
vars := mux.Vars(r)
|
||||
v, ok := vars[key]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetQuery 查询参数
|
||||
func GetQuery(r *http.Request, key string) string {
|
||||
return r.URL.Query().Get(key)
|
||||
}
|
||||
|
||||
// GetHeader 请求头参数
|
||||
func GetHeader(r *http.Request, key string) string {
|
||||
return r.Header.Get(key)
|
||||
}
|
||||
|
||||
// QueryMap 查询参数转换Map
|
||||
func QueryMap(r *http.Request) map[string]any {
|
||||
queryValues := r.URL.Query()
|
||||
queryParams := make(map[string]any)
|
||||
for key, values := range queryValues {
|
||||
queryParams[key] = values[0]
|
||||
}
|
||||
return queryParams
|
||||
}
|
||||
|
||||
// ShouldBindQuery 查询参数读取json请求结构团体
|
||||
func ShouldBindQuery(r *http.Request, args any) error {
|
||||
queryParams := QueryMap(r)
|
||||
body, err := json.Marshal(queryParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(body, args)
|
||||
}
|
||||
|
||||
// 读取json请求结构团体
|
||||
func ShouldBindJSON(r *http.Request, args any) error {
|
||||
body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20)) // 设置较大的长度,例如 1<<20 (1MB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(body, args)
|
||||
return err
|
||||
}
|
||||
|
||||
// JSON 相应json数据
|
||||
func JSON(w http.ResponseWriter, code int, data any) {
|
||||
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
||||
|
||||
response, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
} else {
|
||||
w.WriteHeader(code)
|
||||
w.Write(response)
|
||||
}
|
||||
}
|
||||
|
||||
// 将文件导出到外部下载
|
||||
func FileAttachment(w http.ResponseWriter, r *http.Request, filepath, filename string) {
|
||||
w.Header().Set("Content-Disposition", `attachment; filename=`+url.QueryEscape(filename))
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
// 将文件上传保存到指定目录
|
||||
// file, handler, err := r.FormFile("file")
|
||||
// SaveUploadedFile uploads the form file to specific dst.
|
||||
func SaveUploadedFile(r *http.Request, dst string) error {
|
||||
// 解析请求中的文件
|
||||
_, handler, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := handler.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, src)
|
||||
return err
|
||||
}
|
||||
|
||||
/// ==== 登录用户信息, 通过中间件后预置入
|
||||
|
||||
// Authorization 解析请求头
|
||||
func Authorization(r *http.Request) string {
|
||||
authHeader := r.Header.Get(tokenConst.HEADER_KEY)
|
||||
if authHeader == "" {
|
||||
return ""
|
||||
}
|
||||
// 拆分 Authorization 请求头,提取 JWT 令牌部分
|
||||
arr := strings.Split(authHeader, tokenConst.HEADER_PREFIX)
|
||||
if len(arr) == 2 && arr[1] == "" {
|
||||
return ""
|
||||
}
|
||||
return arr[1]
|
||||
}
|
||||
|
||||
// AcceptLanguage 解析客户端接收语言 zh:中文 en: 英文
|
||||
func AcceptLanguage(r *http.Request) string {
|
||||
preferredLanguage := language.English
|
||||
|
||||
// Query请求查询
|
||||
if v := GetQuery(r, "language"); v != "" {
|
||||
tags, _, _ := language.ParseAcceptLanguage(v)
|
||||
if len(tags) > 0 {
|
||||
preferredLanguage = tags[0]
|
||||
}
|
||||
}
|
||||
// Header请求头
|
||||
if v := GetHeader(r, "Accept-Language"); v != "" {
|
||||
tags, _, _ := language.ParseAcceptLanguage(v)
|
||||
if len(tags) > 0 {
|
||||
preferredLanguage = tags[0]
|
||||
}
|
||||
}
|
||||
|
||||
// 只取前缀
|
||||
lang := preferredLanguage.String()
|
||||
arr := strings.Split(lang, "-")
|
||||
return arr[0]
|
||||
}
|
||||
|
||||
// ContextKey 定义自定义类型作为键
|
||||
type ContextKey string
|
||||
|
||||
// LoginUser 登录用户信息需要Authorize中间件
|
||||
func LoginUser(r *http.Request) (vo.LoginUser, error) {
|
||||
// 上下文
|
||||
v := r.Context().Value(ContextKey(commonConstants.CTX_LOGIN_USER))
|
||||
if v != nil {
|
||||
return v.(vo.LoginUser), nil
|
||||
}
|
||||
return vo.LoginUser{}, fmt.Errorf("No user information")
|
||||
}
|
||||
|
||||
// LoginUserToUserID 登录用户信息-用户ID
|
||||
func LoginUserToUserID(r *http.Request) string {
|
||||
loginUser, err := LoginUser(r)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return loginUser.UserID
|
||||
}
|
||||
|
||||
// LoginUserToUserName 登录用户信息-用户名称
|
||||
func LoginUserToUserName(r *http.Request) string {
|
||||
loginUser, err := LoginUser(r)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return loginUser.UserName
|
||||
}
|
||||
70
lib/core/utils/date/date.go
Normal file
70
lib/core/utils/date/date.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package date
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"nms_nbi/lib/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// 年 列如:2022
|
||||
YYYY = "2006"
|
||||
// 年-月 列如:2022-12
|
||||
YYYY_MM = "2006-01"
|
||||
// 年-月-日 列如:2022-12-30
|
||||
YYYY_MM_DD = "2006-01-02"
|
||||
// 年月日时分秒 列如:20221230010159
|
||||
YYYYMMDDHHMMSS = "20060102150405"
|
||||
// 年-月-日 时:分:秒 列如:2022-12-30 01:01:59
|
||||
YYYY_MM_DD_HH_MM_SS = "2006-01-02 15:04:05"
|
||||
)
|
||||
|
||||
// 格式时间字符串
|
||||
//
|
||||
// dateStr 时间字符串
|
||||
//
|
||||
// formatStr 时间格式 默认YYYY-MM-DD HH:mm:ss
|
||||
func ParseStrToDate(dateStr, formatStr string) time.Time {
|
||||
t, err := time.Parse(formatStr, dateStr)
|
||||
if err != nil {
|
||||
log.Infof("utils ParseStrToDate err %v", err)
|
||||
return time.Time{}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// 格式时间
|
||||
//
|
||||
// date 可转的Date对象
|
||||
//
|
||||
// formatStr 时间格式 默认YYYY-MM-DD HH:mm:ss
|
||||
func ParseDateToStr(date any, formatStr string) string {
|
||||
t, ok := date.(time.Time)
|
||||
if !ok {
|
||||
switch v := date.(type) {
|
||||
case int64:
|
||||
if v == 0 {
|
||||
return ""
|
||||
}
|
||||
t = time.UnixMilli(v)
|
||||
case string:
|
||||
parsedTime, err := time.Parse(formatStr, v)
|
||||
if err != nil {
|
||||
fmt.Printf("utils ParseDateToStr err %v \n", err)
|
||||
return ""
|
||||
}
|
||||
t = parsedTime
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return t.Format(formatStr)
|
||||
}
|
||||
|
||||
// 格式时间成日期路径
|
||||
//
|
||||
// 年/月 列如:2022/12
|
||||
func ParseDatePath(date time.Time) string {
|
||||
return date.Format("2006/01")
|
||||
}
|
||||
139
lib/core/utils/parse/parse.go
Normal file
139
lib/core/utils/parse/parse.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
// Number 解析数值型
|
||||
func Number(str any) int64 {
|
||||
switch str := str.(type) {
|
||||
case string:
|
||||
if str == "" {
|
||||
return 0
|
||||
}
|
||||
num, err := strconv.ParseInt(str, 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return num
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
return reflect.ValueOf(str).Int()
|
||||
case float32, float64:
|
||||
return int64(reflect.ValueOf(str).Float())
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Boolean 解析布尔型
|
||||
func Boolean(str any) bool {
|
||||
switch str := str.(type) {
|
||||
case string:
|
||||
if str == "" || str == "false" || str == "0" {
|
||||
return false
|
||||
}
|
||||
// 尝试将字符串解析为数字
|
||||
if num, err := strconv.ParseFloat(str, 64); err == nil {
|
||||
return num != 0
|
||||
}
|
||||
return true
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
num := reflect.ValueOf(str).Int()
|
||||
return num != 0
|
||||
case float32, float64:
|
||||
num := reflect.ValueOf(str).Float()
|
||||
return num != 0
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// FirstUpper 首字母转大写
|
||||
//
|
||||
// 字符串 abc_123!@# 结果 Abc_123
|
||||
func FirstUpper(str string) string {
|
||||
if len(str) == 0 {
|
||||
return str
|
||||
}
|
||||
reg := regexp.MustCompile(`[^_\w]+`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
return strings.ToUpper(str[:1]) + str[1:]
|
||||
}
|
||||
|
||||
// Bit 比特位为单位
|
||||
func Bit(bit float64) string {
|
||||
var GB, MB, KB string
|
||||
|
||||
if bit > float64(1<<30) {
|
||||
GB = fmt.Sprintf("%0.2f", bit/(1<<30))
|
||||
}
|
||||
|
||||
if bit > float64(1<<20) && bit < (1<<30) {
|
||||
MB = fmt.Sprintf("%.2f", bit/(1<<20))
|
||||
}
|
||||
|
||||
if bit > float64(1<<10) && bit < (1<<20) {
|
||||
KB = fmt.Sprintf("%.2f", bit/(1<<10))
|
||||
}
|
||||
|
||||
if GB != "" {
|
||||
return GB + "GB"
|
||||
} else if MB != "" {
|
||||
return MB + "MB"
|
||||
} else if KB != "" {
|
||||
return KB + "KB"
|
||||
} else {
|
||||
return fmt.Sprintf("%vB", bit)
|
||||
}
|
||||
}
|
||||
|
||||
// CronExpression 解析 Cron 表达式,返回下一次执行的时间戳(毫秒)
|
||||
//
|
||||
// 【*/5 * * * * ?】 6个参数
|
||||
func CronExpression(expression string) int64 {
|
||||
specParser := cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
|
||||
schedule, err := specParser.Parse(expression)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return 0
|
||||
}
|
||||
return schedule.Next(time.Now()).UnixMilli()
|
||||
}
|
||||
|
||||
// SafeContent 内容值进行安全掩码
|
||||
func SafeContent(value string) string {
|
||||
if len(value) < 3 {
|
||||
return strings.Repeat("*", len(value))
|
||||
} else if len(value) < 6 {
|
||||
return string(value[0]) + strings.Repeat("*", len(value)-1)
|
||||
} else if len(value) < 10 {
|
||||
return string(value[0]) + strings.Repeat("*", len(value)-2) + string(value[len(value)-1])
|
||||
} else if len(value) < 15 {
|
||||
return value[:2] + strings.Repeat("*", len(value)-4) + value[len(value)-2:]
|
||||
} else {
|
||||
return value[:3] + strings.Repeat("*", len(value)-6) + value[len(value)-3:]
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveDuplicates 数组内字符串去重
|
||||
func RemoveDuplicates(ids []string) []string {
|
||||
uniqueIDs := make(map[string]bool)
|
||||
uniqueIDSlice := make([]string, 0)
|
||||
|
||||
for _, id := range ids {
|
||||
_, ok := uniqueIDs[id]
|
||||
if !ok && id != "" {
|
||||
uniqueIDs[id] = true
|
||||
uniqueIDSlice = append(uniqueIDSlice, id)
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueIDSlice
|
||||
}
|
||||
54
lib/core/utils/regular/regular.go
Normal file
54
lib/core/utils/regular/regular.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package regular
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Replace 正则替换
|
||||
func Replace(originStr, pattern, repStr string) string {
|
||||
regex := regexp.MustCompile(pattern)
|
||||
return regex.ReplaceAllString(originStr, repStr)
|
||||
}
|
||||
|
||||
// 判断是否为有效用户名格式
|
||||
//
|
||||
// 用户名不能以数字开头,可包含大写小写字母,数字,且不少于5位
|
||||
func ValidUsername(username string) bool {
|
||||
if username == "" {
|
||||
return false
|
||||
}
|
||||
pattern := `^[a-zA-Z][a-z0-9A-Z]{5,}`
|
||||
match, err := regexp.MatchString(pattern, username)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
// 判断是否为有效手机号格式,1开头的11位手机号
|
||||
func ValidMobile(mobile string) bool {
|
||||
if mobile == "" {
|
||||
return false
|
||||
}
|
||||
pattern := `^1[3|4|5|6|7|8|9][0-9]\d{8}$`
|
||||
match, err := regexp.MatchString(pattern, mobile)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
// 判断是否为http(s)://开头
|
||||
//
|
||||
// link 网络链接
|
||||
func ValidHttp(link string) bool {
|
||||
if link == "" {
|
||||
return false
|
||||
}
|
||||
pattern := `^http(s)?:\/\/+`
|
||||
match, err := regexp.MatchString(pattern, link)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return match
|
||||
}
|
||||
31
lib/core/utils/scan/scan.go
Normal file
31
lib/core/utils/scan/scan.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ScanPort(port int) bool {
|
||||
ln, err := net.Listen("tcp", ":"+strconv.Itoa(port))
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
defer ln.Close()
|
||||
return false
|
||||
}
|
||||
|
||||
func ScanUDPPort(port int) bool {
|
||||
ln, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port})
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
defer ln.Close()
|
||||
return false
|
||||
}
|
||||
|
||||
func ScanPortWithProto(port int, proto string) bool {
|
||||
if proto == "udp" {
|
||||
return ScanUDPPort(port)
|
||||
}
|
||||
return ScanPort(port)
|
||||
}
|
||||
28
lib/core/vo/login_user.go
Normal file
28
lib/core/vo/login_user.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package vo
|
||||
|
||||
import (
|
||||
"nms_nbi/lib/dborm"
|
||||
)
|
||||
|
||||
// LoginUser 登录用户身份权限信息对象
|
||||
type LoginUser struct {
|
||||
// UserID 用户ID
|
||||
UserID string `json:"userId"`
|
||||
|
||||
// UserName 用户名
|
||||
UserName string `json:"userName"`
|
||||
|
||||
// LoginTime 登录时间时间戳
|
||||
LoginTime int64 `json:"loginTime"`
|
||||
|
||||
// ExpireTime 过期时间时间戳
|
||||
ExpireTime int64 `json:"expireTime"`
|
||||
|
||||
// Permissions 权限列表
|
||||
Permissions []string `json:"permissions"`
|
||||
|
||||
// User 用户信息
|
||||
User dborm.User `json:"user"`
|
||||
|
||||
Session dborm.Session `json:"-"`
|
||||
}
|
||||
72
lib/core/vo/result/result.go
Normal file
72
lib/core/vo/result/result.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package result
|
||||
|
||||
const CODE_ERROR = 0
|
||||
const MSG_ERROR = "error"
|
||||
const CODE_SUCCESS = 1
|
||||
const MSG_SUCCESS = "success"
|
||||
|
||||
// CodeMsg 响应结果
|
||||
func CodeMsg(code int, msg string) map[string]any {
|
||||
args := make(map[string]any)
|
||||
args["code"] = code
|
||||
args["msg"] = msg
|
||||
return args
|
||||
}
|
||||
|
||||
// 响应成功结果 map[string]any{}
|
||||
func Ok(v map[string]any) map[string]any {
|
||||
args := make(map[string]any)
|
||||
args["code"] = CODE_SUCCESS
|
||||
args["msg"] = MSG_SUCCESS
|
||||
// v合并到args
|
||||
for key, value := range v {
|
||||
args[key] = value
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// 响应成功结果信息
|
||||
func OkMsg(msg string) map[string]any {
|
||||
args := make(map[string]any)
|
||||
args["code"] = CODE_SUCCESS
|
||||
args["msg"] = msg
|
||||
return args
|
||||
}
|
||||
|
||||
// 响应成功结果数据
|
||||
func OkData(data any) map[string]any {
|
||||
args := make(map[string]any)
|
||||
args["code"] = CODE_SUCCESS
|
||||
args["msg"] = MSG_SUCCESS
|
||||
args["data"] = data
|
||||
return args
|
||||
}
|
||||
|
||||
// 响应失败结果 map[string]any{}
|
||||
func Err(v map[string]any) map[string]any {
|
||||
args := make(map[string]any)
|
||||
args["code"] = CODE_ERROR
|
||||
args["msg"] = MSG_ERROR
|
||||
// v合并到args
|
||||
for key, value := range v {
|
||||
args[key] = value
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// 响应失败结果信息
|
||||
func ErrMsg(msg string) map[string]any {
|
||||
args := make(map[string]any)
|
||||
args["code"] = CODE_ERROR
|
||||
args["msg"] = msg
|
||||
return args
|
||||
}
|
||||
|
||||
// 响应失败结果数据
|
||||
func ErrData(data any) map[string]any {
|
||||
args := make(map[string]any)
|
||||
args["code"] = CODE_ERROR
|
||||
args["msg"] = MSG_ERROR
|
||||
args["data"] = data
|
||||
return args
|
||||
}
|
||||
17
lib/core/vo/router.go
Normal file
17
lib/core/vo/router.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package vo
|
||||
|
||||
// Router 路由信息对象
|
||||
type Router struct {
|
||||
// 路由名字 英文首字母大写
|
||||
Name string `json:"name"`
|
||||
// 路由地址
|
||||
Path string `json:"path"`
|
||||
// 其他元素
|
||||
Meta RouterMeta `json:"meta"`
|
||||
// 组件地址
|
||||
Component string `json:"component"`
|
||||
// 重定向地址
|
||||
Redirect string `json:"redirect"`
|
||||
// 子路由
|
||||
Children []Router `json:"children,omitempty"`
|
||||
}
|
||||
17
lib/core/vo/router_meta.go
Normal file
17
lib/core/vo/router_meta.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package vo
|
||||
|
||||
// RouterMeta 路由元信息对象
|
||||
type RouterMeta struct {
|
||||
// 设置该菜单在侧边栏和面包屑中展示的名字
|
||||
Title string `json:"title"`
|
||||
// 设置该菜单的图标
|
||||
Icon string `json:"icon"`
|
||||
// 设置为true,则不会被 <keep-alive>缓存
|
||||
Cache bool `json:"cache"`
|
||||
// 内链地址(http(s)://开头), 打开目标位置 '_blank' | '_self' | ''
|
||||
Target string `json:"target"`
|
||||
// 在菜单中隐藏子节点
|
||||
HideChildInMenu bool `json:"hideChildInMenu"`
|
||||
// 在菜单中隐藏自己和子节点
|
||||
HideInMenu bool `json:"hideInMenu"`
|
||||
}
|
||||
36
lib/core/vo/treeselect.go
Normal file
36
lib/core/vo/treeselect.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package vo
|
||||
|
||||
// import sysmenu "nms_nbi/features/sys_menu"
|
||||
|
||||
// TreeSelect 树结构实体类
|
||||
type TreeSelect struct {
|
||||
// ID 节点ID
|
||||
ID string `json:"id"`
|
||||
|
||||
// Label 节点名称
|
||||
Label string `json:"label"`
|
||||
|
||||
// Title 节点名称旧版本layui
|
||||
Title string `json:"title"`
|
||||
|
||||
// Children 子节点
|
||||
Children []TreeSelect `json:"children"`
|
||||
}
|
||||
|
||||
// // SysMenuTreeSelect 使用给定的 SysMenu 对象解析为 TreeSelect 对象
|
||||
// func SysMenuTreeSelect(sysMenu sysmenu.SysMenu) TreeSelect {
|
||||
// t := TreeSelect{}
|
||||
// t.ID = sysMenu.MenuID
|
||||
// t.Label = sysMenu.MenuName
|
||||
|
||||
// if len(sysMenu.Children) > 0 {
|
||||
// for _, menu := range sysMenu.Children {
|
||||
// child := SysMenuTreeSelect(menu)
|
||||
// t.Children = append(t.Children, child)
|
||||
// }
|
||||
// } else {
|
||||
// t.Children = []TreeSelect{}
|
||||
// }
|
||||
|
||||
// return t
|
||||
// }
|
||||
Reference in New Issue
Block a user