瀏覽代碼

feat: add缓存api

double 5 年之前
父節點
當前提交
57725ba299

+ 8 - 1
cmd/dolphin/gen/template/app.go

@@ -75,7 +75,14 @@ func Auth(ctx *Context) {
 // Roles middles
 func Roles(roles ...string) func(ctx *Context) {
 	return func(ctx *Context) {
-		pApp.Roles(roles...)
+		pApp.Roles(roles...)(ctx.Context)
+	}
+}
+
+// Cache middles
+func Cache(time time.Duration) func(ctx *Context) {
+	return func(ctx *Context) {
+		pApp.Cache(time)(ctx.Context)
 	}
 }
 

+ 2 - 1
cmd/dolphin/gen/template/auto.go

@@ -11,6 +11,7 @@ var TmplAuto = `// Code generated by dol build. DO NOT EDIT.
 package app
 
 import (
+	"time"
 	"{{.PackageName}}/model"
 
 	"github.com/2637309949/dolphin/packages/viper"
@@ -44,7 +45,7 @@ func New{{.ToUpperCase .Name}}() *{{.ToUpperCase .Name}} {
 func {{.ToUpperCase .Name}}Routes(engine *Engine) {
 	group := engine.Group({{- if ne .Prefix ""}}"{{.Prefix}}"{{- else}}viper.GetString("http.prefix"){{- end}})
 	{{- range .APIS}}
-	group.Handle("{{.ToUpper .Method}}", "{{.APIPrefix .Version}}/{{.APIPath $ctr.Name .Path}}/{{.Name}}"{{- if .Auth}}, Auth{{- end}}{{- if gt (len .Roles) 0}}, Roles({{.FormatString .Roles ","}}){{- end}}, {{.ToUpperCase $ctrName}}Instance.{{.ToUpperCase .Name}})
+	group.Handle("{{.ToUpper .Method}}", "{{.APIPrefix .Version}}/{{.APIPath $ctr.Name .Path}}/{{.Name}}"{{- if .Auth}}, Auth{{- end}}{{- if gt (len .Roles) 0}}, Roles({{.FormatString .Roles ","}}){{- end}}{{- if gt .Cache 0}}, Cache({{.Cache}}*time.Second){{- end}}, {{.ToUpperCase $ctrName}}Instance.{{.ToUpperCase .Name}})
 	{{- end}}
 }
 

+ 3 - 0
cmd/dolphin/parser/xml.go

@@ -110,6 +110,9 @@ func (parser *AppParser) parse(xmlPath string) error {
 						api.Path = attrValue
 					case attrName == "roles":
 						api.Roles = strings.Split(attrValue, ",")
+					case attrName == "cache":
+						sed, _ := strconv.ParseUint(attrValue, 10, 64)
+						api.Cache = sed
 					case attrName == "auth":
 						ret, err := strconv.ParseBool(strings.TrimSpace(attrValue))
 						if err != nil {

+ 1 - 0
cmd/dolphin/schema/schema.go

@@ -40,6 +40,7 @@ type API struct {
 	Func    string
 	Table   string
 	Method  string
+	Cache   uint64
 	Params  []*Param
 	Return  *Return
 }

+ 9 - 1
demo/app/app.go

@@ -5,6 +5,7 @@ package app
 
 import (
 	"sync"
+	"time"
 
 	"github.com/2637309949/dolphin/packages/gin"
 	"github.com/2637309949/dolphin/packages/go-funk"
@@ -65,7 +66,14 @@ func Auth(ctx *Context) {
 // Roles middles
 func Roles(roles ...string) func(ctx *Context) {
 	return func(ctx *Context) {
-		pApp.Roles(roles...)
+		pApp.Roles(roles...)(ctx.Context)
+	}
+}
+
+// Cache middles
+func Cache(time time.Duration) func(ctx *Context) {
+	return func(ctx *Context) {
+		pApp.Cache(time)(ctx.Context)
 	}
 }
 

+ 4 - 2
demo/doc/swagger.yaml

@@ -155,7 +155,8 @@ definitions:
         description: 最后更新时间
         type: string
       url:
-        description: 菜单URL,类型:1.普通页面(如用户管理, /sys/user) 2.嵌套完整外部页面,以http(s)开头的链接 3.嵌套服务器页面,使用iframe:前缀+目标URL(如SQL监控, iframe:/druid/login.html, iframe:前缀会替换成服务器地址)
+        description: 菜单URL,类型:1.普通页面(如用户管理, /sys/user) 2.嵌套完整外部页面,以http(s)开头的链接 3.嵌套服务器页面,使用iframe:前缀+目标URL(如SQL监控,
+          iframe:/druid/login.html, iframe:前缀会替换成服务器地址)
         type: string
     type: object
   model.SysArea:
@@ -449,7 +450,8 @@ definitions:
         description: 最后更新时间
         type: string
       url:
-        description: 菜单URL,类型:1.普通页面(如用户管理, /sys/user) 2.嵌套完整外部页面,以http(s)开头的链接 3.嵌套服务器页面,使用iframe:前缀+目标URL(如SQL监控, iframe:/druid/login.html, iframe:前缀会替换成服务器地址)
+        description: 菜单URL,类型:1.普通页面(如用户管理, /sys/user) 2.嵌套完整外部页面,以http(s)开头的链接 3.嵌套服务器页面,使用iframe:前缀+目标URL(如SQL监控,
+          iframe:/druid/login.html, iframe:前缀会替换成服务器地址)
         type: string
     type: object
   model.SysNotification:

+ 3 - 0
demo/go.sum

@@ -20,6 +20,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bndr/gotabulate v1.1.2/go.mod h1:0+8yUgaPTtLRTjf49E8oju7ojpU11YmXyvq1LbPAb3U=
+github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g=
 github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -120,6 +121,7 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
 github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/memcachier/mc v2.0.1+incompatible h1:s8EDz0xrJLP8goitwZOoq1vA/sm0fPS4X3KAF0nyhWQ=
 github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -150,6 +152,7 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62 h1:pyecQtsPmlkCsMkYhT5iZ+sUXuwee+OvfuJjinEA3ko=
 github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62/go.mod h1:65XQgovT59RWatovFwnwocoUxiI/eENTnOY5GK3STuY=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=

+ 1 - 1
demo/xml/controller/applet_activity.xml

@@ -42,7 +42,7 @@
             <failure type="$response" />
         </return>
     </api>
-    <api name="list" func="page" table="applet_activity" desc="活动分页查询" method="get" roles="admin,xd">
+    <api name="list" func="page" table="applet_activity" desc="活动分页查询" method="get" roles="X8e6D3y60K" cache="60">
         <param name="page" type="int" desc="页码" value="1" />
         <param name="size" type="int" desc="单页数" value="20" />
         <param name="title" type="string" desc="标题筛选" value="nn" />

+ 12 - 9
packages/cache/cache.go

@@ -145,12 +145,13 @@ func SiteCache(store persistence.CacheStore, expire time.Duration) gin.HandlerFu
 				}
 			}
 			c.Writer.Write(cache.Data)
+			c.Abort()
 		}
 	}
 }
 
 // CachePage Decorator
-func CachePage(store persistence.CacheStore, expire time.Duration, handle gin.HandlerFunc) gin.HandlerFunc {
+func CachePage(store persistence.CacheStore, expire time.Duration) gin.HandlerFunc {
 	return func(c *gin.Context) {
 		var cache responseCache
 		url := c.Request.URL
@@ -162,8 +163,7 @@ func CachePage(store persistence.CacheStore, expire time.Duration, handle gin.Ha
 			// replace writer
 			writer := newCachedWriter(store, expire, c.Writer, key)
 			c.Writer = writer
-			handle(c)
-
+			c.Next()
 			// Drop caches of aborted contexts
 			if c.IsAborted() {
 				store.Delete(key)
@@ -176,12 +176,13 @@ func CachePage(store persistence.CacheStore, expire time.Duration, handle gin.Ha
 				}
 			}
 			c.Writer.Write(cache.Data)
+			c.Abort()
 		}
 	}
 }
 
 // CachePageWithoutQuery add ability to ignore GET query parameters.
-func CachePageWithoutQuery(store persistence.CacheStore, expire time.Duration, handle gin.HandlerFunc) gin.HandlerFunc {
+func CachePageWithoutQuery(store persistence.CacheStore, expire time.Duration) gin.HandlerFunc {
 	return func(c *gin.Context) {
 		var cache responseCache
 		key := CreateKey(c.Request.URL.Path)
@@ -192,7 +193,7 @@ func CachePageWithoutQuery(store persistence.CacheStore, expire time.Duration, h
 			// replace writer
 			writer := newCachedWriter(store, expire, c.Writer, key)
 			c.Writer = writer
-			handle(c)
+			c.Next()
 		} else {
 			c.Writer.WriteHeader(cache.Status)
 			for k, vals := range cache.Header {
@@ -201,14 +202,15 @@ func CachePageWithoutQuery(store persistence.CacheStore, expire time.Duration, h
 				}
 			}
 			c.Writer.Write(cache.Data)
+			c.Abort()
 		}
 	}
 }
 
 // CachePageAtomic Decorator
-func CachePageAtomic(store persistence.CacheStore, expire time.Duration, handle gin.HandlerFunc) gin.HandlerFunc {
+func CachePageAtomic(store persistence.CacheStore, expire time.Duration) gin.HandlerFunc {
 	var m sync.Mutex
-	p := CachePage(store, expire, handle)
+	p := CachePage(store, expire)
 	return func(c *gin.Context) {
 		m.Lock()
 		defer m.Unlock()
@@ -216,7 +218,7 @@ func CachePageAtomic(store persistence.CacheStore, expire time.Duration, handle
 	}
 }
 
-func CachePageWithoutHeader(store persistence.CacheStore, expire time.Duration, handle gin.HandlerFunc) gin.HandlerFunc {
+func CachePageWithoutHeader(store persistence.CacheStore, expire time.Duration) gin.HandlerFunc {
 	return func(c *gin.Context) {
 		var cache responseCache
 		url := c.Request.URL
@@ -228,7 +230,7 @@ func CachePageWithoutHeader(store persistence.CacheStore, expire time.Duration,
 			// replace writer
 			writer := newCachedWriter(store, expire, c.Writer, key)
 			c.Writer = writer
-			handle(c)
+			c.Next()
 
 			// Drop caches of aborted contexts
 			if c.IsAborted() {
@@ -237,6 +239,7 @@ func CachePageWithoutHeader(store persistence.CacheStore, expire time.Duration,
 		} else {
 			c.Writer.WriteHeader(cache.Status)
 			c.Writer.Write(cache.Data)
+			c.Abort()
 		}
 	}
 }

+ 3 - 1
platform/app/app.auto.go

@@ -4,6 +4,8 @@
 package app
 
 import (
+	"time"
+
 	"github.com/2637309949/dolphin/packages/viper"
 	"github.com/2637309949/dolphin/platform/model"
 )
@@ -662,7 +664,7 @@ func SysUserRoutes(engine *Engine) {
 	group.Handle("POST", "/sys/user/add", Auth, Roles("X8e6D3y60K"), SysUserInstance.Add)
 	group.Handle("DELETE", "/sys/user/del", Auth, Roles("X8e6D3y60K"), SysUserInstance.Del)
 	group.Handle("PUT", "/sys/user/update", Auth, Roles("X8e6D3y60K"), SysUserInstance.Update)
-	group.Handle("GET", "/sys/user/page", Auth, SysUserInstance.Page)
+	group.Handle("GET", "/sys/user/page", Auth, Cache(5*time.Second), SysUserInstance.Page)
 	group.Handle("GET", "/sys/user/get", Auth, SysUserInstance.Get)
 	group.Handle("POST", "/sys/user/login", SysUserInstance.Login)
 	group.Handle("GET", "/sys/user/logout", Auth, SysUserInstance.Logout)

+ 15 - 0
platform/app/app.manager.go

@@ -7,7 +7,11 @@ package app
 import (
 	"fmt"
 	"strconv"
+	"time"
 
+	"github.com/2637309949/dolphin/packages/cache"
+
+	"github.com/2637309949/dolphin/packages/cache/persistence"
 	"github.com/2637309949/dolphin/packages/logrus"
 	"github.com/2637309949/dolphin/packages/oauth2"
 	"github.com/2637309949/dolphin/packages/oauth2/store"
@@ -73,9 +77,19 @@ func NewDefaultManager() Manager {
 	return mg
 }
 
+// Cache middles
+func Cache(time time.Duration) func(ctx *Context) {
+	return func(ctx *Context) {
+		cache.CachePage(CacheStore, time)(ctx.Context)
+	}
+}
+
 // RedisClient defined
 var RedisClient *redis.Client
 
+// CacheStore defined
+var CacheStore persistence.CacheStore
+
 func init() {
 	if uri := util.EnsureLeft(http.Parse(viper.GetString("rd.dataSource"))).(*http.URI); uri.Laddr != "" {
 		RedisClient := redis.NewClient(&redis.Options{
@@ -88,4 +102,5 @@ func init() {
 			RedisClient = nil
 		}
 	}
+	CacheStore = persistence.NewInMemoryStore(60 * time.Second)
 }