diff --git a/context.go b/context.go new file mode 100644 index 0000000..f4e298f --- /dev/null +++ b/context.go @@ -0,0 +1,34 @@ +package bingo_router + +import ( + "net/http" + "github.com/json-iterator/go" +) + +// 上下文结构体 +type Context struct { + Writer http.ResponseWriter // 响应 + Request *http.Request // 请求 + Params Params //参数 + //Session Session // 保存session +} + +// 重定向,传入路径和状态码 +func (c *Context) Redirect(path string) { + url := c.Request.URL.Host + path + http.Redirect(c.Writer, c.Request, url, http.StatusFound) +} + +// 输出字符串 +func (c *Context) String(data string) { + c.Writer.WriteHeader(http.StatusOK) + c.Writer.Write([]byte(data)) +} + +// 输出json +func (c *Context) ResponseJson(data interface{}) { + json := jsoniter.ConfigCompatibleWithStandardLibrary + d, _ := json.Marshal(data) + c.Writer.WriteHeader(http.StatusOK) + c.Writer.Write([]byte(d)) +} diff --git a/controller.go b/controller.go new file mode 100644 index 0000000..81ba55f --- /dev/null +++ b/controller.go @@ -0,0 +1,43 @@ +package bingo_router + +// 控制器接口 +type IController interface { + Index(c *Context) // 对应 get : path方法 + Create(c *Context) // 对应 get : path/create 方法 + Store(c *Context) // 对应 post : path 方法 + Update(c *Context) // 对应put/patch : path/:id 方法 + Edit(c *Context) // 对应get : path/:id/edit + Show(c *Context) // 对应 get: route/:id + Destroy(c *Context) // 对应 delete: route/:id +} + +// 默认基本控制器 +type Controller struct { +} + +func (cc *Controller) Index(c *Context) { + +} + +func (cc *Controller) Create(c *Context) { + +} + +func (cc *Controller) Store(c *Context) { + +} + +func (cc *Controller) Update(c *Context) { + +} + +func (cc *Controller) Edit(c *Context) { + +} +func (cc *Controller) Show(c *Context) { + +} + +func (cc *Controller) Destroy(c *Context) { + +} diff --git a/examples/main.go b/examples/main.go index 388d977..c5df2dc 100644 --- a/examples/main.go +++ b/examples/main.go @@ -1,47 +1,46 @@ package main import ( - "fmt" "github.com/silsuer/bingo-router" "net/http" ) -// 定义 -func setRoute() *bingo_router.Route { - return bingo_router.NewRoute().Prefix("/common").Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { - fmt.Fprintln(c.Writer, "common middleware 1") - next(c) - }).Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { - fmt.Fprintln(c.Writer, "common middleware 2") - next(c) - }).Mount(func(b *bingo_router.Builder) { - b.NewRoute().Get("/test1").Target(func(c *bingo_router.Context) { - fmt.Fprint(c.Writer, "hello test 1") - }).Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { - next(c) - fmt.Fprintln(c.Writer, " middleware test 1") - - }) - - b.NewRoute().Get("/test2").Target(func(c *bingo_router.Context) { - fmt.Fprint(c.Writer, "hello test2") - }).Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { - next(c) - fmt.Fprintln(c.Writer, "test 2 middleware 1") - - }).Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { - fmt.Fprintln(c.Writer, "test 2 middleware 2") - next(c) - }) - }) -} +//// 定义 +//func setRoute() *bingo_router.Route { +// return bingo_router.NewRoute().Prefix("/common").Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { +// fmt.Fprintln(c.Writer, "common middleware 1") +// next(c) +// }).Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { +// fmt.Fprintln(c.Writer, "common middleware 2") +// next(c) +// }).Mount(func(b *bingo_router.Builder) { +// b.NewRoute().Get("/test1").Target(func(c *bingo_router.Context) { +// fmt.Fprint(c.Writer, "hello test 1") +// }).Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { +// next(c) +// fmt.Fprintln(c.Writer, " middleware test 1") +// +// }) +// +// b.NewRoute().Get("/test2").Target(func(c *bingo_router.Context) { +// fmt.Fprint(c.Writer, "hello test2") +// }).Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { +// next(c) +// fmt.Fprintln(c.Writer, "test 2 middleware 1") +// +// }).Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { +// fmt.Fprintln(c.Writer, "test 2 middleware 2") +// next(c) +// }) +// }) +//} func main() { // 创建一个路由 r := bingo_router.New() // 得到一个路由 - rr := setRoute() + //rr := setRoute() //r2 := bingo_router.NewRoute().Get("/test").Middleware(func(c *bingo_router.Context, next func(c *bingo_router.Context)) { // fmt.Fprint(c.Writer,"middleware") @@ -50,10 +49,26 @@ func main() { // fmt.Fprintln(c.Writer,"target") //}) // 挂载路由方法,遍历传入的所有路由,然后遍历每个路由里的子路由,并设定路径等,设定中间件等 - r.Mount(rr) + //r.Mount(rr) + + // 按照列表打印所有路由 + // 使用控制器一次性挂载多个路由 + r.Mount(bingo_router.NewRoute().Resource("/resource", &controller{})) // 启动服务 + r.PrintRoutes() http.ListenAndServe(":8080", r) // TODO 服务的平滑重启和关闭 } + +type controller struct { + bingo_router.Controller +} + +func (cc *controller) Index(c *bingo_router.Context) { + //c.Redirect("/get") + m := make(map[string]int) + m["id"] = 111 + c.ResponseJson(&m) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a57a477 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module github.com/silsuer/bingo-router + +require ( + github.com/json-iterator/go v1.1.5 // indirect + github.com/julienschmidt/httprouter v1.2.0 + github.com/klauspost/compress v0.0.0-20180801095237-b50017755d44 + github.com/klauspost/cpuid v1.2.0 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/modood/table v0.0.0-20181112072225-499dc7fba710 + github.com/valyala/bytebufferpool v0.0.0-20180905182247-cdfbe9377474 + github.com/valyala/fasthttp v0.0.0-20171207120941-e5f51c11919d +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ef22562 --- /dev/null +++ b/go.sum @@ -0,0 +1,13 @@ +github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/klauspost/compress v0.0.0-20180801095237-b50017755d44/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modood/table v0.0.0-20181112072225-499dc7fba710 h1:KkTJhLbA/nYDXBQZp9aRiBLAQ6LmcyV7v57vlCuCa94= +github.com/modood/table v0.0.0-20181112072225-499dc7fba710/go.mod h1:41qyXVI5QH9/ObyPj27CGCVau5v/njfc3Gjj7yzr0HQ= +github.com/valyala/bytebufferpool v0.0.0-20180905182247-cdfbe9377474/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v0.0.0-20171207120941-e5f51c11919d/go.mod h1:+g/po7GqyG5E+1CNgquiIxJnsXEi5vwFn5weFujbO78= diff --git a/route.go b/route.go index 8144e06..a6f5243 100644 --- a/route.go +++ b/route.go @@ -1,6 +1,10 @@ package bingo_router -import "net/http" +import ( + "strings" + "runtime" + "reflect" +) const GET = "GET" const POST = "POST" @@ -8,14 +12,6 @@ const DELETE = "DELETE" const PUT = "PUT" const PATCH = "PATCH" -// 上下文结构体 -type Context struct { - Writer http.ResponseWriter // 响应 - Request *http.Request // 请求 - Params Params //参数 - //Session Session // 保存session -} - // 路由 type Route struct { path string // 路径 @@ -63,7 +59,7 @@ func (r *Route) Post(path string) *Route { } // 添加路由时需要,设置为put方法 -func (r *Route) Put(path string, target TargetHandle) *Route { +func (r *Route) Put(path string) *Route { //return r.Request(PUT, path, target) r.path = path r.method = PUT @@ -71,7 +67,7 @@ func (r *Route) Put(path string, target TargetHandle) *Route { } // 添加路由时需要,设置为patch方法 -func (r *Route) Patch(path string, target TargetHandle) *Route { +func (r *Route) Patch(path string) *Route { //return r.Request(PATCH, path, target) r.path = path r.method = PATCH @@ -79,15 +75,33 @@ func (r *Route) Patch(path string, target TargetHandle) *Route { } // 添加路由时需要,设置为delete方法 -func (r *Route) Delete(path string, target TargetHandle) *Route { +func (r *Route) Delete(path string) *Route { //return r.Request(DELETE, path, target) r.path = path r.method = DELETE return r } +// 传入一个控制器,自动构建多个路由 +func (r *Route) Resource(path string, controller IController) *Route { + // 在当前路由下挂载子路由 + r.Mount(func(b *Builder) { + b.NewRoute().Get(path).Target(controller.Index) + b.NewRoute().Get(path + "/detail/:id").Target(controller.Show) + b.NewRoute().Post(path).Target(controller.Store) + b.NewRoute().Get(path + "/create").Target(controller.Create) + b.NewRoute().Put(path + "/:id").Target(controller.Update) + b.NewRoute().Patch(path + "/:id").Target(controller.Update) + b.NewRoute().Get(path + "/edit/:id").Target(controller.Edit) + b.NewRoute().Delete(path + "/:id").Target(controller.Destroy) + }) + return r +} + // 这里传入一个回调 func (r *Route) Target(target TargetHandle) *Route { + r.name = r.path + "." + r.method + return r.Request(r.method, r.path, target) } @@ -116,6 +130,14 @@ func (r *Route) MiddlewareGroup(hg []MiddlewareHandle) *Route { return r } +func (r *Route) Name(name string) *Route { + if r.name != "" { + return r + } + r.name = name + return r +} + // 挂载子路由,这里只是将回调中的路由放入 func (r *Route) Mount(rr func(b *Builder)) *Route { builder := new(Builder) @@ -127,4 +149,30 @@ func (r *Route) Mount(rr func(b *Builder)) *Route { return r } +func (r *Route) print(arr []Output) []Output { + o := Output{} + o.Name = r.name + o.URI = r.path + o.Method = r.method + o.Middleware = strings.Join(r.printMiddlewares(), "|") + o.Action = runtime.FuncForPC(reflect.ValueOf(r.targetMethod).Pointer()).Name() + arr = append(arr, o) + if len(r.mount) > 0 { + for rr := range r.mount { + arr = r.mount[rr].print(arr) + } + } + + return arr +} + +// 返回所有的中间件名称组合成的数组 +func (r *Route) printMiddlewares() []string { + var res []string + for m := range r.middleware { + res = append(res, runtime.FuncForPC(reflect.ValueOf(r.middleware[m]).Pointer()).Name()) + } + return res +} + // 每个请求进来都要生成一个管道,根据管道执行中间件最后到达目的路由 diff --git a/router.go b/router.go index c0d1497..36157ed 100644 --- a/router.go +++ b/router.go @@ -4,6 +4,7 @@ import ( "net/http" "strings" "strconv" + "github.com/modood/table" ) type Handle func(http.ResponseWriter, *http.Request, Params) @@ -333,7 +334,6 @@ func (r *Router) MountRoute(route *Route) { // 设置中间件 //setRouteMiddlewares(currentPointer, route) - if route.method != "" && p != "" { r.Handle(route.method, p, route) } @@ -380,3 +380,29 @@ func setMiddlewares(current int, route *Route) { } } } + +type Output struct { + Method string + URI string + Name string + Action string + Middleware string +} + +// 在控制台中打印所有路由 +func (r *Router) PrintRoutes() { + var outputs []Output + // 遍历所有路由,拼接成table结构体,然后打印输出 + for m := range r.trees { + rr := r.trees[m].route + if rr.path == "" { + continue + } + + // 调用路由的一个方法,传入一个 output数组,如果有 + outputs = append(outputs, rr.print(outputs)...) + } + + //fmt.Println(outputs) + table.Output(outputs) +}