mirror of
https://github.com/astaxie/beego.git
synced 2024-11-22 13:00:54 +00:00
beego: support more router
//design model beego.Get(router, beego.FilterFunc) beego.Post(router, beego.FilterFunc) beego.Put(router, beego.FilterFunc) beego.Head(router, beego.FilterFunc) beego.Options(router, beego.FilterFunc) beego.Delete(router, beego.FilterFunc) beego.Handler(router, http.Handler) //example beego.Get("/user", func(ctx *context.Context) { ctx.Output.Body([]byte("Get userlist")) }) beego.Post("/user", func(ctx *context.Context) { ctx.Output.Body([]byte("add userlist")) }) beego.Delete("/user/:id", func(ctx *context.Context) { ctx.Output.Body([]byte([]byte(ctx.Input.Param(":id"))) }) import ( "http" "github.com/gorilla/rpc" "github.com/gorilla/rpc/json" ) func init() { s := rpc.NewServer() s.RegisterCodec(json.NewCodec(), "application/json") s.RegisterService(new(HelloService), "") beego.Handler("/rpc", s) }
This commit is contained in:
parent
ef815bf5fc
commit
55ad951bce
54
app.go
54
app.go
@ -136,6 +136,60 @@ func (app *App) AutoRouterWithPrefix(prefix string, c ControllerInterface) *App
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for Get method
|
||||
func (app *App) Get(rootpath string, f FilterFunc) *App {
|
||||
app.Handlers.Get(rootpath, f)
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for Post method
|
||||
func (app *App) Post(rootpath string, f FilterFunc) *App {
|
||||
app.Handlers.Post(rootpath, f)
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for Put method
|
||||
func (app *App) Put(rootpath string, f FilterFunc) *App {
|
||||
app.Handlers.Put(rootpath, f)
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for Delete method
|
||||
func (app *App) Delete(rootpath string, f FilterFunc) *App {
|
||||
app.Handlers.Delete(rootpath, f)
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for Options method
|
||||
func (app *App) Options(rootpath string, f FilterFunc) *App {
|
||||
app.Handlers.Options(rootpath, f)
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for Head method
|
||||
func (app *App) Head(rootpath string, f FilterFunc) *App {
|
||||
app.Handlers.Head(rootpath, f)
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for Patch method
|
||||
func (app *App) Patch(rootpath string, f FilterFunc) *App {
|
||||
app.Handlers.Patch(rootpath, f)
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for Patch method
|
||||
func (app *App) Any(rootpath string, f FilterFunc) *App {
|
||||
app.Handlers.Any(rootpath, f)
|
||||
return app
|
||||
}
|
||||
|
||||
// add router for http.Handler
|
||||
func (app *App) Handler(rootpath string, h http.Handler) *App {
|
||||
app.Handlers.Handler(rootpath, h)
|
||||
return app
|
||||
}
|
||||
|
||||
// UrlFor creates a url with another registered controller handler with params.
|
||||
// The endpoint is formed as path.controller.name to defined the controller method which will run.
|
||||
// The values need key-pair data to assign into controller method.
|
||||
|
54
beego.go
54
beego.go
@ -121,6 +121,60 @@ func AutoPrefix(prefix string, c ControllerInterface) *App {
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Get method
|
||||
func Get(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Get(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Post method
|
||||
func Post(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Post(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Delete method
|
||||
func Delete(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Delete(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Put method
|
||||
func Put(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Put(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Head method
|
||||
func Head(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Head(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Options method
|
||||
func Options(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Options(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Patch method
|
||||
func Patch(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Patch(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for all method
|
||||
func Any(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Any(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for own Handler
|
||||
func Handler(rootpath string, h http.Handler) *App {
|
||||
BeeApp.Handler(rootpath, h)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// ErrorHandler registers http.HandlerFunc to each http err code string.
|
||||
// usage:
|
||||
// beego.ErrorHandler("404",NotFound)
|
||||
|
293
router.go
293
router.go
@ -35,6 +35,12 @@ const (
|
||||
FinishRouter
|
||||
)
|
||||
|
||||
const (
|
||||
routerTypeBeego = iota
|
||||
routerTypeRESTFul
|
||||
routerTypeHandler
|
||||
)
|
||||
|
||||
var (
|
||||
// supported http methods.
|
||||
HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head", "trace", "connect"}
|
||||
@ -60,6 +66,9 @@ type controllerInfo struct {
|
||||
controllerType reflect.Type
|
||||
methods map[string]string
|
||||
hasMethod bool
|
||||
handler http.Handler
|
||||
runfunction FilterFunc
|
||||
routerType int
|
||||
}
|
||||
|
||||
// ControllerRegistor containers registered router rules, controller handlers and filters.
|
||||
@ -92,10 +101,211 @@ func NewControllerRegistor() *ControllerRegistor {
|
||||
// Add("/api",&RestController{},"get,post:ApiFunc")
|
||||
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
|
||||
func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
|
||||
parts := strings.Split(pattern, "/")
|
||||
j, params, parts := p.splitRoute(pattern)
|
||||
reflectVal := reflect.ValueOf(c)
|
||||
t := reflect.Indirect(reflectVal).Type()
|
||||
methods := make(map[string]string)
|
||||
if len(mappingMethods) > 0 {
|
||||
semi := strings.Split(mappingMethods[0], ";")
|
||||
for _, v := range semi {
|
||||
colon := strings.Split(v, ":")
|
||||
if len(colon) != 2 {
|
||||
panic("method mapping format is invalid")
|
||||
}
|
||||
comma := strings.Split(colon[0], ",")
|
||||
for _, m := range comma {
|
||||
if m == "*" || utils.InSlice(strings.ToLower(m), HTTPMETHOD) {
|
||||
if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
|
||||
methods[strings.ToLower(m)] = colon[1]
|
||||
} else {
|
||||
panic(colon[1] + " method doesn't exist in the controller " + t.Name())
|
||||
}
|
||||
} else {
|
||||
panic(v + " is an invalid method mapping. Method doesn't exist " + m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if j == 0 {
|
||||
//now create the Route
|
||||
route := &controllerInfo{}
|
||||
route.pattern = pattern
|
||||
route.controllerType = t
|
||||
route.methods = methods
|
||||
route.routerType = routerTypeBeego
|
||||
if len(methods) > 0 {
|
||||
route.hasMethod = true
|
||||
}
|
||||
p.fixrouters = append(p.fixrouters, route)
|
||||
} else { // add regexp routers
|
||||
//recreate the url pattern, with parameters replaced
|
||||
//by regular expressions. then compile the regex
|
||||
pattern = strings.Join(parts, "/")
|
||||
regex, regexErr := regexp.Compile(pattern)
|
||||
if regexErr != nil {
|
||||
//TODO add error handling here to avoid panic
|
||||
panic(regexErr)
|
||||
}
|
||||
|
||||
//now create the Route
|
||||
|
||||
route := &controllerInfo{}
|
||||
route.regex = regex
|
||||
route.params = params
|
||||
route.pattern = pattern
|
||||
route.methods = methods
|
||||
route.routerType = routerTypeBeego
|
||||
if len(methods) > 0 {
|
||||
route.hasMethod = true
|
||||
}
|
||||
route.controllerType = t
|
||||
p.routers = append(p.routers, route)
|
||||
}
|
||||
}
|
||||
|
||||
// add get method
|
||||
// usage:
|
||||
// Get("/", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Get(pattern string, f FilterFunc) {
|
||||
p.AddMethod("get", pattern, f)
|
||||
}
|
||||
|
||||
// add post method
|
||||
// usage:
|
||||
// Post("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Post(pattern string, f FilterFunc) {
|
||||
p.AddMethod("post", pattern, f)
|
||||
}
|
||||
|
||||
// add put method
|
||||
// usage:
|
||||
// Put("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Put(pattern string, f FilterFunc) {
|
||||
p.AddMethod("put", pattern, f)
|
||||
}
|
||||
|
||||
// add delete method
|
||||
// usage:
|
||||
// Delete("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Delete(pattern string, f FilterFunc) {
|
||||
p.AddMethod("delete", pattern, f)
|
||||
}
|
||||
|
||||
// add head method
|
||||
// usage:
|
||||
// Head("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Head(pattern string, f FilterFunc) {
|
||||
p.AddMethod("head", pattern, f)
|
||||
}
|
||||
|
||||
// add patch method
|
||||
// usage:
|
||||
// Patch("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Patch(pattern string, f FilterFunc) {
|
||||
p.AddMethod("patch", pattern, f)
|
||||
}
|
||||
|
||||
// add options method
|
||||
// usage:
|
||||
// Options("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Options(pattern string, f FilterFunc) {
|
||||
p.AddMethod("options", pattern, f)
|
||||
}
|
||||
|
||||
// add all method
|
||||
// usage:
|
||||
// Any("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Any(pattern string, f FilterFunc) {
|
||||
p.AddMethod("*", pattern, f)
|
||||
}
|
||||
|
||||
// add http method router
|
||||
// usage:
|
||||
// AddMethod("get","/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
|
||||
if method != "*" && !utils.InSlice(strings.ToLower(method), HTTPMETHOD) {
|
||||
panic("not support http method: " + method)
|
||||
}
|
||||
route := &controllerInfo{}
|
||||
route.routerType = routerTypeRESTFul
|
||||
route.runfunction = f
|
||||
methods := make(map[string]string)
|
||||
if method == "*" {
|
||||
for _, val := range HTTPMETHOD {
|
||||
methods[val] = val
|
||||
}
|
||||
} else {
|
||||
methods[method] = method
|
||||
}
|
||||
route.methods = methods
|
||||
paramnums, params, parts := p.splitRoute(pattern)
|
||||
if paramnums == 0 {
|
||||
//now create the Route
|
||||
route.pattern = pattern
|
||||
p.fixrouters = append(p.fixrouters, route)
|
||||
} else {
|
||||
//recreate the url pattern, with parameters replaced
|
||||
//by regular expressions. then compile the regex
|
||||
pattern = strings.Join(parts, "/")
|
||||
regex, regexErr := regexp.Compile(pattern)
|
||||
if regexErr != nil {
|
||||
panic(regexErr)
|
||||
}
|
||||
//now create the Route
|
||||
route.regex = regex
|
||||
route.params = params
|
||||
route.pattern = pattern
|
||||
p.routers = append(p.routers, route)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ControllerRegistor) Handler(pattern string, h http.Handler) {
|
||||
paramnums, params, parts := p.splitRoute(pattern)
|
||||
route := &controllerInfo{}
|
||||
route.routerType = routerTypeHandler
|
||||
route.handler = h
|
||||
if paramnums == 0 {
|
||||
route.pattern = pattern
|
||||
p.fixrouters = append(p.fixrouters, route)
|
||||
} else {
|
||||
//recreate the url pattern, with parameters replaced
|
||||
//by regular expressions. then compile the regex
|
||||
pattern = strings.Join(parts, "/")
|
||||
regex, regexErr := regexp.Compile(pattern)
|
||||
if regexErr != nil {
|
||||
panic(regexErr)
|
||||
}
|
||||
//now create the Route
|
||||
route.regex = regex
|
||||
route.params = params
|
||||
route.pattern = pattern
|
||||
p.routers = append(p.routers, route)
|
||||
}
|
||||
}
|
||||
|
||||
// analisys the patter to params & parts
|
||||
func (p *ControllerRegistor) splitRoute(pattern string) (paramnums int, params map[int]string, parts []string) {
|
||||
parts = strings.Split(pattern, "/")
|
||||
j := 0
|
||||
params := make(map[int]string)
|
||||
params = make(map[int]string)
|
||||
for i, part := range parts {
|
||||
if strings.HasPrefix(part, ":") {
|
||||
expr := "(.*)"
|
||||
@ -180,63 +390,7 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
|
||||
parts[i] = string(out)
|
||||
}
|
||||
}
|
||||
reflectVal := reflect.ValueOf(c)
|
||||
t := reflect.Indirect(reflectVal).Type()
|
||||
methods := make(map[string]string)
|
||||
if len(mappingMethods) > 0 {
|
||||
semi := strings.Split(mappingMethods[0], ";")
|
||||
for _, v := range semi {
|
||||
colon := strings.Split(v, ":")
|
||||
if len(colon) != 2 {
|
||||
panic("method mapping format is invalid")
|
||||
}
|
||||
comma := strings.Split(colon[0], ",")
|
||||
for _, m := range comma {
|
||||
if m == "*" || utils.InSlice(strings.ToLower(m), HTTPMETHOD) {
|
||||
if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
|
||||
methods[strings.ToLower(m)] = colon[1]
|
||||
} else {
|
||||
panic(colon[1] + " method doesn't exist in the controller " + t.Name())
|
||||
}
|
||||
} else {
|
||||
panic(v + " is an invalid method mapping. Method doesn't exist " + m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if j == 0 {
|
||||
//now create the Route
|
||||
route := &controllerInfo{}
|
||||
route.pattern = pattern
|
||||
route.controllerType = t
|
||||
route.methods = methods
|
||||
if len(methods) > 0 {
|
||||
route.hasMethod = true
|
||||
}
|
||||
p.fixrouters = append(p.fixrouters, route)
|
||||
} else { // add regexp routers
|
||||
//recreate the url pattern, with parameters replaced
|
||||
//by regular expressions. then compile the regex
|
||||
pattern = strings.Join(parts, "/")
|
||||
regex, regexErr := regexp.Compile(pattern)
|
||||
if regexErr != nil {
|
||||
//TODO add error handling here to avoid panic
|
||||
panic(regexErr)
|
||||
}
|
||||
|
||||
//now create the Route
|
||||
|
||||
route := &controllerInfo{}
|
||||
route.regex = regex
|
||||
route.params = params
|
||||
route.pattern = pattern
|
||||
route.methods = methods
|
||||
if len(methods) > 0 {
|
||||
route.hasMethod = true
|
||||
}
|
||||
route.controllerType = t
|
||||
p.routers = append(p.routers, route)
|
||||
}
|
||||
return j, params, parts
|
||||
}
|
||||
|
||||
// Add auto router to ControllerRegistor.
|
||||
@ -501,6 +655,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
var runrouter reflect.Type
|
||||
var findrouter bool
|
||||
var runMethod string
|
||||
var routerInfo *controllerInfo
|
||||
params := make(map[string]string)
|
||||
|
||||
w := &responseWriter{writer: rw}
|
||||
@ -584,6 +739,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
if requestPath == route.pattern {
|
||||
runMethod = p.getRunMethod(r.Method, context, route)
|
||||
if runMethod != "" {
|
||||
routerInfo = route
|
||||
runrouter = route.controllerType
|
||||
findrouter = true
|
||||
break
|
||||
@ -598,6 +754,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
if requestPath[n-1] == '/' && route.pattern+"/" == requestPath {
|
||||
runMethod = p.getRunMethod(r.Method, context, route)
|
||||
if runMethod != "" {
|
||||
routerInfo = route
|
||||
runrouter = route.controllerType
|
||||
findrouter = true
|
||||
break
|
||||
@ -636,6 +793,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
runMethod = p.getRunMethod(r.Method, context, route)
|
||||
if runMethod != "" {
|
||||
routerInfo = route
|
||||
runrouter = route.controllerType
|
||||
context.Input.Params = params
|
||||
findrouter = true
|
||||
@ -706,7 +864,23 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
if do_filter(BeforeExec) {
|
||||
goto Admin
|
||||
}
|
||||
isRunable := false
|
||||
if routerInfo != nil {
|
||||
if routerInfo.routerType == routerTypeRESTFul {
|
||||
if _, ok := routerInfo.methods[strings.ToLower(r.Method)]; ok {
|
||||
isRunable = true
|
||||
routerInfo.runfunction(context)
|
||||
} else {
|
||||
middleware.Exception("405", rw, r, "Method Not Allowed")
|
||||
goto Admin
|
||||
}
|
||||
} else if routerInfo.routerType == routerTypeHandler {
|
||||
isRunable = true
|
||||
routerInfo.handler.ServeHTTP(rw, r)
|
||||
}
|
||||
}
|
||||
|
||||
if !isRunable {
|
||||
//Invoke the request handler
|
||||
vc := reflect.New(runrouter)
|
||||
execController, ok := vc.Interface().(ControllerInterface)
|
||||
@ -765,6 +939,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
|
||||
// finish all runrouter. release resource
|
||||
execController.Finish()
|
||||
}
|
||||
|
||||
//execute middleware filters
|
||||
if do_filter(AfterExec) {
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/astaxie/beego/context"
|
||||
)
|
||||
|
||||
type TestController struct {
|
||||
@ -232,3 +234,47 @@ func TestAutoPrefix(t *testing.T) {
|
||||
t.Errorf("TestAutoPrefix can't run")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterGet(t *testing.T) {
|
||||
r, _ := http.NewRequest("GET", "/user", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegistor()
|
||||
handler.Get("/user", func(ctx *context.Context) {
|
||||
ctx.Output.Body([]byte("Get userlist"))
|
||||
})
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Body.String() != "Get userlist" {
|
||||
t.Errorf("TestRouterGet can't run")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterPost(t *testing.T) {
|
||||
r, _ := http.NewRequest("POST", "/user/123", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegistor()
|
||||
handler.Post("/user/:id", func(ctx *context.Context) {
|
||||
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
|
||||
})
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Body.String() != "123" {
|
||||
t.Errorf("TestRouterPost can't run")
|
||||
}
|
||||
}
|
||||
|
||||
func sayhello(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("sayhello"))
|
||||
}
|
||||
|
||||
func TestRouterHandler(t *testing.T) {
|
||||
r, _ := http.NewRequest("POST", "/sayhi", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegistor()
|
||||
handler.Handler("/sayhi", http.HandlerFunc(sayhello))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Body.String() != "sayhello" {
|
||||
t.Errorf("TestRouterHandler can't run")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user