Goを使って簡単なMVCのWebフレームワークを書く
Bingo
Golang中国語ネットで初登場
これは私が最近書き始めたものです.
PHPから回ってきたばかりで、Goの特性についてはまだよく分からないので、ginを適用してみました.いいと思いますが、Laravelほど便利ではありません.
だから車輪を作ってみたい...en .... みそにする
bingoはgo言語に基づく軽量レベルのAPIフレームワークでありrestfulAPIの構築に専念している.
GitHubアドレス:silsuer/bingo
最近私は多くの修正をして、gayhubの上のはこの文章ととても合わないで、だからここで更にcommitのリンクを貼ってここをクリックします~
ディレクトリ構造 app Webサイト関連コード を配置 core配置フレームコアコードa vendorサードパーティライブラリを配置しglideを使用してサードパーティライブラリ を管理 public配置htmlコード 開発プロセス
goのnetパッケージは極めて使いやすく、それを使ってフレームワークを開発するのも極めて速い(phpフレームワークを書くよりも速いなんて...)
まずmain関数を決定し、main関数で構造体をインスタンス化し、Run関数を呼び出せばよい.
操作:
次にbingoファイルを書きます.
私たちは自分でいろいろなルートを制御しなければならないので、netパッケージに付属しているhttpサービスを使うことができません.ネット上には多くの原理がはっきりしています.
Muxというルータインタフェースを実現するために
ブラウザがアクセスする異なるURLに基づいて,異なるコントローラやミドルウェアの構造体を反射することによって得,
対応するメソッドを呼び出し、アクセスするURLが定義されていなければ、静的フォルダに行って探し、見つかったら静的ファイルを出力し、そうでなければ404ページを出力します.
(P.S.は無状態のAPI高速開発フレームワークを実現するため、テンプレートレンダリングを必要とせず、すべてのデータがajaxを介してページに転送される)
この関数では
具体的な定義は次のとおりです.
ここではapp/controllerおよびmiddlewareパッケージの構造体を使用します.ルーティングが完了すると、リクエストされたパスがここのmapに対応します.routerでルーティングコードを解析する方法を見てみましょう.
コンパイルを準備する段階でinit関数を実行し、ルーティングフォルダの下のすべてのルーティングリストを取得します.jsonフォーマットを使用してルーティングを組織し、解析したデータをRoutesListリストに格納します.
解析コードは次のとおりです
jsonファイルを解析してルーティングリストを取得し、上のSerbeHttpファイルでルーティングリストと比較できます.
これにより,簡単なGOを用いたWebフレームワークを実現した.
現在、静的ページの表示とAPI応答のみが可能
次に実現するのは、便利なORM コントローラおよびミドルウェアを素早く追加するコマンド を作成する.データベース移行を実現 tokenベースのAPI認証 を実現データキャッシュ キュー フック 便利なファイルアップロード/ストレージ機能 starを求めて、PR~ハハハ(silsuer/bingo)を歓迎します
これはずっと前に书いたもので、今はフレームワークがたくさん更新されていますが、原生开発にとってはまだ参考価値があるのではないでしょうか.
Golang中国語ネットで初登場
これは私が最近書き始めたものです.
PHPから回ってきたばかりで、Goの特性についてはまだよく分からないので、ginを適用してみました.いいと思いますが、Laravelほど便利ではありません.
だから車輪を作ってみたい...en .... みそにする
bingoはgo言語に基づく軽量レベルのAPIフレームワークでありrestfulAPIの構築に専念している.
GitHubアドレス:silsuer/bingo
最近私は多くの修正をして、gayhubの上のはこの文章ととても合わないで、だからここで更にcommitのリンクを貼ってここをクリックします~
ディレクトリ構造
goのnetパッケージは極めて使いやすく、それを使ってフレームワークを開発するのも極めて速い(phpフレームワークを書くよりも速いなんて...)
まずmain関数を決定し、main関数で構造体をインスタンス化し、Run関数を呼び出せばよい.
操作:
func main() {
// new bingo , bingo.Run()
// , index.html ,
// env
bingo := new(core.Bingo)
bingo.Run(":12345")
}
次にbingoファイルを書きます.
func (b *Bingo) Run(port string) {
// , , http
// , 、
// router , router json , json ,
// env config ,
// , , , http
http.ListenAndServe(port, bin)
// TODO
}
Run
関数は非常に簡単で、1行のコードしかありません.Httpサーバを開き、受信したポートを傍受します.私たちは自分でいろいろなルートを制御しなければならないので、netパッケージに付属しているhttpサービスを使うことができません.ネット上には多くの原理がはっきりしています.
Muxというルータインタフェースを実現するために
ServeHTTP
メソッドを実装する必要があるので、ServeHttp
メソッドをもう1つ書きます. func (b *Bingo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
flag := false //
// http , , URL,
params := []reflect.Value{reflect.ValueOf(w), reflect.ValueOf(r)}
for _, v := range RoutesList {
// , ,
// ,
if r.URL.Path == v.path && r.Method == v.method {
flag = true // ,
//TODO ,
// , ,
for _, m := range v.middleware {
if mid, ok := MiddlewareMap[m]; ok { //
rmid := reflect.ValueOf(mid)
params = rmid.MethodByName("Handle").Call(params) // , values
// ,
str := rmid.Elem().FieldByName("ResString").String()
if str != "" {
status := rmid.Elem().FieldByName("Status").Int()
// , , 500
if status == 0 {
status = 500
}
w.WriteHeader(int(status))
fmt.Fprint(w,str)
return
}
}
}
// ,
//
if d, ok := ControllerMap[v.controller]; ok { // c , c
reflect.ValueOf(d).MethodByName(v.function).Call(params)
}
//
return
}
}
// ,
if !flag {
//
http.ServeFile(w,r,GetPublicPath()+ r.URL.Path)
}
return
}
ブラウザがアクセスする異なるURLに基づいて,異なるコントローラやミドルウェアの構造体を反射することによって得,
対応するメソッドを呼び出し、アクセスするURLが定義されていなければ、静的フォルダに行って探し、見つかったら静的ファイルを出力し、そうでなければ404ページを出力します.
(P.S.は無状態のAPI高速開発フレームワークを実現するため、テンプレートレンダリングを必要とせず、すべてのデータがajaxを介してページに転送される)
この関数では
MiddlewareMap[m]
およびControllerMap[m]
を使用していることに気づきました.これはミドルウェアおよびコントローラのmapで、プログラムの初期化時にメモリに格納されます.具体的な定義は次のとおりです.
//
// map
var ControllerMap map[string]interface{}
// map
var MiddlewareMap map[string]interface{}
func init() {
ControllerMap = make(map[string]interface{})
MiddlewareMap = make(map[string]interface{})
// map ,
//
MiddlewareMap["WebMiddleware"] =&middleware.WebMiddleware{}
//
ControllerMap["Controller"] = &controller.Controller{}
}
ここではapp/controllerおよびmiddlewareパッケージの構造体を使用します.ルーティングが完了すると、リクエストされたパスがここのmapに対応します.routerでルーティングコードを解析する方法を見てみましょう.
type route struct {
path string //
target string // Controller@index
method string // get post
alias string //
middleware []string //
controller string //
function string //
}
type route_group struct {
root_path string //
root_target string // Controller@index
alias string //
middleware []string //
routes []route //
}
var Routes []route //
var RoutesGroups []route_group //
var RoutesList []route //
var R interface{}
func init() {
// ,
// , , ,
routes_path := GetRoutesPath()
dir_list, err := ioutil.ReadDir(routes_path)
Check(err)
// dir list json ,
for _, v := range dir_list {
fmt.Println(" ........" + v.Name())
// , json,
content, err := FileGetContents(routes_path + "/" + v.Name())
Check(err)
err = json.Unmarshal([]byte(content), &R)
Check(err)
// R,
parse(R)
}
}
コンパイルを準備する段階でinit関数を実行し、ルーティングフォルダの下のすべてのルーティングリストを取得します.jsonフォーマットを使用してルーティングを組織し、解析したデータをRoutesListリストに格納します.
解析コードは次のとおりです
func parse(r interface{}) {
// r
m := r.(map[string]interface{})
//newRoute := route{}
for k, v := range m {
if k == "Routes" {
//
parseRoutes(v)
}
if k == "RoutesGroups" {
//
parseRoutesGroups(v)
}
}
}
// json
func parseRoutes(r interface{}) {
m := r.([]interface{})
for _, v := range m {
// v
simpleRoute := v.(map[string]interface{})
//
newRoute := route{}
for kk, vv := range simpleRoute {
switch kk {
case "Route":
newRoute.path = vv.(string)
break
case "Target":
newRoute.target = vv.(string)
break
case "Method":
newRoute.method = vv.(string)
break
case "Alias":
newRoute.alias = vv.(string)
break
case "Middleware":
//newRoute.middleware = vv.([])
var mdw []string
vvm := vv.([]interface{})
for _, vvv := range vvm {
mdw = append(mdw, vvv.(string))
}
newRoute.middleware = mdw
break
default:
break
}
}
// target
cf := strings.Split(newRoute.target,"@")
if len(cf)==2 {
newRoute.controller = cf[0]
newRoute.function = cf[1]
}else{
fmt.Println("Target !"+newRoute.target)
return
}
// , ,
Routes = append(Routes, newRoute)
RoutesList = append(RoutesList, newRoute)
}
}
func parseRoutesGroups(r interface{}) {
//
m := r.([]interface{})
for _, v := range m {
group := v.(map[string]interface{})
for kk, vv := range group {
//
var newGroup route_group
switch kk {
case "RootRoute":
newGroup.root_path = vv.(string)
break
case "RootTarget":
newGroup.root_target = vv.(string)
break
case "Middleware":
var mdw []string
vvm := vv.([]interface{})
for _, vvv := range vvm {
mdw = append(mdw, vvv.(string))
}
newGroup.middleware = mdw
break
case "Routes":
// , parseRoutes ,
rs := parseRootRoute(group)
newGroup.routes = rs
break
default:
break
}
// group
RoutesGroups = append(RoutesGroups,newGroup)
}
}
}
// inteface ,
// ,
func parseRootRoute(group map[string]interface{}) []route {
// ,
var tmpRoutes []route //
var route_root_path string
var target_root_path string
var public_middleware []string
for k, v := range group {
if k == "RootRoute" {
route_root_path = v.(string)
}
if k == "RootTarget" {
target_root_path = v.(string)
}
if k=="Middleware" {
vvm := v.([]interface{})
for _, vvv := range vvm {
public_middleware = append(public_middleware, vvv.(string))
}
}
}
//
for k, s := range group {
if k == "Routes" {
m := s.([]interface{})
for _, v := range m {
// v
simpleRoute := v.(map[string]interface{})
//
newRoute := route{}
for kk, vv := range simpleRoute {
switch kk {
case "Route":
newRoute.path = route_root_path+ vv.(string)
break
case "Target":
newRoute.target = target_root_path+ vv.(string)
break
case "Method":
newRoute.method = vv.(string)
break
case "Alias":
newRoute.alias = vv.(string)
break
case "Middleware":
vvm := vv.([]interface{})
for _, vvv := range vvm {
newRoute.middleware = append(public_middleware,vvv.(string))//
}
break
default:
break
}
}
// target
cf := strings.Split(newRoute.target,"@")
if len(cf)==2 {
newRoute.controller = cf[0]
newRoute.function = cf[1]
}else{
fmt.Println("Target !"+newRoute.target)
os.Exit(2)
}
// , , ,
RoutesList = append(RoutesList, newRoute)
tmpRoutes = append(tmpRoutes,newRoute)
}
}
}
return tmpRoutes
}
jsonファイルを解析してルーティングリストを取得し、上のSerbeHttpファイルでルーティングリストと比較できます.
これにより,簡単なGOを用いたWebフレームワークを実現した.
現在、静的ページの表示とAPI応答のみが可能
次に実現するのは、
これはずっと前に书いたもので、今はフレームワークがたくさん更新されていますが、原生开発にとってはまだ参考価値があるのではないでしょうか.