Golangの簡単な例

6572 ワード

1 main.go appを起動
package main

import (
	"log"
	"github.com/track/blogserver/pkg/app"
)

func main() {

	//    app
	app := app.NewApp()
	defer app.Destory()

	//   
	log.Fatal(app.Launch())
}

2 app packetはdotwebフレームワークを用いてhttpサーバ、dotwebを構築する.New()が返すdotwebオブジェクトは、通常appと呼ばれ、ログ、キャッシュ、ホットロード、httpserverのロードなどの作業を担当します.コンテナ、宿主であり、httpserverはその環境で動作します.HttpServerは、リクエストの処理、ルーティング、セッション、ミドルウェアの管理などの機能を担当します.
サーバを初期化すると、ルーティング構成が初期化されます.
package app

import (
	"github.com/devfeel/dotweb"
	"github.com/track/blogserver/pkg/config"
	"github.com/track/blogserver/pkg/controllers"
	"github.com/track/blogserver/pkg/routers"
)

//     
type App struct {
	Conf   *config.BlogConfig
	Server *dotweb.DotWeb
}

func NewApp() *App {
	return &App{}
}

//     
func (app *App) Launch() error {
	app.Conf = config.Config()
	app.initServer()
	app.initRouter()
	return app.Server.StartServer(app.Conf.ServerPort)
}

//    
func (app *App) Destory() {
	if app.Server != nil {
		app.Server.Close()
	}
}

//          
func (app *App) initServer() {
	app.Server = dotweb.New()

	//  Log
	app.Server.SetEnabledLog(app.Conf.LogEnable)
	app.Server.SetLogPath(app.Conf.LogPath)

	//     error
	app.initError()

	//      
	if app.Conf.EnvProd {
		app.Server.SetProductionMode()
	} else {
		app.Server.SetDevelopmentMode()
	}
	//  Gzip  
	app.Server.HttpServer.SetEnabledGzip(false)
}

//       
func (app *App) initRouter() {

	r := routers.NewApiRouter(app.Server.HttpServer)

	// api/admin/xx api
	r.Admin()
}

//     error
func (app *App) initError() {
	ec := controllers.NewErrorController()
	app.Server.SetNotFoundHandle(ec.NotFound)
	app.Server.SetExceptionHandle(ec.Internal)
	app.Server.SetMethodNotAllowedHandle(ec.MethodNotAllowed)
}

エラー処理モジュールの定義:
package controllers

import (
	"fmt"
	"github.com/devfeel/dotweb"
	"github.com/track/blogserver/pkg/common"
	"net/http"
)

type ErrorController struct {
}

func NewErrorController() *ErrorController {
	return &ErrorController{}
}

//  404
func (ec *ErrorController) NotFound(context dotweb.Context) {
	context.WriteJsonC(http.StatusNotFound, common.ErrNotFound)
}

//  500
func (ec *ErrorController) Internal(context dotweb.Context, err error) {
	errCust := common.Err{
		Code: common.ErrInternal.Code,
		Msg:  fmt.Sprintf("%s %s", common.ErrInternal.Msg, err.Error()),
	}
	context.WriteJsonC(http.StatusInternalServerError, errCust)
}

//  405
func (ec *ErrorController) MethodNotAllowed(context dotweb.Context) {
	context.WriteJsonC(http.StatusMethodNotAllowed, common.ErrMethodNotAllow)
}

3 routerの実装ExtentControllerによるrouterの処理
package routers

import (
	"github.com/devfeel/dotweb"
	"github.com/track/blogserver/pkg/controllers"
)

type Router struct {
	server *dotweb.HttpServer
	group  dotweb.Group
}

//    
func NewApiRouter(server *dotweb.HttpServer) *Router {
	router := &Router{server: server, group: server.Group("/api")}
	return router
}

func (r *Router) Admin() {
	admin := r.group.Group("/admin")
	//    
	addItem(admin.Group("/extends"))
}

func addItem(item dotweb.Group) {
	ec := controllers.NewExtendController()
	item.OPTIONS("", ec.Options)
	item.POST("", ec.AddItem)
}

4 ExtentControlの実装
package controllers

import (
	"bufio"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/devfeel/dotweb"

	"github.com/track/blogserver/pkg/common"
	"github.com/track/blogserver/pkg/models"
	"github.com/track/blogserver/pkg/services"
	"github.com/track/blogserver/pkg/utils"
)

type ExtendController struct {

}

func NewExtendController() *ExtendController {
	return &ExtendController{}
}

func (ec *ExtendController) Options(ctx dotweb.Context) error {
	ctx.Response().SetHeader("Access-Control-Allow-Origin", "*") //       
	ctx.Response().SetHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
	ctx.Response().SetHeader("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With,Sign")

	return ctx.WriteJsonC(http.StatusNoContent, nil)
}

func (ec *ExtendController) AddItem(ctx dotweb.Context) error {

    //    
	orderno := ctx.FormValue("orderno")
	uid := ctx.FormValue("uid")
	origin := ctx.FormValue("itemid")
	originnum := ctx.FormValue("itemnum")

    //    ,         
	v := utils.Validation{}
	if v.Required(orderno) || v.Required(uid) || v.Required(origin) || v.Required(originnum) {
		return ctx.WriteJsonC(http.StatusBadRequest, models.Response{Err: common.ErrClientParams, Data: nil})
	}

    //       
	WriteItemFile(orderno, uid, origin, originnum)
	
    //    
	return ctx.WriteJsonC(http.StatusOK, models.Response{Err: common.Err{Msg: common.MsgResistSucc}, Data: nil})
}

5構成関連
package config

import (
	"fmt"
	"os"
	"path/filepath"
	"sync"

	"github.com/BurntSushi/toml"
)

// server config
// use: config.Config() return *BlogConfig  single instance
var (
	cfg   *BlogConfig
	sOnce sync.Once
	lock  = &sync.RWMutex{}
)

//       
type BlogConfig struct {
	LogEnable bool   `toml:"log_enable"`
	LogPath   string `toml:"log_path"`
	ServerPort int  `toml:"server_port"`
	EnvProd    bool `toml:"environment_prod"`
}

//return single config instance
func Config() *BlogConfig {
	sOnce.Do(decodeConfig)
	lock.RLock()
	defer lock.RUnlock()
	return cfg
}

//decode config with toml file
func decodeConfig() {
	path := os.Getenv("APP_CONFIG_PATH")
	if len(path) <= 0 {
		path = "./config/config_debug.toml"
	}
	fp, err := filepath.Abs(path)
	if err != nil {
		panic(fmt.Errorf(" Read Config Path Err: %s", fp))
	}
	config := new(BlogConfig)
	if _, err := toml.DecodeFile(fp, config); err != nil {
		panic(fmt.Errorf("DecodeFile Config  Err:  %s", err.Error()))
	}
	lock.Lock()
	cfg = config
	lock.Unlock()
}

およびプロファイル:
# This block as  Server Config
log_enable = true             #       
log_path = "/var/log/blogserver"  #          
server_port = 8888            #       
environment_prod = false      #     ,       true