mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
refactor: 引入tailwind css & 后端部分非公共包位置调整
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/pkg/utils/assert"
|
||||
"mayfly-go/pkg/utils/cryptox"
|
||||
)
|
||||
|
||||
type Aes struct {
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
|
||||
// 编码并base64
|
||||
func (a *Aes) EncryptBase64(data []byte) (string, error) {
|
||||
return cryptox.AesEncryptBase64(data, []byte(a.Key))
|
||||
}
|
||||
|
||||
// base64解码后再aes解码
|
||||
func (a *Aes) DecryptBase64(data string) ([]byte, error) {
|
||||
return cryptox.AesDecryptBase64(data, []byte(a.Key))
|
||||
}
|
||||
|
||||
func (a *Aes) Valid() {
|
||||
if a.Key == "" {
|
||||
return
|
||||
}
|
||||
aesKeyLen := len(a.Key)
|
||||
assert.IsTrue(aesKeyLen == 16 || aesKeyLen == 24 || aesKeyLen == 32,
|
||||
fmt.Sprintf("config.yml之 [aes.key] 长度需为16、24、32位长度, 当前为%d位", aesKeyLen))
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package config
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
AppName = "mayfly-go"
|
||||
Version = "v1.9.4"
|
||||
)
|
||||
|
||||
func GetAppInfo() string {
|
||||
return fmt.Sprintf("[%s:%s]", AppName, Version)
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/ymlx"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ConfigItem interface {
|
||||
// 验证配置
|
||||
Valid()
|
||||
|
||||
// 如果不存在配置值,则设置默认值
|
||||
Default()
|
||||
}
|
||||
|
||||
// 配置文件映射对象
|
||||
var Conf *Config
|
||||
|
||||
func Init() {
|
||||
configFilePath := flag.String("e", "./config.yml", "配置文件路径,默认为可执行文件目录")
|
||||
flag.Parse()
|
||||
// 获取启动参数中,配置文件的绝对路径
|
||||
path, _ := filepath.Abs(*configFilePath)
|
||||
startConfigParam := &CmdConfigParam{ConfigFilePath: path}
|
||||
// 读取配置文件信息
|
||||
yc := &Config{}
|
||||
if err := ymlx.LoadYml(startConfigParam.ConfigFilePath, yc); err != nil {
|
||||
logx.Warn(fmt.Sprintf("读取配置文件[%s]失败: %s, 使用系统默认配置或环境变量配置", startConfigParam.ConfigFilePath, err.Error()))
|
||||
}
|
||||
// 尝试使用系统环境变量替换配置信息
|
||||
yc.ReplaceOsEnv()
|
||||
|
||||
yc.IfBlankDefaultValue()
|
||||
// 校验配置文件内容信息
|
||||
yc.Valid()
|
||||
Conf = yc
|
||||
}
|
||||
|
||||
// 启动配置参数
|
||||
type CmdConfigParam struct {
|
||||
ConfigFilePath string // -e 配置文件路径
|
||||
}
|
||||
|
||||
// yaml配置文件映射对象
|
||||
type Config struct {
|
||||
Server Server `yaml:"server"`
|
||||
Jwt Jwt `yaml:"jwt"`
|
||||
Aes Aes `yaml:"aes"`
|
||||
Mysql Mysql `yaml:"mysql"`
|
||||
Sqlite Sqlite `yaml:"sqlite"`
|
||||
Redis Redis `yaml:"redis"`
|
||||
Log Log `yaml:"log"`
|
||||
}
|
||||
|
||||
func (c *Config) IfBlankDefaultValue() {
|
||||
c.Log.Default()
|
||||
// 优先初始化log,因为后续的一些default方法中会需要用到。统一日志输出
|
||||
logx.Init(logx.Config{
|
||||
Level: c.Log.Level,
|
||||
Type: c.Log.Type,
|
||||
AddSource: c.Log.AddSource,
|
||||
Filename: c.Log.File.Name,
|
||||
Filepath: c.Log.File.Path,
|
||||
MaxSize: c.Log.File.MaxSize,
|
||||
MaxAge: c.Log.File.MaxAge,
|
||||
Compress: c.Log.File.Compress,
|
||||
})
|
||||
|
||||
c.Server.Default()
|
||||
c.Jwt.Default()
|
||||
c.Mysql.Default()
|
||||
c.Sqlite.Default()
|
||||
}
|
||||
|
||||
// 配置文件内容校验
|
||||
func (c *Config) Valid() {
|
||||
c.Jwt.Valid()
|
||||
c.Aes.Valid()
|
||||
}
|
||||
|
||||
// 替换系统环境变量,如果环境变量中存在该值,则优先使用环境变量设定的值
|
||||
func (c *Config) ReplaceOsEnv() {
|
||||
serverPort := os.Getenv("MAYFLY_SERVER_PORT")
|
||||
if serverPort != "" {
|
||||
if num, err := strconv.Atoi(serverPort); err != nil {
|
||||
panic("环境变量-[MAYFLY_SERVER_PORT]-服务端口号需为数字")
|
||||
} else {
|
||||
c.Server.Port = num
|
||||
}
|
||||
}
|
||||
|
||||
dbHost := os.Getenv("MAYFLY_DB_HOST")
|
||||
if dbHost != "" {
|
||||
c.Mysql.Host = dbHost
|
||||
}
|
||||
|
||||
dbName := os.Getenv("MAYFLY_DB_NAME")
|
||||
if dbName != "" {
|
||||
c.Mysql.Dbname = dbName
|
||||
}
|
||||
|
||||
dbUser := os.Getenv("MAYFLY_DB_USER")
|
||||
if dbUser != "" {
|
||||
c.Mysql.Username = dbUser
|
||||
}
|
||||
|
||||
dbPwd := os.Getenv("MAYFLY_DB_PASS")
|
||||
if dbPwd != "" {
|
||||
c.Mysql.Password = dbPwd
|
||||
}
|
||||
|
||||
sqlitePath := os.Getenv("MAYFLY_SQLITE_PATH")
|
||||
if sqlitePath != "" {
|
||||
c.Sqlite.Path = sqlitePath
|
||||
}
|
||||
|
||||
aesKey := os.Getenv("MAYFLY_AES_KEY")
|
||||
if aesKey != "" {
|
||||
c.Aes.Key = aesKey
|
||||
}
|
||||
|
||||
jwtKey := os.Getenv("MAYFLY_JWT_KEY")
|
||||
if jwtKey != "" {
|
||||
c.Jwt.Key = jwtKey
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/assert"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
)
|
||||
|
||||
type Jwt struct {
|
||||
Key string `yaml:"key"`
|
||||
ExpireTime uint64 `yaml:"expire-time"` // 过期时间,单位分钟
|
||||
RefreshTokenExpireTime uint64 `yaml:"refresh-token-expire-time"` // 刷新token的过期时间,单位分钟
|
||||
}
|
||||
|
||||
func (j *Jwt) Default() {
|
||||
if j.Key == "" {
|
||||
// 如果配置文件中的jwt key为空,则随机生成字符串
|
||||
j.Key = stringx.Rand(32)
|
||||
logx.Warnf("未配置jwt.key, 随机生成key为: %s", j.Key)
|
||||
}
|
||||
|
||||
if j.ExpireTime == 0 {
|
||||
j.ExpireTime = 1440
|
||||
logx.Warnf("未配置jwt.expire-time, 默认值: %d", j.ExpireTime)
|
||||
}
|
||||
if j.RefreshTokenExpireTime == 0 {
|
||||
j.RefreshTokenExpireTime = j.ExpireTime * 5
|
||||
logx.Warnf("未配置jwt.refresh-token-expire-time, 默认值: %d", j.RefreshTokenExpireTime)
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Jwt) Valid() {
|
||||
assert.IsTrue(j.ExpireTime != 0, "config.yml之[jwt.expire-time] 不能为空")
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/logx"
|
||||
)
|
||||
|
||||
type Log struct {
|
||||
Level string `yaml:"level"`
|
||||
Type string `yaml:"type"`
|
||||
AddSource bool `yaml:"add-source"`
|
||||
File LogFile `yaml:"file"`
|
||||
}
|
||||
|
||||
func (l *Log) Default() {
|
||||
if l.Level == "" {
|
||||
l.Level = "info"
|
||||
logx.Warnf("未配置log.level, 默认值: %s", l.Level)
|
||||
}
|
||||
if l.Type == "" {
|
||||
l.Type = "text"
|
||||
}
|
||||
if l.File.Name == "" {
|
||||
l.File.Name = "mayfly-go.log"
|
||||
}
|
||||
}
|
||||
|
||||
type LogFile struct {
|
||||
Name string `yaml:"name"`
|
||||
Path string `yaml:"path"`
|
||||
MaxSize int `yaml:"max-size"`
|
||||
MaxAge int `yaml:"max-age"`
|
||||
Compress bool `yaml:"compress"`
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package config
|
||||
|
||||
import "mayfly-go/pkg/logx"
|
||||
|
||||
type Mysql struct {
|
||||
Host string `mapstructure:"path" json:"host" yaml:"host"`
|
||||
Config string `mapstructure:"config" json:"config" yaml:"config"`
|
||||
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"`
|
||||
Username string `mapstructure:"username" json:"username" yaml:"username"`
|
||||
Password string `mapstructure:"password" json:"password" yaml:"password"`
|
||||
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
|
||||
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
|
||||
LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"`
|
||||
LogZap string `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"`
|
||||
}
|
||||
|
||||
func (m *Mysql) Default() {
|
||||
if m.Host == "" {
|
||||
m.Host = "localhost:3306"
|
||||
logx.Warnf("[使用sqlite可忽略]未配置mysql.host, 默认值: %s", m.Host)
|
||||
}
|
||||
if m.Config == "" {
|
||||
m.Config = "charset=utf8&loc=Local&parseTime=true"
|
||||
}
|
||||
if m.MaxIdleConns == 0 {
|
||||
m.MaxIdleConns = 5
|
||||
}
|
||||
if m.MaxOpenConns == 0 {
|
||||
m.MaxOpenConns = m.MaxIdleConns
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mysql) Dsn() string {
|
||||
return m.Username + ":" + m.Password + "@tcp(" + m.Host + ")/" + m.Dbname + "?" + m.Config
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package config
|
||||
|
||||
type Redis struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Password string `yaml:"password"`
|
||||
Db int `yaml:"db"`
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/pkg/i18n"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Lang string `yaml:"lang"`
|
||||
Port int `yaml:"port"`
|
||||
Model string `yaml:"model"`
|
||||
ContextPath string `yaml:"context-path"` // 请求路径上下文
|
||||
Cors bool `yaml:"cors"`
|
||||
Tls *Tls `yaml:"tls"`
|
||||
Static *[]*Static `yaml:"static"`
|
||||
StaticFile *[]*StaticFile `yaml:"static-file"`
|
||||
}
|
||||
|
||||
func (s *Server) Default() {
|
||||
if s.Lang == "" {
|
||||
s.Lang = i18n.Zh_CN
|
||||
}
|
||||
if s.Model == "" {
|
||||
s.Model = "release"
|
||||
}
|
||||
if s.Port == 0 {
|
||||
s.Port = 18888
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) GetPort() string {
|
||||
return fmt.Sprintf(":%d", s.Port)
|
||||
}
|
||||
|
||||
type Static struct {
|
||||
RelativePath string `yaml:"relative-path"`
|
||||
Root string `yaml:"root"`
|
||||
}
|
||||
|
||||
type StaticFile struct {
|
||||
RelativePath string `yaml:"relative-path"`
|
||||
Filepath string `yaml:"filepath"`
|
||||
}
|
||||
|
||||
type Tls struct {
|
||||
Enable bool `yaml:"enable"` // 是否启用tls
|
||||
KeyFile string `yaml:"key-file"` // 私钥文件路径
|
||||
CertFile string `yaml:"cert-file"` // 证书文件路径
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package config
|
||||
|
||||
import "mayfly-go/pkg/logx"
|
||||
|
||||
type Sqlite struct {
|
||||
Path string `mapstructure:"path" json:"path" yaml:"path"`
|
||||
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
|
||||
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
|
||||
}
|
||||
|
||||
func (m *Sqlite) Default() {
|
||||
if m.Path == "" {
|
||||
m.Path = "./mayfly-go.sqlite"
|
||||
logx.Warnf("[使用mysql可忽略]未配置sqlite.path, 默认值: %s", m.Path)
|
||||
}
|
||||
if m.MaxIdleConns == 0 {
|
||||
m.MaxIdleConns = 5
|
||||
}
|
||||
if m.MaxOpenConns == 0 {
|
||||
m.MaxOpenConns = m.MaxIdleConns
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
const (
|
||||
InjectTag = "inject"
|
||||
InjectMethodPrefix = "Inject"
|
||||
ByTypeComponentName = "T" // 根据类型注入的组件名
|
||||
)
|
||||
|
||||
@@ -74,14 +75,13 @@ func (c *Container) Inject(obj any) error {
|
||||
|
||||
// 对所有组件实例执行Inject。即为实例字段注入依赖的组件实例
|
||||
func (c *Container) InjectComponents() error {
|
||||
componentsGroups := collx.ArraySplit[*Component](collx.MapValues(c.components), 5)
|
||||
componentsGroups := collx.ArraySplit[*Component](collx.MapValues(c.components), 10)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
errGroup, _ := errgroup.WithContext(ctx)
|
||||
|
||||
for _, components := range componentsGroups {
|
||||
components := components // 创建局部变量以在闭包中使用
|
||||
errGroup.Go(func() error {
|
||||
for _, v := range components {
|
||||
if err := c.Inject(v.Value); err != nil {
|
||||
@@ -165,7 +165,7 @@ func (c *Container) GetComponentsByType(fieldType reflect.Type) []*Component {
|
||||
return components
|
||||
}
|
||||
|
||||
// injectWithField 根据实例字段的inject:"xxx"或injectByType:""标签进行依赖注入
|
||||
// injectWithField 根据实例字段的inject:"xxx"标签进行依赖注入
|
||||
func (c *Container) injectWithField(context context.Context, objValue reflect.Value) error {
|
||||
objValue = structx.Indirect(objValue)
|
||||
objType := objValue.Type()
|
||||
@@ -224,7 +224,7 @@ func (c *Container) injectByName(context context.Context, structType reflect.Typ
|
||||
return fmt.Errorf("%s error: injection types are inconsistent(Expected type -> %s.%s, Component type -> %s.%s)", injectInfo, field.Type.PkgPath(), field.Type.Name(), indirectComponentType.PkgPath(), indirectComponentType.Name())
|
||||
}
|
||||
|
||||
logx.DebugfContext(context, fmt.Sprintf("ioc field inject by name => [%s (%s) -> %s.%s#%s]", componentName, getComponentValueDesc(componentType), structType.PkgPath(), structType.Name(), field.Name))
|
||||
logx.DebugfContext(context, "ioc field inject by name => [%s (%s) -> %s.%s#%s]", componentName, getComponentValueDesc(componentType), structType.PkgPath(), structType.Name(), field.Name)
|
||||
|
||||
if err := setFieldValue(fieldValue, component.Value); err != nil {
|
||||
return fmt.Errorf("%s error: %s", injectInfo, err.Error())
|
||||
@@ -244,7 +244,7 @@ func (c *Container) injectByType(context context.Context, structType reflect.Typ
|
||||
return fmt.Errorf("%s error: %s", injectInfo, err.Error())
|
||||
}
|
||||
|
||||
logx.DebugfContext(context, fmt.Sprintf("ioc field inject by type => [%s.%s (%s) -> %s.%s#%s]", fieldType.PkgPath(), fieldType.Name(), getComponentValueDesc(component.GetType()), structType.PkgPath(), structType.Name(), field.Name))
|
||||
logx.DebugfContext(context, "ioc field inject by type => [%s.%s (%s) -> %s.%s#%s]", fieldType.PkgPath(), fieldType.Name(), getComponentValueDesc(component.GetType()), structType.PkgPath(), structType.Name(), field.Name)
|
||||
|
||||
if err := setFieldValue(fieldValue, component.Value); err != nil {
|
||||
return fmt.Errorf("%s error: %s", injectInfo, err.Error())
|
||||
@@ -261,8 +261,8 @@ func (c *Container) injectWithMethod(context context.Context, objValue reflect.V
|
||||
method := objType.Method(i)
|
||||
|
||||
methodName := method.Name
|
||||
// 不是以Inject开头的函数,则默认跳过
|
||||
if !strings.HasPrefix(methodName, "Inject") {
|
||||
// 不是以指定方法名前缀开头的函数,则默认跳过
|
||||
if !strings.HasPrefix(methodName, InjectMethodPrefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mayfly-go/pkg/cache"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/contextx"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/model"
|
||||
@@ -107,7 +106,7 @@ type DefaultPermissionCodeRegistry struct {
|
||||
|
||||
func (r *DefaultPermissionCodeRegistry) SaveCodes(userId uint64, codes []string) {
|
||||
if r.cache == nil {
|
||||
r.cache = cache.NewTimedCache(time.Minute*time.Duration(config.Conf.Jwt.ExpireTime), 5*time.Second)
|
||||
r.cache = cache.NewTimedCache(time.Minute*time.Duration(jwtConf.ExpireTime), 5*time.Second)
|
||||
}
|
||||
r.cache.Put(fmt.Sprintf("%v", userId), codes)
|
||||
}
|
||||
@@ -138,7 +137,7 @@ type RedisPermissionCodeRegistry struct {
|
||||
}
|
||||
|
||||
func (r *RedisPermissionCodeRegistry) SaveCodes(userId uint64, codes []string) {
|
||||
rediscli.Set(fmt.Sprintf("mayfly:%v:codes", userId), anyx.ToString(codes), time.Minute*time.Duration(config.Conf.Jwt.ExpireTime))
|
||||
rediscli.Set(fmt.Sprintf("mayfly:%v:codes", userId), anyx.ToString(codes), time.Minute*time.Duration(jwtConf.ExpireTime))
|
||||
}
|
||||
|
||||
func (r *RedisPermissionCodeRegistry) HasCode(userId uint64, code string) bool {
|
||||
|
||||
@@ -2,15 +2,33 @@ package req
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// JwtConf jwt配置
|
||||
type JwtConf struct {
|
||||
Key string
|
||||
ExpireTime uint64 // 过期时间,单位分钟
|
||||
RefreshTokenExpireTime uint64 // 刷新token的过期时间,单位分钟
|
||||
}
|
||||
|
||||
// 默认jwt配置
|
||||
var jwtConf = JwtConf{
|
||||
Key: stringx.RandUUID(),
|
||||
ExpireTime: 60,
|
||||
RefreshTokenExpireTime: 360,
|
||||
}
|
||||
|
||||
// SetJwtConf 设置jwt配置
|
||||
func SetJwtConf(conf JwtConf) {
|
||||
jwtConf = conf
|
||||
}
|
||||
|
||||
// 创建用户token
|
||||
func CreateToken(userId uint64, username string) (accessToken string, refreshToken string, err error) {
|
||||
jwtConf := config.Conf.Jwt
|
||||
now := time.Now()
|
||||
|
||||
// 带权限创建令牌
|
||||
@@ -46,7 +64,7 @@ func ParseToken(tokenStr string) (uint64, string, error) {
|
||||
|
||||
// Parse token
|
||||
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (any, error) {
|
||||
return []byte(config.Conf.Jwt.Key), nil
|
||||
return []byte(jwtConf.Key), nil
|
||||
})
|
||||
if err != nil || token == nil {
|
||||
return 0, "", err
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package starter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/logx"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
func printBanner() {
|
||||
buildInfo, _ := debug.ReadBuildInfo()
|
||||
logx.Print(fmt.Sprintf(`
|
||||
__ _
|
||||
_ __ ___ __ _ _ _ / _| |_ _ __ _ ___
|
||||
| '_ ' _ \ / _' | | | | |_| | | | |_____ / _' |/ _ \
|
||||
| | | | | | (_| | |_| | _| | |_| |_____| (_| | (_) | version: %s | go_version: %s | pid: %d
|
||||
|_| |_| |_|\__,_|\__, |_| |_|\__, | \__, |\___/
|
||||
|___/ |___/ |___/ `, config.Version, buildInfo.GoVersion, os.Getpid()))
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package starter
|
||||
|
||||
import (
|
||||
"log"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"time"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
func initDb() {
|
||||
global.Db = initGormDb()
|
||||
}
|
||||
|
||||
func initGormDb() *gorm.DB {
|
||||
m := config.Conf.Mysql
|
||||
// 存在msyql数据库名,则优先使用mysql
|
||||
if m.Dbname != "" {
|
||||
return initMysql(m)
|
||||
}
|
||||
|
||||
return initSqlite(config.Conf.Sqlite)
|
||||
}
|
||||
|
||||
func initMysql(m config.Mysql) *gorm.DB {
|
||||
logx.Infof("connecting to mysql [%s]", m.Host)
|
||||
mysqlConfig := mysql.Config{
|
||||
DSN: m.Dsn(), // DSN data source name
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
|
||||
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
|
||||
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
|
||||
SkipInitializeWithVersion: false, // 根据版本自动配置
|
||||
}
|
||||
|
||||
if db, err := gorm.Open(mysql.New(mysqlConfig), getGormConfig()); err != nil {
|
||||
logx.Panicf("failed to connect to mysql! [%s]", err.Error())
|
||||
return nil
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
func initSqlite(sc config.Sqlite) *gorm.DB {
|
||||
logx.Infof("connecting to sqlite [%s]", sc.Path)
|
||||
if db, err := gorm.Open(sqlite.Open(sc.Path), getGormConfig()); err != nil {
|
||||
logx.Panicf("failed to connect to sqlite! [%s]", err.Error())
|
||||
return nil
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(sc.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(sc.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
func getGormConfig() *gorm.Config {
|
||||
sqlLogLevel := logger.Error
|
||||
logConf := logx.GetConfig()
|
||||
// 如果为配置文件中配置的系统日志级别为debug,则打印gorm执行的sql信息
|
||||
if logConf.IsDebug() {
|
||||
sqlLogLevel = logger.Info
|
||||
}
|
||||
|
||||
gormLogger := logger.New(
|
||||
log.New(logConf.GetLogOut(), "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, // 慢 SQL 阈值
|
||||
LogLevel: sqlLogLevel, // 日志级别, 改为logger.Info即可显示sql语句
|
||||
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
|
||||
Colorful: false, // 禁用彩色打印
|
||||
},
|
||||
)
|
||||
|
||||
return &gorm.Config{NamingStrategy: schema.NamingStrategy{
|
||||
TablePrefix: "t_",
|
||||
SingularTable: true,
|
||||
}, Logger: gormLogger}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package starter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/rediscli"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
func initRedis() {
|
||||
rediscli.SetCli(connRedis())
|
||||
}
|
||||
|
||||
func connRedis() *redis.Client {
|
||||
// 设置redis客户端
|
||||
redisConf := config.Conf.Redis
|
||||
if redisConf.Host == "" {
|
||||
// logx.Panic("未找到redis配置信息")
|
||||
return nil
|
||||
}
|
||||
logx.Infof("连接redis [%s:%d]", redisConf.Host, redisConf.Port)
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%s:%d", redisConf.Host, redisConf.Port),
|
||||
Password: redisConf.Password, // no password set
|
||||
DB: redisConf.Db, // use default DB
|
||||
})
|
||||
// 测试连接
|
||||
_, e := rdb.Ping(context.TODO()).Result()
|
||||
if e != nil {
|
||||
logx.Panicf("连接redis失败! [%s:%d][%s]", redisConf.Host, redisConf.Port, e.Error())
|
||||
}
|
||||
return rdb
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package starter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/migration"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/validatorx"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func RunWebServer() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
go func() {
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
cancel()
|
||||
}()
|
||||
|
||||
// 初始化config.yml配置文件映射信息或使用环境变量。并初始化系统日志相关配置
|
||||
config.Init()
|
||||
|
||||
// 打印banner
|
||||
printBanner()
|
||||
|
||||
// 初始化并赋值数据库全局变量
|
||||
initDb()
|
||||
|
||||
// 有配置redis信息,则初始化redis。多台机器部署需要使用redis存储验证码、权限、公私钥等
|
||||
initRedis()
|
||||
|
||||
// 数据库升级操作
|
||||
if err := migration.RunMigrations(global.Db); err != nil {
|
||||
logx.Panicf("db migration failed: %v", err)
|
||||
}
|
||||
|
||||
// 参数校验器初始化、如错误提示中文转译等
|
||||
validatorx.Init()
|
||||
|
||||
// 初始化其他需要启动时运行的方法
|
||||
initialize.InitOther()
|
||||
|
||||
// 运行web服务
|
||||
runWebServer(ctx)
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package starter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/i18n"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/req"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
sysapp "mayfly-go/internal/sys/application"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func runWebServer(ctx context.Context) {
|
||||
// 设置gin日志输出器
|
||||
logOut := logx.GetConfig().GetLogOut()
|
||||
gin.DefaultErrorWriter = logOut
|
||||
gin.DefaultWriter = logOut
|
||||
|
||||
// 权限处理器
|
||||
req.UseBeforeHandlerInterceptor(req.PermissionHandler)
|
||||
// 日志处理器
|
||||
req.UseAfterHandlerInterceptor(req.LogHandler)
|
||||
// 设置日志保存函数
|
||||
req.SetSaveLogFunc(sysapp.GetSyslogApp().SaveFromReq)
|
||||
|
||||
i18n.SetLang(config.Conf.Server.Lang)
|
||||
|
||||
srv := http.Server{
|
||||
Addr: config.Conf.Server.GetPort(),
|
||||
// 注册路由
|
||||
Handler: initialize.InitRouter(),
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
logx.Info("Shutdown HTTP Server ...")
|
||||
timeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
err := srv.Shutdown(timeout)
|
||||
if err != nil {
|
||||
logx.Errorf("failed to Shutdown HTTP Server: %v", err)
|
||||
}
|
||||
|
||||
initialize.Terminate()
|
||||
}()
|
||||
|
||||
confSrv := config.Conf.Server
|
||||
logx.Infof("Listening and serving HTTP on %s", srv.Addr+confSrv.ContextPath)
|
||||
var err error
|
||||
if confSrv.Tls != nil && confSrv.Tls.Enable {
|
||||
err = srv.ListenAndServeTLS(confSrv.Tls.CertFile, confSrv.Tls.KeyFile)
|
||||
} else {
|
||||
err = srv.ListenAndServe()
|
||||
}
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
logx.Info("HTTP Server Shutdown")
|
||||
} else if err != nil {
|
||||
logx.Errorf("Failed to Start HTTP Server: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -14,13 +14,6 @@ var (
|
||||
patternErrMsg map[string]string
|
||||
)
|
||||
|
||||
// 注册自定义正则表达式校验规则
|
||||
func RegisterCustomPatterns() {
|
||||
// 账号用户名校验
|
||||
RegisterPattern("account_username", "^[a-zA-Z0-9_]{5,20}$", "只允许输入5-20位大小写字母、数字、下划线")
|
||||
RegisterPattern("resource_code", "^[a-zA-Z0-9_\\-.:]{1,32}$", "只允许输入1-32位大小写字母、数字、_-.:")
|
||||
}
|
||||
|
||||
// 注册自定义正则表达式
|
||||
func RegisterPattern(patternName string, regexpStr string, errMsg string) {
|
||||
if regexpMap == nil {
|
||||
|
||||
@@ -50,9 +50,6 @@ func Init() {
|
||||
|
||||
// 注册自定义校验器
|
||||
validate.RegisterValidation(CustomPatternTagName, patternValidFunc)
|
||||
|
||||
// 注册自定义正则校验规则
|
||||
RegisterCustomPatterns()
|
||||
}
|
||||
|
||||
// Translate 翻译错误信息
|
||||
|
||||
Reference in New Issue
Block a user