From bfb284c4cc89a608452f3b93a856aa4e9bf16cfd Mon Sep 17 00:00:00 2001 From: iuu <2167162990@qq.com> Date: Fri, 30 Aug 2024 11:55:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=20=E5=A4=84=E7=90=86=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + api/v1/peak_valley.go | 6 +- api/v1/test.go | 4 + config.yaml | 1 + config/config.go | 1 + core/cron/crontab.go | 44 ++++ core/{ => gorm}/gorm.go | 4 +- core/logger/logger.go | 91 ++++++++ core/validator.go | 2 - core/{ => viper}/viper.go | 2 +- global/logger.go | 14 ++ global/var.go | 2 + go.mod | 15 +- go.sum | 17 +- main.go | 94 ++------ middleware/log.go | 57 +++++ middleware/recovery.go | 46 ---- {core => model}/init-db-data/init.go | 0 .../init-db-data/peak_valley_time_block.go | 0 request/request.go | 186 ++++++++------- request/validator/validator.go | 57 +++++ response/response.go | 6 +- router/router.go | 26 ++- service/peak_valley.go | 54 ++--- utils/{exception => code}/code.go | 24 +- utils/exception/exception.go | 211 ++++++++++++------ utils/recovery/cron_recovery.go | 36 +++ utils/recovery/gin_recovery.go | 86 +++++++ utils/string.go | 179 +++++++++++++++ utils/utils.go | 15 ++ 30 files changed, 945 insertions(+), 336 deletions(-) create mode 100644 core/cron/crontab.go rename core/{ => gorm}/gorm.go (97%) create mode 100644 core/logger/logger.go delete mode 100644 core/validator.go rename core/{ => viper}/viper.go (98%) create mode 100644 global/logger.go create mode 100644 middleware/log.go rename {core => model}/init-db-data/init.go (100%) rename {core => model}/init-db-data/peak_valley_time_block.go (100%) create mode 100644 request/validator/validator.go rename utils/{exception => code}/code.go (52%) create mode 100644 utils/recovery/cron_recovery.go create mode 100644 utils/recovery/gin_recovery.go create mode 100644 utils/string.go diff --git a/.gitignore b/.gitignore index 5470aa0..6d8e79b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ main.exe go_build_energy_management_system.exe .idea +log \ No newline at end of file diff --git a/api/v1/peak_valley.go b/api/v1/peak_valley.go index c9bae35..4b603b3 100644 --- a/api/v1/peak_valley.go +++ b/api/v1/peak_valley.go @@ -41,7 +41,7 @@ func (r *PeakValley) UpdatePeakValleyQuarter(c *gin.Context) { func (r *PeakValley) PeakValleyQuarterEditDetail(c *gin.Context) { var req form.PeakValleyQuarterEditDetailReq id, err := strconv.Atoi(c.Param("id")) - exception.PanicMsgBool(err != nil, "参数有误") + exception.PBM(err != nil, "参数有误") req.Id = id respData := service.GroupServices.PeakValley.PeakValleyQuarterEditDetail(&req) response.SuccessData(respData, c) @@ -81,7 +81,7 @@ func (r *PeakValley) UpdatePeakValleyRule(c *gin.Context) { func (r *PeakValley) PeakValleyRuleDetail(c *gin.Context) { var req form.PeakValleyRuleDetailReq id, err := strconv.Atoi(c.Param("id")) - exception.PanicMsgBool(err != nil, "参数有误") + exception.PBM(err != nil, "参数有误") req.RuleId = id respData := service.GroupServices.PeakValley.PeakValleyRuleDetail(&req) response.SuccessData(respData, c) @@ -90,7 +90,7 @@ func (r *PeakValley) PeakValleyRuleDetail(c *gin.Context) { func (r *PeakValley) PeakValleyRuleEditDetail(c *gin.Context) { var req form.PeakValleyRuleEditDetailReq id, err := strconv.Atoi(c.Param("id")) - exception.PanicMsgBool(err != nil, "参数有误") + exception.PBM(err != nil, "参数有误") req.RuleId = id respData := service.GroupServices.PeakValley.PeakValleyRuleEditDetail(&req) response.SuccessData(respData, c) diff --git a/api/v1/test.go b/api/v1/test.go index 9c993fe..7eead9f 100644 --- a/api/v1/test.go +++ b/api/v1/test.go @@ -2,6 +2,8 @@ package v1 import ( "energy-management-system/response" + "energy-management-system/utils" + "fmt" "github.com/gin-gonic/gin" ) @@ -13,6 +15,8 @@ func (r *TestApi) Test(c *gin.Context) { } func (r *TestApi) TestData(c *gin.Context) { + x, y, z, e := utils.GetMinutesFromTimeRange("00:00", "05:01") + fmt.Println(x, y, z, e) response.SuccessData(gin.H{"userName": "iuu"}, c) } diff --git a/config.yaml b/config.yaml index d71163a..6eef66d 100644 --- a/config.yaml +++ b/config.yaml @@ -1,3 +1,4 @@ +is_debug: true service: http: host: 0.0.0.0 # 默认localhost diff --git a/config/config.go b/config/config.go index 425208d..a666ded 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,7 @@ const ( ) type Config struct { + IsDebug bool `mapstructure:"is_debug" json:"is_debug" yaml:"is_debug"` Db DbConf `mapstructure:"db" json:"db" yaml:"db"` Service ServiceConf `mapstructure:"service" json:"service" yaml:"service"` } diff --git a/core/cron/crontab.go b/core/cron/crontab.go new file mode 100644 index 0000000..af03145 --- /dev/null +++ b/core/cron/crontab.go @@ -0,0 +1,44 @@ +package cron + +import ( + "energy-management-system/utils" + "energy-management-system/utils/recovery" + "fmt" + "github.com/robfig/cron/v3" + "reflect" + "runtime" +) + +var servers server + +type server struct { + Cron []string + Func []func() +} + +func (c *server) register(cron string, f func()) { + c.Cron = append(c.Cron, cron) + c.Func = append(c.Func, f) +} + +func CronRun() { + c := cron.New() + for k, v := range servers.Cron { + eid, err := c.AddFunc(v, wrap(servers.Func[k])) + fmt.Println("定时任务:", eid, "添加成功") + utils.Exit(err, "添加定时器错误:") + } + c.Start() +} + +func wrap(f func()) func() { + return func() { + defer recovery.CronRecovery(runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()) + f() + } +} + +// Register 参数:规则(s m h d m w),函数 +func Register(rule string, f func()) { + servers.register(rule, f) +} diff --git a/core/gorm.go b/core/gorm/gorm.go similarity index 97% rename from core/gorm.go rename to core/gorm/gorm.go index a5cff6f..ca26a6a 100644 --- a/core/gorm.go +++ b/core/gorm/gorm.go @@ -1,8 +1,8 @@ -package core +package gorm import ( - init_db_data "energy-management-system/core/init-db-data" "energy-management-system/global" + "energy-management-system/model/init-db-data" peak_valley "energy-management-system/model/peak-valley" "fmt" "gorm.io/driver/postgres" diff --git a/core/logger/logger.go b/core/logger/logger.go new file mode 100644 index 0000000..c5803c7 --- /dev/null +++ b/core/logger/logger.go @@ -0,0 +1,91 @@ +package logger + +import ( + "energy-management-system/global" + "fmt" + rotatelogs "github.com/lestrrat-go/file-rotatelogs" + "github.com/sirupsen/logrus" + "runtime" + "strings" + "sync" + "time" +) + +func InitLogger() *global.Logger { + L := logrus.New() + path := "./log/log" + file, _ := rotatelogs.New( + path+".%Y%m%d", + rotatelogs.WithLinkName(path), + rotatelogs.WithMaxAge(time.Duration(100*24)*time.Hour), //自动删除 + rotatelogs.WithRotationTime(time.Duration(24*60)*time.Minute), //分割时间 + ) + L.SetOutput(file) + L.SetFormatter(&logrus.JSONFormatter{}) + Log := &global.Logger{Logger: L, Heads: []string{}} + global.Log = Log + return Log +} + +var errs = &errFunc{lock: new(sync.Mutex)} + +func ErrorRegister(f func(string)) { + errs.register(f, false) +} +func ErrorRegisterOnly1(f func(string)) { + errs.register(f, true) +} +func ErrorWx(e ...string) { + errs.run(strings.Join(e, " ")) + global.Log.Error(e) +} + +type errFunc struct { + f []func(string) + lastTime int64 + lock *sync.Mutex +} + +func (e *errFunc) register(f func(string), only bool) { + if only { + e.f = []func(string){f} + } else { + e.f = append(e.f, f) + } +} + +func (e *errFunc) run(logs string) { + if len(e.f) == 0 { + return + } + if time.Now().Unix()-e.lastTime > 1 { + e.lock.Lock() + e.lastTime = time.Now().Unix() + defer e.lock.Unlock() + for _, v := range e.f { + v(logs) + } + } +} + +func StackSend(skip int, e string) { + e += "\n" + Stack(skip) + if global.AppConf.IsDebug { + fmt.Print(e) + } + errs.run(e) +} + +func Stack(skip int) (re string) { + for i := skip; ; i++ { + _, file, line, ok := runtime.Caller(i) + if !ok { + break + } + if !strings.Contains(file, "local/go/src") && !strings.Contains(file, "/go/pkg") { + logs := fmt.Sprintf("%s:%d\n", file, line) + re += logs + } + } + return +} diff --git a/core/validator.go b/core/validator.go deleted file mode 100644 index 25dcb76..0000000 --- a/core/validator.go +++ /dev/null @@ -1,2 +0,0 @@ -package core - diff --git a/core/viper.go b/core/viper/viper.go similarity index 98% rename from core/viper.go rename to core/viper/viper.go index 6569dc7..b0ed4d9 100644 --- a/core/viper.go +++ b/core/viper/viper.go @@ -1,4 +1,4 @@ -package core +package viper import ( "energy-management-system/config" diff --git a/global/logger.go b/global/logger.go new file mode 100644 index 0000000..93ce028 --- /dev/null +++ b/global/logger.go @@ -0,0 +1,14 @@ +package global + +import "github.com/sirupsen/logrus" + +type Logger struct { + *logrus.Logger + Heads []string +} + +func (l *Logger) AddHead(args ...string) { + for _, v := range args { + l.Heads = append(l.Heads, v) + } +} diff --git a/global/var.go b/global/var.go index 970e468..86e1260 100644 --- a/global/var.go +++ b/global/var.go @@ -11,6 +11,8 @@ var ( // Db 数据库 Db *gorm.DB + Log *Logger + // Trans 定义一个全局翻译器T //Trans ut.Translator //Validate *validator.Validate diff --git a/go.mod b/go.mod index 52aec34..89200d3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,12 @@ go 1.22 require ( github.com/fsnotify/fsnotify v1.7.0 github.com/gin-gonic/gin v1.10.0 - github.com/gookit/goutil v0.6.16 + github.com/go-playground/locales v0.14.1 + github.com/go-playground/universal-translator v0.18.1 + github.com/go-playground/validator/v10 v10.20.0 + github.com/gookit/color v1.5.4 + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible + github.com/sirupsen/logrus v1.9.3 github.com/spf13/viper v1.19.0 gorm.io/driver/postgres v1.5.9 gorm.io/gorm v1.25.11 @@ -18,11 +23,7 @@ require ( github.com/cloudwego/iasm v0.2.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/gookit/color v1.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect @@ -30,15 +31,19 @@ require ( github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/lestrrat-go/strftime v1.1.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/robfig/cron/v3 v3.0.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect diff --git a/go.sum b/go.sum index 9a21552..3bf1df9 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= -github.com/gookit/goutil v0.6.16 h1:9fRMCF4X9abdRD5+2HhBS/GwafjBlTUBjRtA5dgkvuw= -github.com/gookit/goutil v0.6.16/go.mod h1:op2q8AoPDFSiY2+qkHxcBWQMYxOLQ1GbLXqe7vrwscI= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -51,6 +49,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -63,6 +63,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.1.0 h1:gMESpZy44/4pXLO/m+sL0yBd1W6LjgjrrD4a68Gapyg= +github.com/lestrrat-go/strftime v1.1.0/go.mod h1:uzeIB52CeUJenCo1syghlugshMysrqUT51HlxphXVeI= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -76,15 +82,21 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E= +github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -130,6 +142,7 @@ golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= diff --git a/main.go b/main.go index d8abad0..4e28280 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,12 @@ package main import ( "context" - "energy-management-system/core" + "energy-management-system/core/cron" + "energy-management-system/core/gorm" + "energy-management-system/core/logger" + "energy-management-system/core/viper" "energy-management-system/global" - "energy-management-system/request" + "energy-management-system/request/validator" "energy-management-system/router" "errors" "fmt" @@ -16,19 +19,26 @@ import ( func init() { // 配置 - core.InitViper() + viper.InitViper() + // 日志 + logger.InitLogger() // 数据库 - core.InitGorm() + gorm.InitGorm() // gin验证器 - request.InitTrans() + validator.InitTrans() // 可选初始化表结构 - core.AutoMigrate(global.Db) + gorm.AutoMigrate(global.Db) // 可选初始化表数据 - core.AutoInitDbData() + gorm.AutoInitDbData() } func main() { + cron.Register("0/1 * * * * ", func() { + fmt.Println(time.Now()) + }) + cron.CronRun() + r := router.InitRouter() host := global.AppConf.Service.Http.Host port := global.AppConf.Service.Http.Port @@ -39,78 +49,8 @@ func main() { // 优雅关闭 gracefulShutdown(srv) - - //// 定义一个切片来接收查询结果 - //var users []peaks_valleys.PeakValleyTimeBlock - // - //// 查询所有用户 - //result := global.Db.Find(&users) - //if result.Error != nil { - // fmt.Println("Error:", result.Error) - //} - // - //// 打印查询结果 - //for _, user := range users { - // - // if user.BlockIndex < 20 { - // global.Db.Create(&peaks_valleys.PeakValleyTimeBlockPrice{ - // BlockId: user.BlockIndex, - // Price: 35, - // PeakValleyType: 5, - // }) - // } else if user.BlockIndex < 40 { - // global.Db.Create(&peaks_valleys.PeakValleyTimeBlockPrice{ - // BlockId: user.BlockIndex, - // Price: 45, - // PeakValleyType: 4, - // }) - // } else if user.BlockIndex < 60 { - // global.Db.Create(&peaks_valleys.PeakValleyTimeBlockPrice{ - // BlockId: user.BlockIndex, - // Price: 55, - // PeakValleyType: 3, - // }) - // } else if user.BlockIndex < 80 { - // global.Db.Create(&peaks_valleys.PeakValleyTimeBlockPrice{ - // BlockId: user.BlockIndex, - // Price: 65, - // PeakValleyType: 2, - // }) - // } else if user.BlockIndex < 100 { - // global.Db.Create(&peaks_valleys.PeakValleyTimeBlockPrice{ - // BlockId: user.BlockIndex, - // Price: 85, - // PeakValleyType: 1, - // }) - // } else if user.BlockIndex <= 144 { - // global.Db.Create(&peaks_valleys.PeakValleyTimeBlockPrice{ - // BlockId: user.BlockIndex, - // Price: 35, - // PeakValleyType: 5, - // }) - // } - // - // //fmt.Printf("ID: %d, Name: %s, Email: %s\n", user.BlockIndex) - //} - } -//func loadConfig() (host, port string) { -// host = viper.GetString("service.http.host") -// if host == "" { -// host = "localhost" -// fmt.Println("Using default host:", host) -// } -// -// port = viper.GetString("service.http.port") -// if port == "" { -// port = "9999" -// fmt.Println("Using default port:", port) -// } -// -// return host, port -//} - func initServer(host, port string, handler http.Handler) *http.Server { return &http.Server{ Addr: fmt.Sprintf("%s:%s", host, port), diff --git a/middleware/log.go b/middleware/log.go new file mode 100644 index 0000000..3216241 --- /dev/null +++ b/middleware/log.go @@ -0,0 +1,57 @@ +package middleware + +import ( + "bytes" + "energy-management-system/global" + "energy-management-system/utils/exception" + "github.com/gin-gonic/gin" + "io" + "net/url" + "strings" + "time" +) + +func Log(c *gin.Context) { + // 开始时间 + startTime := time.Now() + var body []byte + if c.Request.Method != "GET" { + if strings.Contains(c.GetHeader("Content-Type"), "application/json") { + var e error + if body, e = io.ReadAll(c.Request.Body); e == nil { + c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + } + } + } // 处理请求 + c.Next() + // 执行时间 + latencyTime := time.Now().Sub(startTime).String() + // 日志格式 + path, _ := url.PathUnescape(c.Request.RequestURI) + // + field := map[string]any{ + "ip": c.ClientIP(), + "method": c.Request.Method, + "url": path, + "code": c.Writer.Status(), + "period": latencyTime, + "model": "gin", + } + if len(global.Log.Heads) > 0 { + for _, v := range global.Log.Heads { + field[v] = c.Request.Header.Get(v) + } + } + if err := c.Errors.Last(); err != nil { + if h, ok := err.Meta.(*exception.E); ok { + field["code"] = h.Code + field["errMsg"] = h.Msg + if h.Err != nil { + field["err"] = h.Err.Error() + } + } + global.Log.WithFields(field).Error(string(body)) + } else { + global.Log.WithFields(field).Info(string(body)) + } +} diff --git a/middleware/recovery.go b/middleware/recovery.go index 6894d59..76806ed 100644 --- a/middleware/recovery.go +++ b/middleware/recovery.go @@ -1,48 +1,2 @@ package middleware -import ( - "energy-management-system/utils" - "energy-management-system/utils/exception" - "fmt" - "github.com/gin-gonic/gin" - "net" - "os" - "strings" - "time" -) - -func Recovery() gin.HandlerFunc { - return func(c *gin.Context) { - defer func() { - if err := recover(); err != nil { - var brokenPipe bool - if ne, ok := err.(*net.OpError); ok { - if se, ok := ne.Err.(*os.SyscallError); ok { - if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { - brokenPipe = true - } - } - } - if brokenPipe { - c.Error(err.(error)) - } else { - if h, ok := err.(*exception.Exception); ok { - exception.Panic(c, h) - c.Errors = append(c.Errors, &gin.Error{Meta: h}) - } else if _, ok = err.(error); ok { - if gin.IsDebugging() { - fmt.Printf("[Recovery] %s : %s", utils.TimeFormat(time.Now()), err) - utils.Stack(3) - } - exception.Unknow(c) - } else { - fmt.Print(err) - exception.Server(c) - } - } - c.Abort() - } - }() - c.Next() - } -} diff --git a/core/init-db-data/init.go b/model/init-db-data/init.go similarity index 100% rename from core/init-db-data/init.go rename to model/init-db-data/init.go diff --git a/core/init-db-data/peak_valley_time_block.go b/model/init-db-data/peak_valley_time_block.go similarity index 100% rename from core/init-db-data/peak_valley_time_block.go rename to model/init-db-data/peak_valley_time_block.go diff --git a/request/request.go b/request/request.go index 7edf05e..d3c7a97 100644 --- a/request/request.go +++ b/request/request.go @@ -2,104 +2,136 @@ package request import ( "encoding/json" + req_validator "energy-management-system/request/validator" + "energy-management-system/utils/code" "energy-management-system/utils/exception" - "errors" "fmt" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" - "github.com/go-playground/locales/en" - "github.com/go-playground/locales/zh" - ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" - zhTranslations "github.com/go-playground/validator/v10/translations/zh" - "os" - "reflect" - "regexp" "strconv" - "strings" ) // Trans 定义一个全局翻译器T -var trans ut.Translator -var validate *validator.Validate -var ok bool +//var trans ut.Translator +//var validate *validator.Validate +//var ok bool // InitTrans 初始化翻译器 -func InitTrans(locale ...string) { - if len(locale) == 0 { - locale = []string{"zh"} - } - // 修改gin框架中的Validator引擎属性,实现自定制 - if validate, ok = binding.Validator.Engine().(*validator.Validate); ok { +//func InitTrans(locale ...string) { +// if len(locale) == 0 { +// locale = []string{"zh"} +// } +// // 修改gin框架中的Validator引擎属性,实现自定制 +// if validate, ok = binding.Validator.Engine().(*validator.Validate); ok { +// +// // zi +// //validate.SetTagName("ss") +// +// validate.RegisterTagNameFunc(func(fld reflect.StructField) string { +// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] +// if name == "-" || name == "_" { +// return "" +// } +// return name +// }) +// +// // 第一个参数是备用(fallback)的语言环境 +// uni := ut.New(en.New(), zh.New()) +// trans, _ = uni.FindTranslator(locale[0]) +// // 注册翻译器 +// err := zhTranslations.RegisterDefaultTranslations(validate, trans) +// +// // 注册自定义验证 +// validate.RegisterValidation("mobile", func(fl validator.FieldLevel) bool { +// regRuler := "^1[3456789]{1}\\d{9}$" +// reg := regexp.MustCompile(regRuler) +// return reg.MatchString(fl.Field().String()) +// }) +// +// // 注册自定义验证的翻译 +// validate.RegisterTranslation("mobile", trans, func(ut ut.Translator) error { +// return ut.Add("mobile", "手机号错误!", true) +// }, func(ut ut.Translator, fe validator.FieldError) string { +// t, _ := ut.T("mobile", fe.Field()) +// return t +// }) +// +// if err != nil { +// fmt.Printf("[-]自定义gin验证器失败: %s \n", err) +// os.Exit(0) +// } +// } +//} - // zi - //validate.SetTagName("ss") +//func BindJson(c *gin.Context, f interface{}) { +// dealWithError(c.ShouldBindJSON(f), "JSON") +//} +//func BindJsonWith(c *gin.Context, f interface{}) { +// dealWithError(c.ShouldBindBodyWith(f, binding.JSON), "JSON") +//} +//func BindParam(c *gin.Context, f interface{}) { +// dealWithError(c.ShouldBindQuery(f), "FORM") +//} +// +//func dealWithError(err error, t string) { +// if err != nil { +// var validationErrors validator.ValidationErrors +// var unmarshalTypeError *json.UnmarshalTypeError +// var numError *strconv.NumError +// switch { +// case errors.As(err, &validationErrors): +// exception.PanicMsg(removeTopStruct(err.(validator.ValidationErrors).Translate(trans))) +// case errors.As(err, &unmarshalTypeError): +// exception.PanicCodeMsg(code.PARAMETER_ERROR, err.(*json.UnmarshalTypeError).Field+": 类型错误") +// case errors.As(err, &numError): +// exception.PanicCodeMsg(code.PARAMETER_ERROR, err.(*strconv.NumError).Num+": 类型错误") +// default: +// exception.PanicCodeMsg(code.PARAMETER_ERROR, fmt.Sprintf("请将参数放于%s中传递: ", t)+err.Error()) +// } +// } +//} +// +//func removeTopStruct(fields map[string]string) (re []string) { +// for _, err := range fields { +// re = append(re, err) +// } +// return +//} - validate.RegisterTagNameFunc(func(fld reflect.StructField) string { - name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] - if name == "-" || name == "_" { - return "" - } - return name - }) - - // 第一个参数是备用(fallback)的语言环境 - uni := ut.New(en.New(), zh.New()) - trans, _ = uni.FindTranslator(locale[0]) - // 注册翻译器 - err := zhTranslations.RegisterDefaultTranslations(validate, trans) - - // 注册自定义验证 - validate.RegisterValidation("mobile", func(fl validator.FieldLevel) bool { - regRuler := "^1[3456789]{1}\\d{9}$" - reg := regexp.MustCompile(regRuler) - return reg.MatchString(fl.Field().String()) - }) - - // 注册自定义验证的翻译 - validate.RegisterTranslation("mobile", trans, func(ut ut.Translator) error { - return ut.Add("mobile", "手机号错误!", true) - }, func(ut ut.Translator, fe validator.FieldError) string { - t, _ := ut.T("mobile", fe.Field()) - return t - }) - - if err != nil { - fmt.Printf("[-]自定义gin验证器失败: %s \n", err) - os.Exit(0) - } - } +func BindJson(c *gin.Context, f any) { + err := c.ShouldBindJSON(f) + //if gin.IsDebugging() { + // c.Set("_req", f) + //doc.SetReq(c, f) + //} + DealValidError(err, "JSON") +} +func BindJsonWith(c *gin.Context, f any) { + DealValidError(c.ShouldBindBodyWith(f, binding.JSON), "JSON") +} +func BindParam(c *gin.Context, f any) { + err := c.ShouldBindQuery(f) + //doc.SetReq(c, f) + DealValidError(err, "FORM") } -func BindJson(c *gin.Context, f interface{}) { - dealWithError(c.ShouldBindJSON(f), "JSON") -} -func BindJsonWith(c *gin.Context, f interface{}) { - dealWithError(c.ShouldBindBodyWith(f, binding.JSON), "JSON") -} -func BindParam(c *gin.Context, f interface{}) { - dealWithError(c.ShouldBindQuery(f), "FORM") -} - -func dealWithError(err error, t string) { +func DealValidError(err error, t string) { if err != nil { - var validationErrors validator.ValidationErrors - var unmarshalTypeError *json.UnmarshalTypeError - var numError *strconv.NumError - switch { - case errors.As(err, &validationErrors): - exception.PanicMsg(removeTopStruct(err.(validator.ValidationErrors).Translate(trans))) - case errors.As(err, &unmarshalTypeError): - exception.PanicCodeMsg(exception.PARAMETER_ERROR, err.(*json.UnmarshalTypeError).Field+": 类型错误") - case errors.As(err, &numError): - exception.PanicCodeMsg(exception.PARAMETER_ERROR, err.(*strconv.NumError).Num+": 类型错误") + switch err.(type) { + case validator.ValidationErrors: + exception.PM(RemoveTopStruct(err.(validator.ValidationErrors).Translate(req_validator.Trans))) + case *json.UnmarshalTypeError: + exception.PMC(err.(*json.UnmarshalTypeError).Field+": 类型错误", code.PARAMETER_ERROR) + case *strconv.NumError: + exception.PMC(err.(*strconv.NumError).Num+": 类型错误", code.PARAMETER_ERROR) default: - exception.PanicCodeMsg(exception.PARAMETER_ERROR, fmt.Sprintf("请将参数放于%s中传递: ", t)+err.Error()) + exception.PMC(fmt.Sprintf("请将参数放于%s中传递: ", t)+err.Error(), code.PARAMETER_ERROR) } } } -func removeTopStruct(fields map[string]string) (re []string) { +func RemoveTopStruct(fields map[string]string) (re []string) { for _, err := range fields { re = append(re, err) } diff --git a/request/validator/validator.go b/request/validator/validator.go new file mode 100644 index 0000000..0b2dab8 --- /dev/null +++ b/request/validator/validator.go @@ -0,0 +1,57 @@ +package validator + +import ( + "fmt" + "github.com/gin-gonic/gin/binding" + "github.com/go-playground/locales/en" + "github.com/go-playground/locales/zh" + ut "github.com/go-playground/universal-translator" + "github.com/go-playground/validator/v10" + zhTranslations "github.com/go-playground/validator/v10/translations/zh" + "os" + "reflect" + "regexp" + "strings" +) + +// 定义一个全局翻译器T + +var Trans ut.Translator +var Validate *validator.Validate + +// InitTrans 初始化翻译器 +func InitTrans(locale ...string) { + if len(locale) == 0 { + locale = []string{"zh"} + } + + var ok bool + if Validate, ok = binding.Validator.Engine().(*validator.Validate); ok { + Validate.RegisterTagNameFunc(func(fld reflect.StructField) string { + name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] + if name == "-" || name == "_" { + return "" + } + return name + }) + uni := ut.New(en.New(), zh.New()) + Trans, _ = uni.FindTranslator(locale[0]) + err := zhTranslations.RegisterDefaultTranslations(Validate, Trans) + + Validate.RegisterValidation("mobile", func(fl validator.FieldLevel) bool { + regRuler := "^1[3456789]{1}\\d{9}$" + reg := regexp.MustCompile(regRuler) + return reg.MatchString(fl.Field().String()) + }) + Validate.RegisterTranslation("mobile", Trans, func(ut ut.Translator) error { + return ut.Add("mobile", "手机号错误!", true) + }, func(ut ut.Translator, fe validator.FieldError) string { + t, _ := ut.T("mobile", fe.Field()) + return t + }) + if err != nil { + fmt.Printf("[-]自定义gin验证器失败: %s \n", err) + os.Exit(1) + } + } +} diff --git a/response/response.go b/response/response.go index 80e1705..745970e 100644 --- a/response/response.go +++ b/response/response.go @@ -1,7 +1,7 @@ package response import ( - "energy-management-system/utils/exception" + "energy-management-system/utils/code" "github.com/gin-gonic/gin" "net/http" ) @@ -22,9 +22,9 @@ func Success(c *gin.Context) { } func SuccessMsg(message string, c *gin.Context) { - Result(exception.SUCCESS, map[string]interface{}{}, message, c) + Result(code.SUCCESS, map[string]interface{}{}, message, c) } func SuccessData(data interface{}, c *gin.Context) { - Result(exception.SUCCESS, data, "操作成功", c) + Result(code.SUCCESS, data, "操作成功", c) } diff --git a/router/router.go b/router/router.go index 68170f5..198b7af 100644 --- a/router/router.go +++ b/router/router.go @@ -2,18 +2,36 @@ package router import ( v1 "energy-management-system/api/v1" + "energy-management-system/global" "energy-management-system/middleware" "energy-management-system/router/routes" + "energy-management-system/utils/code" "energy-management-system/utils/exception" + "energy-management-system/utils/recovery" "github.com/gin-gonic/gin" + "net/http" ) func InitRouter() *gin.Engine { - gin.SetMode(gin.DebugMode) + + if global.AppConf.IsDebug { + gin.SetMode(gin.DebugMode) + } else { + gin.SetMode("release") + } + r := gin.Default() - r.NoRoute(exception.NotFoundR) - r.NoMethod(exception.NotFoundM) - r.Use(middleware.Cors(), middleware.Recovery()) + //r.NoRoute(exception.NotFoundR) + //r.NoMethod(exception.NotFoundM) + + r.NoRoute(func(c *gin.Context) { + c.JSON(http.StatusForbidden, exception.E{Code: code.NOT_FOUND_ROUTE, Msg: "Not Found Route", Err: nil}) + }) + r.NoMethod(func(c *gin.Context) { + c.JSON(http.StatusForbidden, exception.E{Code: code.NOT_FOUND_METH, Msg: "Not Found Method"}) + }) + + r.Use(middleware.Cors(), middleware.Log, recovery.GinRecovery) api := r.Group("api") { controllersV1 := new(v1.Controller) diff --git a/service/peak_valley.go b/service/peak_valley.go index 311f447..e9d83c0 100644 --- a/service/peak_valley.go +++ b/service/peak_valley.go @@ -20,7 +20,7 @@ type PeakValley struct{} func (r *PeakValley) PeakValleyQuarterPage(req *form.PeakValleyQuarterListReq) map[string]interface{} { count, list, err := repository.GroupRepositorys.PeakValley.GetPeakValleyQuarterPage(req) if err != nil { - exception.PanicMsgErr(err, "获取列表失败") + exception.PEM(err, "获取列表失败") //return } ListRsp := make(map[string]interface{}) @@ -32,7 +32,7 @@ func (r *PeakValley) PeakValleyQuarterPage(req *form.PeakValleyQuarterListReq) m // PeakValleyQuarterEditDetail 获取季度详情-编辑使用 func (r *PeakValley) PeakValleyQuarterEditDetail(req *form.PeakValleyQuarterEditDetailReq) *peak_valley_model.PeakValleyQuarter { pvq, err := repository.GroupRepositorys.PeakValley.GetOnePeakValleyQuarter(map[string]interface{}{"id": req.Id}) - exception.PanicMsgBool(err != nil, "获取季度详情失败") + exception.PBM(err != nil, "获取季度详情失败") return pvq } @@ -44,11 +44,11 @@ func (r *PeakValley) CreatePeakValleyQuarter(req *form.CreatePeakValleyQuarterRe pvq.Rid = req.RuleId startTime, err := time.Parse("2006-01-02", req.StartTime) endTime, err := time.Parse("2006-01-02", req.EndTime) - exception.PanicMsgBool(err != nil, "时间解析失败") + exception.PBM(err != nil, "时间解析失败") pvq.StartTime = startTime pvq.EndTime = endTime err = repository.GroupRepositorys.PeakValley.CreatePeakValleyQuarter(pvq) - exception.PanicMsgBool(err != nil, "创建季度失败") + exception.PBM(err != nil, "创建季度失败") return } @@ -56,16 +56,16 @@ func (r *PeakValley) CreatePeakValleyQuarter(req *form.CreatePeakValleyQuarterRe func (r *PeakValley) UpdatePeakValleyQuarter(req *form.UpdatePeakValleyQuarterReq) { var err error pvq, err := repository.GroupRepositorys.PeakValley.GetOnePeakValleyQuarter(map[string]interface{}{"id": req.Id}) - exception.PanicMsgBool(err != nil, "修改季度失败") + exception.PBM(err != nil, "修改季度失败") startTime, err := time.Parse("2006-01-02", req.StartTime) endTime, err := time.Parse("2006-01-02", req.EndTime) - exception.PanicMsgBool(err != nil, "时间解析失败") + exception.PBM(err != nil, "时间解析失败") pvq.QuarterName = req.QuarterName pvq.Rid = req.RuleId pvq.StartTime = startTime pvq.EndTime = endTime err = repository.GroupRepositorys.PeakValley.UpdatePeakValleyQuarter(pvq) - exception.PanicMsgBool(err != nil, "修改季度失败") + exception.PBM(err != nil, "修改季度失败") return } @@ -90,15 +90,15 @@ func (r *PeakValley) CreatePeakValleyRule(req *form.CreatePeakValleyRuleReq) { if rec := recover(); rec != nil { tx.Rollback() // 如果发生错误,回滚事务 fmt.Println("事务回滚") - exception.PanicMsg(rec) + exception.PM(rec) } else if err != nil { tx.Rollback() // 错误时回滚事务 fmt.Println("事务回滚") - exception.PanicMsgErr(err, err.Error()) + exception.PEM(err, err.Error()) } else { err = tx.Commit().Error // 提交事务 if err != nil { - exception.PanicMsgErr(err, "事务提交失败") + exception.PEM(err, "事务提交失败") } } }() @@ -180,15 +180,15 @@ func (r *PeakValley) UpdatePeakValleyRule(req *form.UpdatePeakValleyRuleReq) { if rec := recover(); rec != nil { tx.Rollback() // 如果发生错误,回滚事务 fmt.Println("事务回滚1", rec) - exception.PanicMsg(rec) + exception.PM(rec) } else if err != nil { tx.Rollback() // 错误时回滚事务 fmt.Println("事务回滚2", err) - exception.PanicMsgErr(err, err.Error()) + exception.PEM(err, err.Error()) } else { err = tx.Commit().Error // 提交事务 if err != nil { - exception.PanicMsgErr(err, "事务提交失败") + exception.PEM(err, "事务提交失败") } } }() @@ -235,7 +235,7 @@ func (r *PeakValley) UpdatePeakValleyRule(req *form.UpdatePeakValleyRuleReq) { return } timeBlockIds, err = repository.GroupRepositorys.PeakValley.GetTimeBlockIdsByTimeBlock(tx, uint(start), uint(end)) - exception.PanicMsgBool(err != nil, "获取时间区块ID列表失败") + exception.PBM(err != nil, "获取时间区块ID列表失败") timeBlockIdsMap[item.StartTime+item.EndTime] = timeBlockIds } if total < peak_valley_model.MinutesInADay { @@ -273,7 +273,7 @@ func (r *PeakValley) UpdatePeakValleyRule(req *form.UpdatePeakValleyRuleReq) { func (r *PeakValley) GetPeakValleyRulePage(req *form.PeakValleyRuleListReq) map[string]interface{} { count, list, err := repository.GroupRepositorys.PeakValley.GetPeakValleyRulePage(req) if err != nil { - exception.PanicMsgErr(err, "获取列表失败") + exception.PEM(err, "获取列表失败") //return } ListRsp := make(map[string]interface{}) @@ -287,23 +287,23 @@ func (r *PeakValley) PeakValleyRuleDetail(req *form.PeakValleyRuleDetailReq) map // 获取分了多少个时间段 以及每个时间段的自定义名称 峰谷类型 ruleTypes, err := repository.GroupRepositorys.PeakValley.GetPeakValleyRuleTypes(req.RuleId) fmt.Println(ruleTypes) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败1") + exception.PBM(err != nil, "获取规则区块类型失败1") // 查询指定规则 指定峰谷类型的区块 for idx, ruleType := range ruleTypes { // 查询当前类型的时间区块 typeBlockList, err := repository.GroupRepositorys.PeakValley.GetPeakValleyRulePriceByTypeAndRuleID(uint(req.RuleId), ruleType.PeakValleyType) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败2") + exception.PBM(err != nil, "获取规则区块类型失败2") // 根据连贯性 小区块 组合成大区块 (一个区块 或者多个区块) blocks := utils.SplitIntoGroups(typeBlockList) for _, block := range blocks { maxBlockId, minBlockId, err := utils.GetSplitIntMaxMin(block) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败3") + exception.PBM(err != nil, "获取规则区块类型失败3") customName, err := repository.GroupRepositorys.PeakValley.GetPeakValleyRulePriceCustomName(minBlockId, uint(req.RuleId)) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败4") + exception.PBM(err != nil, "获取规则区块类型失败4") startTime, err := repository.GroupRepositorys.PeakValley.GetBlockStartTime(minBlockId) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败5") + exception.PBM(err != nil, "获取规则区块类型失败5") endTime, err := repository.GroupRepositorys.PeakValley.GetBlockEndTime(maxBlockId) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败6") + exception.PBM(err != nil, "获取规则区块类型失败6") startTimeStr := fmt.Sprintf("%02d:%02d", startTime/60, startTime%60) endTimeStr := fmt.Sprintf("%02d:%02d", endTime/60, endTime%60) ruleTimeBlock := peak_valley_model.RuleTimeBlock{ @@ -326,21 +326,21 @@ func (r *PeakValley) PeakValleyRuleDetail(req *form.PeakValleyRuleDetailReq) map // PeakValleyRuleEditDetail 获取规则详情-编辑使用 func (r *PeakValley) PeakValleyRuleEditDetail(req *form.PeakValleyRuleEditDetailReq) map[string]interface{} { pvr, err := repository.GroupRepositorys.PeakValley.GetOnePeakValleyRule(map[string]interface{}{"rule_id": req.RuleId}) - exception.PanicMsgBool(err != nil, "获取规则详情失败") + exception.PBM(err != nil, "获取规则详情失败") // 获取分了多少个时间段 以及每个时间段的自定义名称 峰谷类型 customNames, err := repository.GroupRepositorys.PeakValley.GetPeakValleyRuleCustomName(req.RuleId) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败1") + exception.PBM(err != nil, "获取规则区块类型失败1") // 查询指定规则 指定峰谷类型的区块 for idx, customName := range customNames { // 查询当前类型的时间区块 customNameBlockList, err := repository.GroupRepositorys.PeakValley.GetPeakValleyRulePriceByCustomNameAndRuleID(uint(req.RuleId), customName.CustomName) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败2") + exception.PBM(err != nil, "获取规则区块类型失败2") maxBlockId, minBlockId, err := utils.GetSplitIntMaxMin(customNameBlockList) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败3") + exception.PBM(err != nil, "获取规则区块类型失败3") startTime, err := repository.GroupRepositorys.PeakValley.GetBlockStartTime(minBlockId) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败4") + exception.PBM(err != nil, "获取规则区块类型失败4") endTime, err := repository.GroupRepositorys.PeakValley.GetBlockEndTime(maxBlockId) - exception.PanicMsgBool(err != nil, "获取规则区块类型失败5") + exception.PBM(err != nil, "获取规则区块类型失败5") startTimeStr := fmt.Sprintf("%02d:%02d", startTime/60, startTime%60) endTimeStr := fmt.Sprintf("%02d:%02d", endTime/60, endTime%60) //dump.P(customNameBlockList) diff --git a/utils/exception/code.go b/utils/code/code.go similarity index 52% rename from utils/exception/code.go rename to utils/code/code.go index f665395..1b71372 100644 --- a/utils/exception/code.go +++ b/utils/code/code.go @@ -1,4 +1,4 @@ -package exception +package code const ( SUCCESS = 1 // 操作成功 @@ -23,25 +23,3 @@ const ( DB_ERRROR = 10027 // 数据库错误 SENSITIVE = 10028 // 敏感词语 ) -const ( - //用户 - NOT_FOUND_USER = 20001 // 未查询到用户 - EXIST_USER = 20002 // 用户已存在 - NO_BELONG_ACTION = 20003 // 越权操作 - NO_PHONE = 20004 // 未验证手机号 - - //订单 - ORDER_ERROR = 20100 // 订单统用错误 - NO_ORDER = 20101 // 订单不存在 - NO_PAID_ORDER = 20102 // 订单未支付 - PAID_ORDER = 20103 // 订单已支付 - EXPIRE_ORDER = 20104 // 订单超时 - DONE_ORDER = 20105 // 订单已完结 - NO_BELONG_ORDER = 20106 // 不属于自己的订单 - - //积分 - SIGNED = 20200 // 已签到 - NO_ENOUGH_POINT = 20201 // 积分不足 - NO_ILLEGAL_CHANNEL = 20202 // 渠道非法 - NO_ILLEGAL_SIGN = 20203 // 渠道非签到 -) diff --git a/utils/exception/exception.go b/utils/exception/exception.go index 7440a60..cc06ce4 100644 --- a/utils/exception/exception.go +++ b/utils/exception/exception.go @@ -1,81 +1,164 @@ package exception import ( - "energy-management-system/utils" - "net/http" - + "energy-management-system/utils/code" + "fmt" "github.com/gin-gonic/gin" + "gorm.io/gorm" + "net/http" ) -type Exception struct { - HttpCode int `json:"-"` - Code int `json:"code"` - Msg interface{} `json:"msg"` - Err error `json:"err"` +type E struct { + Code int `json:"code"` + Msg any `json:"msg"` + Err error `json:"-"` } -type ExceptionResponse struct { - Code int `json:"code"` - Msg interface{} `json:"msg"` - Path string `json:"path"` -} - -func (r *Exception) Error() interface{} { - return r.Msg -} - -func NotFoundR(c *gin.Context) { - c.JSON(http.StatusForbidden, ExceptionResponse{NOT_FOUND_ROUTE, "Not Found Route", utils.GetReqPath(c)}) -} - -func NotFoundM(c *gin.Context) { - c.JSON(http.StatusForbidden, ExceptionResponse{NOT_FOUND_METH, "Not Found Method", utils.GetReqPath(c)}) -} - -func Panic(c *gin.Context, e *Exception) { - c.JSON(e.HttpCode, ExceptionResponse{e.Code, e.Msg, utils.GetReqPath(c)}) -} -func Unknow(c *gin.Context) { - c.JSON(http.StatusForbidden, ExceptionResponse{UNKNOW_ERROR, "未知错误", utils.GetReqPath(c)}) -} -func Server(c *gin.Context) { - c.JSON(http.StatusInternalServerError, ExceptionResponse{SERVER_ERROR, "服务器错误", utils.GetReqPath(c)}) -} - -// FailMsg 主动抛出错误Exception类型 -func FailMsg(msg interface{}) *Exception { - return &Exception{http.StatusOK, ERROR, msg, nil} -} - -func FailCodeMsg(code int, msg string) *Exception { - return &Exception{http.StatusOK, code, msg, nil} -} - -func PanicMsg(msg interface{}) { - PanicMsgBool(true, msg) -} -func PanicCodeMsg(code int, msg string) { - PanicCodeMsgBool(true, code, msg) -} - -func PanicMsgBool(flag bool, msg interface{}) { - if flag { - panic(&Exception{http.StatusOK, ERROR, msg, nil}) - } -} -func PanicCodeMsgBool(flag bool, code int, msg string) { - if flag { - panic(&Exception{http.StatusOK, code, msg, nil}) +func (r E) Error() string { + if r.Err != nil { + return fmt.Sprintf(`{\"code\":%d;\"msg\":\"%v\",\"err\":\"%s\"}`, r.Code, r.Msg, r.Err.Error()) + } else { + return fmt.Sprintf(`{\"code\":%d;\"msg\":\"%v\"}`, r.Code, r.Msg) } } -func PanicMsgErr(err error, msg interface{}) { +func (r E) Return(c *gin.Context) { + c.JSON(http.StatusOK, r) +} + +func NE(msg any) error { + return NEC(msg, code.ERROR) +} + +func NEC(msg any, code int) error { + return &E{ + Msg: msg, + Code: code, + } +} + +func NEE(err error, msg string) error { + return NEEC(err, msg, code.ERROR) +} + +func NEEC(err error, msg string, code int) error { if err != nil { - panic(&Exception{http.StatusOK, ERROR, msg, err}) + return &E{ + Msg: msg, + Code: code, + Err: err, + } + } + return nil +} + +func PM(msg any) { + panic(&E{code.ERROR, msg, nil}) +} +func PMC(msg any, code int) { + panic(&E{code, msg, nil}) +} + +func PBM(flag bool, msg any) { + if flag { + panic(&E{code.ERROR, msg, nil}) } } -func PanicCodeMsgErr(err error, code int, msg string) { +func PBMC(flag bool, msg any, code int) { + if flag { + panic(&E{code, msg, nil}) + } +} + +func PEM(err error, msg any) { if err != nil { - panic(&Exception{http.StatusOK, code, msg, err}) + panic(&E{code.ERROR, msg, err}) } } +func PEMC(err error, msg any, code int) { + if err != nil { + panic(&E{code, msg, err}) + } +} +func PDM(db *gorm.DB, msgs ...string) { + if db.Error != nil { + msg := "未查询到" + if len(msgs) > 0 { + msg = msgs[0] + } + panic(&E{code.ERROR, msg, db.Error}) + } +} + +//type Exception struct { +// HttpCode int `json:"-"` +// Code int `json:"code"` +// Msg interface{} `json:"msg"` +// Err error `json:"err"` +//} +// +//type ExceptionResponse struct { +// Code int `json:"code"` +// Msg interface{} `json:"msg"` +// Path string `json:"path"` +//} +// +//func (r *Exception) Error() interface{} { +// return r.Msg +//} +// +//func NotFoundR(c *gin.Context) { +// c.JSON(http.StatusForbidden, ExceptionResponse{NOT_FOUND_ROUTE, "Not Found Route", utils.GetReqPath(c)}) +//} +// +//func NotFoundM(c *gin.Context) { +// c.JSON(http.StatusForbidden, ExceptionResponse{NOT_FOUND_METH, "Not Found Method", utils.GetReqPath(c)}) +//} +// +//func Panic(c *gin.Context, e *Exception) { +// c.JSON(e.HttpCode, ExceptionResponse{e.Code, e.Msg, utils.GetReqPath(c)}) +//} +//func Unknow(c *gin.Context) { +// c.JSON(http.StatusForbidden, ExceptionResponse{UNKNOW_ERROR, "未知错误", utils.GetReqPath(c)}) +//} +//func Server(c *gin.Context) { +// c.JSON(http.StatusInternalServerError, ExceptionResponse{SERVER_ERROR, "服务器错误", utils.GetReqPath(c)}) +//} +// +//// FailMsg 主动抛出错误Exception类型 +//func FailMsg(msg interface{}) *Exception { +// return &Exception{http.StatusOK, ERROR, msg, nil} +//} +// +//func FailCodeMsg(code int, msg string) *Exception { +// return &Exception{http.StatusOK, code, msg, nil} +//} +// +//func PanicMsg(msg interface{}) { +// PanicMsgBool(true, msg) +//} +//func PanicCodeMsg(code int, msg string) { +// PanicCodeMsgBool(true, code, msg) +//} +// +//func PanicMsgBool(flag bool, msg interface{}) { +// if flag { +// panic(&Exception{http.StatusOK, ERROR, msg, nil}) +// } +//} +//func PanicCodeMsgBool(flag bool, code int, msg string) { +// if flag { +// panic(&Exception{http.StatusOK, code, msg, nil}) +// } +//} +// +//func PanicMsgErr(err error, msg interface{}) { +// if err != nil { +// panic(&Exception{http.StatusOK, ERROR, msg, err}) +// } +//} +//func PanicCodeMsgErr(err error, code int, msg string) { +// if err != nil { +// panic(&Exception{http.StatusOK, code, msg, err}) +// } +//} diff --git a/utils/recovery/cron_recovery.go b/utils/recovery/cron_recovery.go new file mode 100644 index 0000000..c20baef --- /dev/null +++ b/utils/recovery/cron_recovery.go @@ -0,0 +1,36 @@ +package recovery + +import ( + "energy-management-system/core/logger" + "energy-management-system/global" + "energy-management-system/utils/code" + "energy-management-system/utils/exception" + "fmt" +) + +func CronRecovery(name string) { + if err := recover(); err != nil { + var codes int + var msg any + var er error + if h, ok := err.(*exception.E); ok { + codes = h.Code + msg = h.Msg + er = h.Err + } else if e, ok := err.(error); ok { + msg = fmt.Sprint("未知错误:", e.Error()) + logger.StackSend(5, e.Error()) + codes = code.UNKNOW_ERROR + } else { + msg = fmt.Sprint("服务器错误:", err) + logger.StackSend(5, err.(string)) + codes = code.SERVER_ERROR + } + global.Log.WithFields(map[string]any{ + "code": codes, + "model": "task", + "func": name, + "err": er, + }).Error(msg) + } +} diff --git a/utils/recovery/gin_recovery.go b/utils/recovery/gin_recovery.go new file mode 100644 index 0000000..2ecabba --- /dev/null +++ b/utils/recovery/gin_recovery.go @@ -0,0 +1,86 @@ +package recovery + +import ( + "energy-management-system/core/logger" + "energy-management-system/global" + "energy-management-system/utils" + "energy-management-system/utils/code" + "energy-management-system/utils/exception" + "github.com/gin-gonic/gin" + "net" + "net/http" + "os" + "strings" +) + +func GinRecovery(c *gin.Context) { + defer func() { + if err := recover(); err != nil { + var brokenPipe bool + if ne, ok := err.(*net.OpError); ok { + if se, ok := ne.Err.(*os.SyscallError); ok { + if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { + brokenPipe = true + } + } + } + if brokenPipe { + c.Error(err.(error)) + } else { + if req, ok := c.Get("_req"); ok { + global.Log.Errorln("获取参数:", utils.String(req)) + } + if h, ok := err.(*exception.E); ok { + h.Return(c) + c.Errors = append(c.Errors, &gin.Error{Meta: h}) + } else if e, ok := err.(error); ok { + global.Log.Errorln("未知错误:", err) + logger.StackSend(3, e.Error()) + c.JSON(http.StatusForbidden, exception.E{code.UNKNOW_ERROR, "未知错误", nil}) + } else { + global.Log.Errorln("服务器错误:", err) + logger.StackSend(3, err.(string)) + c.JSON(http.StatusForbidden, exception.E{code.SERVER_ERROR, "服务器错误", nil}) + } + } + c.Abort() + } + }() + c.Next() +} + +//func GinRecovery() gin.HandlerFunc { +// return func(c *gin.Context) { +// defer func() { +// if err := recover(); err != nil { +// var brokenPipe bool +// if ne, ok := err.(*net.OpError); ok { +// if se, ok := ne.Err.(*os.SyscallError); ok { +// if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { +// brokenPipe = true +// } +// } +// } +// if brokenPipe { +// c.Error(err.(error)) +// } else { +// if h, ok := err.(*exception.Exception); ok { +// exception.Panic(c, h) +// c.Errors = append(c.Errors, &gin.Error{Meta: h}) +// } else if _, ok = err.(error); ok { +// if gin.IsDebugging() { +// fmt.Printf("[Recovery] %s : %s", utils.TimeFormat(time.Now()), err) +// utils.Stack(3) +// } +// exception.Unknow(c) +// } else { +// fmt.Print(err) +// exception.Server(c) +// } +// } +// c.Abort() +// } +// }() +// c.Next() +// } +//} diff --git a/utils/string.go b/utils/string.go new file mode 100644 index 0000000..5433c07 --- /dev/null +++ b/utils/string.go @@ -0,0 +1,179 @@ +package utils + +import ( + "encoding/json" + "fmt" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode" +) + +func ReplaceDownLine(req string) (res string) { + for _, v := range req { + if 64 < v && v < 91 { + res = res + "_" + string(v+32) + } else { + res += string(v) + } + } + return strings.TrimRight(strings.TrimLeft(res, "_"), "_") +} + +func String(data any) string { + if data == nil { + return "" + } + switch value := data.(type) { + case int: + return strconv.Itoa(value) + case int8: + return strconv.Itoa(int(value)) + case int16: + return strconv.Itoa(int(value)) + case int32: + return strconv.Itoa(int(value)) + case int64: + return strconv.FormatInt(value, 10) + case uint: + return strconv.FormatUint(uint64(value), 10) + case uint8: + return strconv.FormatUint(uint64(value), 10) + case uint16: + return strconv.FormatUint(uint64(value), 10) + case uint32: + return strconv.FormatUint(uint64(value), 10) + case uint64: + return strconv.FormatUint(value, 10) + case float32: + return strconv.FormatFloat(float64(value), 'f', -1, 32) + case float64: + return strconv.FormatFloat(value, 'f', -1, 64) + case bool: + return strconv.FormatBool(value) + case string: + return value + case []byte: + return string(value) + case time.Time: + if value.IsZero() { + return "" + } + return value.String() + case *time.Time: + if value == nil { + return "" + } + return value.String() + default: + // Empty checks. + if value == nil { + return "" + } + var ( + rv = reflect.ValueOf(value) + kind = rv.Kind() + ) + switch kind { + case reflect.Chan, + reflect.Map, + reflect.Slice, + reflect.Func, + reflect.Ptr, + reflect.Interface, + reflect.UnsafePointer: + if rv.IsNil() { + return "" + } + case reflect.String: + return rv.String() + } + if kind == reflect.Ptr { + return String(rv.Elem().Interface()) + } + // Finally, we use json.Marshal to convert. + jsonContent, err := json.Marshal(value) + if err != nil { + return fmt.Sprint(value) + } else { + return string(jsonContent) + } + } +} + +func IsNumber(s string) bool { + _, err := strconv.ParseFloat(s, 64) + return err == nil +} + +func ContainChinese(str string) bool { + for _, r := range str { + if unicode.Is(unicode.Scripts["Han"], r) || (regexp.MustCompile("[\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]").MatchString(string(r))) { + return true + } + } + return false +} + +func Contains(ids []string, id string) bool { + for _, v := range ids { + if strings.Compare(v, id) == 0 { + return true + } + } + return false +} + +// contain one of subs +func ContainSub(str string, subs ...string) bool { + for _, sub := range subs { + if strings.Contains(str, sub) { + return true + } + } + return false +} + +// must contain all subs +func ContainSubs(str string, subs ...string) bool { + for _, sub := range subs { + if strings.Contains(str, sub) { + continue + } else { + return false + } + } + return true +} + +func Duplicate(slc []string) []string { + result := make([]string, 0) + tempMap := make(map[string]bool, len(slc)) + for _, e := range slc { + if tempMap[e] == false { + tempMap[e] = true + result = append(result, e) + } + } + return result +} + +func Capitalize(str string) string { + var upperStr string + vv := []rune(str) + for i := 0; i < len(vv); i++ { + if i == 0 { + if vv[i] >= 97 && vv[i] <= 122 { + vv[i] -= 32 // string的码表相差32位 + upperStr += string(vv[i]) + } else { + return str + } + } else { + upperStr += string(vv[i]) + } + } + return upperStr +} diff --git a/utils/utils.go b/utils/utils.go index 91d5db5..859eff2 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -13,6 +13,21 @@ import ( "time" ) +func Exit(err any, str string) { + switch arg := err.(type) { + case error: + if arg != nil { + fmt.Println(str, arg.Error()) + os.Exit(1) + } + case bool: + if arg { + fmt.Println(str, err) + os.Exit(1) + } + } +} + func GetReqPath(c *gin.Context) string { return c.Request.Method + " " + c.Request.URL.String() }