反射入門可以先看這個http://colobu.com/2015/09/23/laws-of-goang-reflection/
因為在使用gin框架吆寨,在配置路由的時候需要手動配置撼短,如下:
r.GET("/page",controller.Page)
r.GET("/index",controller.Index)
其中controller是包名托修,如果在controller包中再增加方法,那就需要在這個地方繼續(xù)更新包翅溺,所以考慮有沒有方法自動掃描controller中的包脑漫,進行自動注冊呢髓抑。
于是想到了反射咙崎,但是查閱資料沒有發(fā)現(xiàn)可以用反射來提取包中的方法。只能另尋思路吨拍。
新的思路是褪猛,新建一個類,每個控制方法都屬于這個類羹饰。
如下:
type Ctl struct{
}
那么這個時候伊滋,就可以通過Ctl這個類對象來獲取其所有的方法,這樣就可以根據(jù)方法來設置路由規(guī)則队秩,達到自動掃描功能笑旺。
其中controller這樣寫:
func (this *Ctl) GETPage(c *gin.Context){
c.HTML(http.StatusOK, "page/page.tmpl",gin.H{
"title":"TEST",
})
}
反射中這樣寫的:
ctl := controller.Ctl{}
// 通過反射獲取ctl中的所有方法
refCtl := reflect.TypeOf(&ctl)
methodCnt := refCtl.NumMethod()
for index := 0; index<methodCnt; index++{
m := refCtl.Method(index)
methodName := m.Name
if strings.HasPrefix(methodName,"GET") {
name := strings.ToLower(strings.Replace(methodName,"GET","",1))
fmt.Println(name)
r.GET(name,m.Func.Interface().(gin.HandlerFunc))
//r.GET(name,m.Func)
}
}
然而最終給我報錯,
interface {} is func(*controller.Ctl, *gin.Context), not gin.HandlerFunc
到這我明白了馍资,形如func (this *Ctl) GETPage(c *gin.Context)
的函數(shù)筒主,其底層其實是func GETPage(this *Ctl, c *gin.Context)
但是雖然如此,這個問題依然沒難倒我(用了一下午想出來一個辦法鸟蟹。乌妙。)
方法是使用map保存path和方法的映射,router中設置統(tǒng)一入口建钥,在該入口進行路由配置藤韵,代碼如下:
package router
import (
"github.com/gin-gonic/gin"
"blog/controller"
"reflect"
"strings"
)
var (
ctl = controller.Ctl{}
methods = make(map[string]reflect.Method)
)
func SetRouter(r *gin.Engine){
// 通過反射獲取ctl中的所有方法
refCtl := reflect.TypeOf(&ctl)
methodCnt := refCtl.NumMethod()
for index := 0; index<methodCnt; index++{
m := refCtl.Method(index)
methodName := m.Name
if strings.HasPrefix(methodName,"GET") {
name := strings.ToLower(strings.Replace(methodName,"GET","",1))
//將path對應的反射方法保存
methods[name] = m
// 設置路由統(tǒng)一入口
r.GET(name,doHandle)
}
}
}
//統(tǒng)一入口
func doHandle(ctx *gin.Context){
//獲取path
p := strings.Split(ctx.Request.URL.Path,"/")[1]
vals := make([]reflect.Value,2)
vals[0] = reflect.ValueOf(&ctl)
vals[1] = reflect.ValueOf(ctx)
//反射進行調用
methods[p].Func.Call(vals)
}
當然這只是提供一種思路,實際使用的時候熊经,因為路由的配置相當復雜泽艘,還是建議手動進行配置