diff --git a/server/.vscode/settings.json b/server/.vscode/settings.json index 75a99a6..68040e1 100644 --- a/server/.vscode/settings.json +++ b/server/.vscode/settings.json @@ -1,6 +1,7 @@ { "cSpell.words": [ "dcloudio", + "endregion", "excelize", "fontsize", "freetype", @@ -9,10 +10,13 @@ "gorm", "Infof", "Inno", + "Itoa", "jinzhu", "mapstructure", "oneof", "rmvb", + "strconv", + "struct", "uniapp", "Warnf", "webp", diff --git a/server/admin/generator/tpl_utils/templates/gocode/controller.go.tpl b/server/admin/generator/tpl_utils/templates/gocode/controller.go.tpl index 4fe0c47..69b5a41 100644 --- a/server/admin/generator/tpl_utils/templates/gocode/controller.go.tpl +++ b/server/admin/generator/tpl_utils/templates/gocode/controller.go.tpl @@ -2,16 +2,20 @@ package {{{ .ModuleName }}} import ( "net/http" + "strconv" "time" "github.com/gin-gonic/gin" "x_admin/core/request" "x_admin/core/response" "x_admin/util" "x_admin/util/excel" + "golang.org/x/sync/singleflight" ) -type {{{ title (toCamelCase .ModuleName) }}}Handler struct {} +type {{{ title (toCamelCase .ModuleName) }}}Handler struct { + requestGroup singleflight.Group +} // @Summary {{{ .FunctionName }}}列表 // @Tags {{{ .ModuleName }}}-{{{ .FunctionName }}} @@ -31,7 +35,7 @@ type {{{ title (toCamelCase .ModuleName) }}}Handler struct {} {{{- end }}} //@Success 200 {object} {{{getPageResp (title (toCamelCase .EntityName)) }}} "成功" //@Router /api/admin/{{{ .ModuleName }}}/list [get] -func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) List(c *gin.Context) { +func (hd *{{{ title (toCamelCase .ModuleName) }}}Handler) List(c *gin.Context) { var page request.PageReq var listReq {{{ title (toCamelCase .EntityName) }}}ListReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &page)) { @@ -59,7 +63,7 @@ func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) List(c *gin.Context) { {{{- end }}} // @Success 200 {object} response.Response{ data=[]{{{ title (toCamelCase .EntityName) }}}Resp} "成功" // @Router /api/admin/{{{ .ModuleName }}}/listAll [get] -func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) ListAll(c *gin.Context) { +func (hd *{{{ title (toCamelCase .ModuleName) }}}Handler) ListAll(c *gin.Context) { var listReq {{{ title (toCamelCase .EntityName) }}}ListReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) { return @@ -79,12 +83,16 @@ func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) ListAll(c *gin.Context {{{- end }}} // @Success 200 {object} response.Response{ data={{{ title (toCamelCase .EntityName) }}}Resp} "成功" // @Router /api/admin/{{{ .ModuleName }}}/detail [get] -func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) Detail(c *gin.Context) { +func (hd *{{{ title (toCamelCase .ModuleName) }}}Handler) Detail(c *gin.Context) { var detailReq {{{ title (toCamelCase .EntityName) }}}DetailReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) { return } - res, err := {{{ title (toCamelCase .EntityName) }}}Service.Detail(detailReq.{{{ title (toCamelCase .PrimaryKey) }}}) + res, err, _ := hd.requestGroup.Do("{{{ title (toCamelCase .EntityName) }}}:Detail:"+strconv.Itoa(detailReq.{{{ title (toCamelCase .PrimaryKey) }}}), func() (any, error) { + v, err := {{{ title (toCamelCase .EntityName) }}}Service.Detail(detailReq.{{{ title (toCamelCase .PrimaryKey) }}}) + return v, err + }) + response.CheckAndRespWithData(c, res, err) } @@ -100,12 +108,13 @@ func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) Detail(c *gin.Context) {{{- end }}} // @Success 200 {object} response.Response "成功" // @Router /api/admin/{{{ .ModuleName }}}/add [post] -func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) Add(c *gin.Context) { +func (hd *{{{ title (toCamelCase .ModuleName) }}}Handler) Add(c *gin.Context) { var addReq {{{ title (toCamelCase .EntityName) }}}AddReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) { return } - response.CheckAndResp(c, {{{ title (toCamelCase .EntityName) }}}Service.Add(addReq)) + createId, e := {{{ title (toCamelCase .EntityName) }}}Service.Add(addReq) + response.CheckAndRespWithData(c,createId, e) } // @Summary {{{ .FunctionName }}}编辑 // @Tags {{{ .ModuleName }}}-{{{ .FunctionName }}} @@ -118,12 +127,12 @@ func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) Add(c *gin.Context) { {{{- end }}} // @Success 200 {object} response.Response "成功" // @Router /api/admin/{{{ .ModuleName }}}/edit [post] -func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) Edit(c *gin.Context) { +func (hd *{{{ title (toCamelCase .ModuleName) }}}Handler) Edit(c *gin.Context) { var editReq {{{ title (toCamelCase .EntityName) }}}EditReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &editReq)) { return } - response.CheckAndResp(c, {{{ title (toCamelCase .EntityName) }}}Service.Edit(editReq)) + response.CheckAndRespWithData(c,editReq.{{{ title (toCamelCase .PrimaryKey) }}}, {{{ title (toCamelCase .EntityName) }}}Service.Edit(editReq)) } // @Summary {{{ .FunctionName }}}删除 // @Tags {{{ .ModuleName }}}-{{{ .FunctionName }}} @@ -136,7 +145,7 @@ func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) Edit(c *gin.Context) { {{{- end }}} // @Success 200 {object} response.Response "成功" // @Router /api/admin/{{{ .ModuleName }}}/del [post] -func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) Del(c *gin.Context) { +func (hd *{{{ title (toCamelCase .ModuleName) }}}Handler) Del(c *gin.Context) { var delReq {{{ title (toCamelCase .EntityName) }}}DelReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) { return @@ -161,7 +170,7 @@ func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) Del(c *gin.Context) { {{{- end }}} {{{- end }}} // @Router /api/admin/{{{ .ModuleName }}}/ExportFile [get] -func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) ExportFile(c *gin.Context) { +func (hd *{{{ title (toCamelCase .ModuleName) }}}Handler) ExportFile(c *gin.Context) { var listReq {{{ title (toCamelCase .EntityName) }}}ListReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) { return @@ -183,7 +192,7 @@ func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) ExportFile(c *gin.Cont // @Tags {{{ .ModuleName }}}-{{{ .FunctionName }}} // @Produce json // @Router /api/admin/{{{ .ModuleName }}}/ImportFile [post] -func (hd {{{ title (toCamelCase .ModuleName) }}}Handler) ImportFile(c *gin.Context) { +func (hd *{{{ title (toCamelCase .ModuleName) }}}Handler) ImportFile(c *gin.Context) { file, _, err := c.Request.FormFile("file") if err != nil { c.String(http.StatusInternalServerError, "文件不存在") diff --git a/server/admin/generator/tpl_utils/templates/gocode/route.go.tpl b/server/admin/generator/tpl_utils/templates/gocode/route.go.tpl index 8b0b249..145bede 100644 --- a/server/admin/generator/tpl_utils/templates/gocode/route.go.tpl +++ b/server/admin/generator/tpl_utils/templates/gocode/route.go.tpl @@ -51,5 +51,5 @@ func {{{ title (toCamelCase .ModuleName) }}}Route(rg *gin.RouterGroup) { r.POST("/{{{ .ModuleName }}}/edit",middleware.RecordLog("{{{ .FunctionName }}}编辑"), handle.Edit) r.POST("/{{{ .ModuleName }}}/del", middleware.RecordLog("{{{ .FunctionName }}}删除"), handle.Del) r.GET("/{{{ .ModuleName }}}/ExportFile", middleware.RecordLog("{{{ .FunctionName }}}导出"), handle.ExportFile) - r.POST("/{{{ .ModuleName }}}/ImportFile", handle.ImportFile) + r.POST("/{{{ .ModuleName }}}/ImportFile",middleware.RecordLog("{{{ .FunctionName }}}导入"), handle.ImportFile) } \ No newline at end of file diff --git a/server/admin/generator/tpl_utils/templates/gocode/service.go.tpl b/server/admin/generator/tpl_utils/templates/gocode/service.go.tpl index c5ed00e..7190c29 100644 --- a/server/admin/generator/tpl_utils/templates/gocode/service.go.tpl +++ b/server/admin/generator/tpl_utils/templates/gocode/service.go.tpl @@ -27,13 +27,13 @@ func (service {{{ toCamelCase .EntityName }}}Service) SetCache(obj model.{{{ tit if e != nil { return false } - return util.RedisUtil.Set("{{{ toCamelCase .EntityName }}}:id:"+strconv.Itoa(obj.Id), str, 3600) + return util.RedisUtil.HSet("{{{ toCamelCase .EntityName }}}",strconv.Itoa(obj.{{{ title (toCamelCase .PrimaryKey) }}}), str, 3600) } // 获取缓存 -func (service {{{ toCamelCase .EntityName }}}Service) GetCache(id int) (model.{{{ title (toCamelCase .EntityName) }}}, error) { +func (service {{{ toCamelCase .EntityName }}}Service) GetCache(key int) (model.{{{ title (toCamelCase .EntityName) }}}, error) { var obj model.{{{ title (toCamelCase .EntityName) }}} - str := util.RedisUtil.Get("{{{ toCamelCase .EntityName }}}:id:" + strconv.Itoa(id)) + str := util.RedisUtil.HGet("{{{ toCamelCase .EntityName }}}", strconv.Itoa(key)) if str == "" { return obj, errors.New("获取缓存失败") } @@ -46,7 +46,7 @@ func (service {{{ toCamelCase .EntityName }}}Service) GetCache(id int) (model.{{ } // 删除缓存 func (service {{{ toCamelCase .EntityName }}}Service) RemoveCache(obj model.{{{ title (toCamelCase .EntityName) }}}) bool { - return util.RedisUtil.Del("{{{ toCamelCase .EntityName }}}:id:" + strconv.Itoa(obj.Id)) + return util.RedisUtil.HDel("{{{ toCamelCase .EntityName }}}", strconv.Itoa(obj.{{{ title (toCamelCase .PrimaryKey) }}})) } @@ -124,11 +124,11 @@ func (service {{{ toCamelCase .EntityName }}}Service) ListAll(listReq {{{ title } // Detail {{{ .FunctionName }}}详情 -func (service {{{ toCamelCase .EntityName }}}Service) Detail(id int) (res {{{ title (toCamelCase .EntityName) }}}Resp, e error) { - var obj, err = service.GetCache(id) +func (service {{{ toCamelCase .EntityName }}}Service) Detail({{{ title (toCamelCase .PrimaryKey) }}} int) (res {{{ title (toCamelCase .EntityName) }}}Resp, e error) { + var obj, err = service.GetCache({{{ title (toCamelCase .PrimaryKey) }}}) // var obj model.{{{ title (toCamelCase .EntityName) }}} if err != nil { - err := service.db.Where("{{{ $.PrimaryKey }}} = ?{{{ if contains .AllFields "is_delete" }}} AND is_delete = ?{{{ end }}}", id{{{ if contains .AllFields "is_delete" }}}, 0{{{ end }}}).Limit(1).First(&obj).Error + err := service.db.Where("{{{ $.PrimaryKey }}} = ?{{{ if contains .AllFields "is_delete" }}} AND is_delete = ?{{{ end }}}", {{{ title (toCamelCase .PrimaryKey) }}}{{{ if contains .AllFields "is_delete" }}}, 0{{{ end }}}).Limit(1).First(&obj).Error if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil { return } @@ -149,15 +149,16 @@ func (service {{{ toCamelCase .EntityName }}}Service) Detail(id int) (res {{{ ti } // Add {{{ .FunctionName }}}新增 -func (service {{{ toCamelCase .EntityName }}}Service) Add(addReq {{{ title (toCamelCase .EntityName) }}}AddReq) (e error) { +func (service {{{ toCamelCase .EntityName }}}Service) Add(addReq {{{ title (toCamelCase .EntityName) }}}AddReq) (createId int,e error) { var obj model.{{{ title (toCamelCase .EntityName) }}} response.Copy(&obj, addReq) err := service.db.Create(&obj).Error e = response.CheckMysqlErr(err) if e != nil { - return e + return 0,e } service.SetCache(obj) + createId = obj.{{{ title (toCamelCase .PrimaryKey) }}} e = response.CheckErr(err, "添加失败") return } @@ -165,7 +166,7 @@ func (service {{{ toCamelCase .EntityName }}}Service) Add(addReq {{{ title (toCa // Edit {{{ .FunctionName }}}编辑 func (service {{{ toCamelCase .EntityName }}}Service) Edit(editReq {{{ title (toCamelCase .EntityName) }}}EditReq) (e error) { var obj model.{{{ title (toCamelCase .EntityName) }}} - err := service.db.Where("{{{ $.PrimaryKey }}} = ?{{{ if contains .AllFields "is_delete" }}} AND is_delete = ?{{{ end }}}", editReq.Id{{{ if contains .AllFields "is_delete" }}}, 0{{{ end }}}).Limit(1).First(&obj).Error + err := service.db.Where("{{{ $.PrimaryKey }}} = ?{{{ if contains .AllFields "is_delete" }}} AND is_delete = ?{{{ end }}}", editReq.{{{ title (toCamelCase .PrimaryKey) }}}{{{ if contains .AllFields "is_delete" }}}, 0{{{ end }}}).Limit(1).First(&obj).Error // 校验 if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil { return @@ -182,9 +183,9 @@ func (service {{{ toCamelCase .EntityName }}}Service) Edit(editReq {{{ title (to } // Del {{{ .FunctionName }}}删除 -func (service {{{ toCamelCase .EntityName }}}Service) Del(id int) (e error) { +func (service {{{ toCamelCase .EntityName }}}Service) Del({{{ title (toCamelCase .PrimaryKey) }}} int) (e error) { var obj model.{{{ title (toCamelCase .EntityName) }}} - err := service.db.Where("{{{ $.PrimaryKey }}} = ?{{{ if contains .AllFields "is_delete" }}} AND is_delete = ?{{{ end }}}", id{{{ if contains .AllFields "is_delete" }}}, 0{{{ end }}}).Limit(1).First(&obj).Error + err := service.db.Where("{{{ $.PrimaryKey }}} = ?{{{ if contains .AllFields "is_delete" }}} AND is_delete = ?{{{ end }}}", {{{ title (toCamelCase .PrimaryKey) }}}{{{ if contains .AllFields "is_delete" }}}, 0{{{ end }}}).Limit(1).First(&obj).Error // 校验 if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil { return diff --git a/server/admin/monitor_project/monitor_project_ctl.go b/server/admin/monitor_project/monitor_project_ctl.go index 8e510fc..fc718d0 100644 --- a/server/admin/monitor_project/monitor_project_ctl.go +++ b/server/admin/monitor_project/monitor_project_ctl.go @@ -1,8 +1,8 @@ package monitor_project import ( - "fmt" "net/http" + "strconv" "time" "x_admin/core/request" "x_admin/core/response" @@ -13,7 +13,9 @@ import ( "golang.org/x/sync/singleflight" ) -type MonitorProjectHandler struct{} +type MonitorProjectHandler struct { + requestGroup singleflight.Group +} // @Summary 错误项目列表 // @Tags monitor_project-错误项目 @@ -27,7 +29,7 @@ type MonitorProjectHandler struct{} // @Success 200 {object} response.Response{data=response.PageResp{lists=[]MonitorProjectResp}} "成功" // @Failure 400 {object} string "请求错误" // @Router /api/admin/monitor_project/list [get] -func (hd MonitorProjectHandler) List(c *gin.Context) { +func (hd *MonitorProjectHandler) List(c *gin.Context) { var page request.PageReq var listReq MonitorProjectListReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &page)) { @@ -45,14 +47,14 @@ func (hd MonitorProjectHandler) List(c *gin.Context) { // @Produce json // @Success 200 {object} response.Response{data=[]MonitorProjectResp} "成功" // @Router /api/admin/monitor_project/listAll [get] -var sg singleflight.Group +// var sg singleflight.Group -func (hd MonitorProjectHandler) ListAll(c *gin.Context) { - res, err, shared := sg.Do("key", func() (any, error) { +func (hd *MonitorProjectHandler) ListAll(c *gin.Context) { + res, err, _ := hd.requestGroup.Do("monitor_project:listAll", func() (any, error) { v, err := Service.ListAll() return v, err }) - fmt.Printf("v: %v, shared: %v\n", res, shared) + // fmt.Printf("v: %v, shared: %v\n", res, shared) // var listReq MonitorProjectListReq // if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) { @@ -68,12 +70,16 @@ func (hd MonitorProjectHandler) ListAll(c *gin.Context) { // @Param id query int false "项目id." // @Success 200 {object} response.Response{data=MonitorProjectResp} "成功" // @Router /api/admin/monitor_project/detail [get] -func (hd MonitorProjectHandler) Detail(c *gin.Context) { +func (hd *MonitorProjectHandler) Detail(c *gin.Context) { var detailReq MonitorProjectDetailReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) { return } - res, err := Service.Detail(detailReq.Id) + res, err, _ := hd.requestGroup.Do("monitor_project:Detail:"+strconv.Itoa(detailReq.Id), func() (any, error) { + v, err := Service.Detail(detailReq.Id) + return v, err + }) + // fmt.Printf("v: %v, shared: %v\n", res, shared) response.CheckAndRespWithData(c, res, err) } @@ -86,12 +92,13 @@ func (hd MonitorProjectHandler) Detail(c *gin.Context) { // @Param projectType body string false "项目类型go java web node php 等." // @Success 200 {object} response.Response "成功" // @Router /api/admin/monitor_project/add [post] -func (hd MonitorProjectHandler) Add(c *gin.Context) { +func (hd *MonitorProjectHandler) Add(c *gin.Context) { var addReq MonitorProjectAddReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) { return } - response.CheckAndResp(c, Service.Add(addReq)) + createId, e := Service.Add(addReq) + response.CheckAndRespWithData(c, createId, e) } // @Summary 错误项目编辑 @@ -104,12 +111,12 @@ func (hd MonitorProjectHandler) Add(c *gin.Context) { // @Param projectType body string false "项目类型go java web node php 等." // @Success 200 {object} response.Response "成功" // @Router /api/admin/monitor_project/edit [post] -func (hd MonitorProjectHandler) Edit(c *gin.Context) { +func (hd *MonitorProjectHandler) Edit(c *gin.Context) { var editReq MonitorProjectEditReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &editReq)) { return } - response.CheckAndResp(c, Service.Edit(editReq)) + response.CheckAndRespWithData(c, editReq.Id, Service.Edit(editReq)) } // @Summary 错误项目删除 @@ -119,7 +126,7 @@ func (hd MonitorProjectHandler) Edit(c *gin.Context) { // @Param id body int false "项目id." // @Success 200 {object} response.Response "成功" // @Router /api/admin/monitor_project/del [post] -func (hd MonitorProjectHandler) Del(c *gin.Context) { +func (hd *MonitorProjectHandler) Del(c *gin.Context) { var delReq MonitorProjectDelReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) { return @@ -135,7 +142,7 @@ func (hd MonitorProjectHandler) Del(c *gin.Context) { // @Param projectName query string false "项目名称." // @Param projectType query string false "项目类型go java web node php 等." // @Router /api/admin/monitor_project/ExportFile [get] -func (hd MonitorProjectHandler) ExportFile(c *gin.Context) { +func (hd *MonitorProjectHandler) ExportFile(c *gin.Context) { var listReq MonitorProjectListReq if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) { return @@ -156,7 +163,7 @@ func (hd MonitorProjectHandler) ExportFile(c *gin.Context) { // @Summary 错误项目导入 // @Tags monitor_project-错误项目 // @Produce json -func (hd MonitorProjectHandler) ImportFile(c *gin.Context) { +func (hd *MonitorProjectHandler) ImportFile(c *gin.Context) { file, _, err := c.Request.FormFile("file") if err != nil { c.String(http.StatusInternalServerError, "文件不存在") @@ -169,9 +176,9 @@ func (hd MonitorProjectHandler) ImportFile(c *gin.Context) { c.String(http.StatusInternalServerError, err.Error()) return } - for _, t := range importList { - fmt.Printf("%#v", t) - } + // for _, t := range importList { + // fmt.Printf("%#v", t) + // } err = Service.ImportFile(importList) response.CheckAndResp(c, err) } diff --git a/server/admin/monitor_project/monitor_project_service.go b/server/admin/monitor_project/monitor_project_service.go index 4056c07..0319bbd 100644 --- a/server/admin/monitor_project/monitor_project_service.go +++ b/server/admin/monitor_project/monitor_project_service.go @@ -41,13 +41,13 @@ func (service monitorProjectService) SetCache(obj model.MonitorProject) bool { if e != nil { return false } - return util.RedisUtil.Set("MonitorProject:id:"+strconv.Itoa(obj.Id), str, 3600) + return util.RedisUtil.HSet("MonitorProject", strconv.Itoa(obj.Id), str, 3600) } // 获取缓存 func (service monitorProjectService) GetCache(id int) (model.MonitorProject, error) { var obj model.MonitorProject - str := util.RedisUtil.Get("MonitorProject:id:" + strconv.Itoa(id)) + str := util.RedisUtil.HGet("MonitorProject", strconv.Itoa(id)) if str == "" { return obj, errors.New("获取缓存失败") } @@ -61,7 +61,7 @@ func (service monitorProjectService) GetCache(id int) (model.MonitorProject, err // 删除缓存 func (service monitorProjectService) RemoveCache(obj model.MonitorProject) bool { - return util.RedisUtil.Del("{{{ toCamelCase .EntityName }}}:id:" + strconv.Itoa(obj.Id)) + return util.RedisUtil.HDel("MonitorProject", strconv.Itoa(obj.Id)) } // List 错误项目列表 @@ -147,16 +147,17 @@ func (service monitorProjectService) Detail(id int) (res MonitorProjectResp, e e } // Add 错误项目新增 -func (service monitorProjectService) Add(addReq MonitorProjectAddReq) (e error) { +func (service monitorProjectService) Add(addReq MonitorProjectAddReq) (createId int, e error) { var obj model.MonitorProject response.Copy(&obj, addReq) obj.ProjectKey = util.ToolsUtil.MakeUuid() err := service.db.Create(&obj).Error if e = response.CheckMysqlErr(err); e != nil { - return e + return 0, e } service.SetCache(obj) + createId = obj.Id e = response.CheckErr(err, "添加失败") return } @@ -194,7 +195,7 @@ func (service monitorProjectService) Del(id int) (e error) { // 删除 obj.IsDelete = 1 err = service.db.Save(&obj).Error - util.RedisUtil.Del("MonitorProject:id:" + strconv.Itoa(obj.Id)) + service.RemoveCache(obj) e = response.CheckErr(err, "Del Save err") return } diff --git a/server/admin/monitor_project_route.go b/server/admin/monitor_project_route.go index 177e029..f390e42 100644 --- a/server/admin/monitor_project_route.go +++ b/server/admin/monitor_project_route.go @@ -38,5 +38,5 @@ func MonitorProjectRoute(rg *gin.RouterGroup) { r.POST("/monitor_project/edit", middleware.RecordLog("错误项目编辑"), handle.Edit) r.POST("/monitor_project/del", middleware.RecordLog("错误项目删除"), handle.Del) r.GET("/monitor_project/ExportFile", middleware.RecordLog("错误项目导出"), handle.ExportFile) - r.POST("/monitor_project/ImportFile", handle.ImportFile) + r.POST("/monitor_project/ImportFile", middleware.RecordLog("错误项目导入"), handle.ImportFile) } diff --git a/server/config/config.go b/server/config/config.go index e8750ba..9c8b8ec 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "os" + "time" "github.com/spf13/viper" ) @@ -14,24 +15,26 @@ var Config = loadConfig(".") // #region envConfig // envConfig 环境配置 type envConfig struct { - RootPath string // 项目根目录 - GinMode string `mapstructure:"GIN_MODE"` // gin运行模式 - PublicUrl string `mapstructure:"PUBLIC_URL"` // 对外发布的Url - OssDomain string `mapstructure:"OSS_DOMAIN"` // OSS域名 - ServerPort int `mapstructure:"SERVER_PORT"` // 服务运行端口 - DisallowModify bool `mapstructure:"DISALLOW_MODIFY"` // 禁止修改操作 (演示功能,限制POST请求) - PublicPrefix string // 资源访问前缀 - UploadDirectory string `mapstructure:"UPLOAD_DIRECTORY"` // 上传文件路径 - RedisUrl string `mapstructure:"REDIS_URL"` // Redis源配置 - RedisPoolSize int // Redis连接池大小 - DatabaseUrl string `mapstructure:"DATABASE_URL"` // 数据源配置 - DbTablePrefix string // Mysql表前缀 - DbDefaultStringSize uint // 数据库string类型字段的默认长度 - DbMaxIdleConns int // 数据库空闲连接池最大值 - DbMaxOpenConns int // 数据库连接池最大值 - DbConnMaxLifetimeSeconds int16 // 连接可复用的最大时间(秒:默认28800秒),请根据这个sql查处的时间设置: show variables like 'wait_timeout' - Version string // 版本 - Secret string // 系统加密字符 + RootPath string // 项目根目录 + GinMode string `mapstructure:"GIN_MODE"` // gin运行模式 + PublicUrl string `mapstructure:"PUBLIC_URL"` // 对外发布的Url + OssDomain string `mapstructure:"OSS_DOMAIN"` // OSS域名 + ServerPort int `mapstructure:"SERVER_PORT"` // 服务运行端口 + DisallowModify bool `mapstructure:"DISALLOW_MODIFY"` // 禁止修改操作 (演示功能,限制POST请求) + PublicPrefix string // 资源访问前缀 + UploadDirectory string `mapstructure:"UPLOAD_DIRECTORY"` // 上传文件路径 + RedisUrl string `mapstructure:"REDIS_URL"` // Redis源配置 + // RedisPoolSize int // Redis连接池大小 + RedisMaxIdleConns int // Redis空闲连接池最大值 + RedisConnMaxLifetime time.Duration // Redis连接可复用的最大时间(秒:默认60秒) + DatabaseUrl string `mapstructure:"DATABASE_URL"` // 数据源配置 + DbTablePrefix string // Mysql表前缀 + DbDefaultStringSize uint // 数据库string类型字段的默认长度 + DbMaxIdleConns int // 数据库空闲连接池最大值 + DbMaxOpenConns int // 数据库连接池最大值 + DbConnMaxLifetimeSeconds int16 // 连接可复用的最大时间(秒:默认28800秒),请根据这个sql查处的时间设置: show variables like 'wait_timeout' + Version string // 版本 + Secret string // 系统加密字符 RedisPrefix string // Redis键前缀 UploadImageSize int64 // 上传图片限制 @@ -75,8 +78,10 @@ func loadConfig(envPath string) envConfig { // 上传文件路径 UploadDirectory: "/tmp/uploads/x_admin-go/", // Redis源配置 - RedisUrl: "redis://localhost:6379", - RedisPoolSize: 100, + RedisUrl: "redis://localhost:6379", + // RedisPoolSize: 100, + RedisMaxIdleConns: 80, + RedisConnMaxLifetime: 60 * time.Second, // 数据源配置 DatabaseUrl: "x_admin:x_admin@tcp(localhost:3306)/x_admin?charset=utf8mb4&parseTime=True&loc=Local", DbTablePrefix: "x_", diff --git a/server/core/redis.go b/server/core/redis.go index 45148f2..3de5d93 100644 --- a/server/core/redis.go +++ b/server/core/redis.go @@ -17,7 +17,10 @@ func initRedis() *redis.Client { if err != nil { log.Fatal("initRedis redis.ParseURL err: ", err) } - opt.PoolSize = config.Config.RedisPoolSize + // opt.PoolSize = config.Config.RedisPoolSize + opt.MaxIdleConns = config.Config.RedisMaxIdleConns + opt.ConnMaxLifetime = config.Config.RedisConnMaxLifetime + client := redis.NewClient(opt) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() diff --git a/server/go.mod b/server/go.mod index 825eae6..e720f93 100644 --- a/server/go.mod +++ b/server/go.mod @@ -35,6 +35,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/KyleBanks/depth v1.2.1 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -84,6 +85,7 @@ require ( github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.uber.org/multierr v1.11.0 // indirect + go.uber.org/ratelimit v0.3.1 // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect diff --git a/server/go.sum b/server/go.sum index 4303540..2f6331c 100644 --- a/server/go.sum +++ b/server/go.sum @@ -2,6 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= @@ -203,6 +205,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= +go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= diff --git a/server/middleware/ratelimit.go b/server/middleware/ratelimit.go new file mode 100644 index 0000000..789d9d2 --- /dev/null +++ b/server/middleware/ratelimit.go @@ -0,0 +1,29 @@ +package middleware + +import ( + "net/http" + "time" + + "github.com/gin-gonic/gin" + "go.uber.org/ratelimit" +) + +// 限制每秒请求数量 +// r := rg.Group("/", middleware.RateLimiterMiddleware(200)) +func RateLimiterMiddleware(rate int) gin.HandlerFunc { + rl := ratelimit.New(rate) + + return func(c *gin.Context) { + // Try to take a token from the rate limiter. + now := rl.Take() + + // Check if we've waited longer than expected. If so, this means the rate + // limit has been exceeded. + if now.After(time.Now()) { + c.AbortWithStatus(http.StatusTooManyRequests) + return + } + + c.Next() + } +} diff --git a/server/util/aj-captcha-go/util/redis_util.go b/server/util/aj-captcha-go/util/redis_util.go index e467922..542ad26 100644 --- a/server/util/aj-captcha-go/util/redis_util.go +++ b/server/util/aj-captcha-go/util/redis_util.go @@ -2,7 +2,6 @@ package util import ( "context" - "fmt" "strconv" "time" @@ -46,8 +45,8 @@ func (l *RedisUtil) Get(key string) string { func (l *RedisUtil) Set(key string, val string, expiresInSeconds int) { //设置阈值,达到即clear缓存 - rdsResult := l.Rdb.Set(context.Background(), key, val, time.Duration(expiresInSeconds)*time.Second) - fmt.Println("rdsResult: ", rdsResult.String(), "rdsErr: ", rdsResult.Err()) + l.Rdb.Set(context.Background(), key, val, time.Duration(expiresInSeconds)*time.Second) + if expiresInSeconds > 0 { // 缓存失效时间 nowTime := time.Now().Unix() + int64(expiresInSeconds)