golang implements the routing scheduling detail with less than 20 lines of code
- 2020-06-15 09:16:28
- OfStack
preface
This paper mainly introduces the implementation of golang routing scheduling related content, Shared for your reference and learning, the following words do not say much, let's have a look at the detailed introduction
The project address
github (local download)
This project depends on
Standard library implementation with no additional dependencies
Why is the routing scheduling layer needed
The golang http standard library can only precisely match the requested URI and then execute handler. Every web project now has at least one Controller layer, implemented as struct, distributed to different methods according to different request paths.
Routing scheduler definition
Since golang cannot create objects dynamically for the time being (for example java's Class.forName ("xxx").newInstance (),xxx is an arbitrary class name). So you need to register 1 controller relationship manually.
Define routes to hold the controller pointer Parse request URL query parameters, provisional a for action name,c for controller name, this article stole the lazy, did not do the processing of PATH_INFO, also did not automatically capitalized the first letter of actionName, this does not affect the core content of this article to convey, interested readers can realize by themselves. Find the corresponding controller according to controllerName in URL Use reflection to set * http.Request and http.ResponseWriter for the current request object to that Controller Use reflection and actionName versus controller
Since the inheritance of golang is not 1-like OOP, there is no such thing as a parent-child class. Only interface{} can be used for route registration.
Code implementation
app/app.go
This file is the core scheduling file
package app
import (
"net/http"
"reflect"
"fmt"
)
type application struct {
routes map[string]interface{}
}
func New() *application {
return &application{
routes: make(map[string]interface{}),
}
}
func (p *application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
controllerName := r.URL.Query().Get("c")
actionName := r.URL.Query().Get("a")
if controllerName == "" || actionName == "" {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
route, ok := p.routes[controllerName]
if !ok {
http.Error(w, "Controller Not Found", http.StatusNotFound)
return
}
ele := reflect.ValueOf(route).Elem()
ele.FieldByName("Request").Set(reflect.ValueOf(r))
ele.FieldByName("Response").Set(reflect.ValueOf(w))
ele.MethodByName(actionName).Call([]reflect.Value{})
}
func (p *application) printRoutes() {
for route, controller := range p.routes {
ele := reflect.ValueOf(controller).Type().String()
fmt.Printf("%s %s\n", route, ele)
}
}
func (p *application) Get(route string, controller interface{}) {
p.routes[route] = controller
}
func (p *application) Run(addr string) error {
p.printRoutes()
fmt.Printf("listen on %s\n", addr)
return http.ListenAndServe(addr, p)
}
app/controller.go
Controller "Base class"
package app
import "net/http"
type Controller struct {
Response http.ResponseWriter
Request *http.Request
}
controller/site.go
Concrete business logic classes
package controllers
import (
"fmt"
"app"
)
type SiteController struct {
app.Controller
}
func (p SiteController) Index() {
fmt.Fprint(p.Response, p.Request.RequestURI)
}
main.go
Entrance to the file
package main
import (
_ "github.com/go-sql-driver/mysql"
"app"
"controllers"
)
func main() {
application := app.New()
application.Get("site", &controllers.SiteController{})
application.Run(":8080")
}
Run the project
Start the process
Visit http: / / localhost: 8080 & # 63; c = site
&
a=Index will print /? c = site
&
a=Index
Write in the last
I hope this small project can inspire readers to develop their own Web framework as soon as possible!