GO Web 後端服務實例
源碼地址: https://github.com/mumushuiding/go-simple-web-demo
概述
一個極簡的GO Web後臺服務實例,全部採用go源生函數,簡單易用,輕量合理;
默認配置了mysql和redis服務
config
1、首先從根目錄下的config.json文件加載配置
2、使用系統參數覆蓋配置,這樣使用k8s部署時可以靈活設置參數
controller
接收前端請求
獲取get參數
打開 index.go 文件
獲取連接 http://localhost:8081/api/v1/test/index?par1=測試 中par1的值
// Index 首頁
func Index(writer http.ResponseWriter, request *http.Request) {
request.ParseForm()
par1:= getParam("par1",request)
}
func getParam(parameterName string, request *http.Request) string {
if len(request.Form[parameterName]) > 0 {
return request.Form[parameterName][0]
}
return ""
}
獲取POST參數
打開 index.go 文件
// GetBody2Struct 獲取POST參數,並轉化成指定的struct對象
func GetBody2Struct(request *http.Request, pojo interface{}) error {
s, _ := ioutil.ReadAll(request.Body)
if len(s) == 0 {
return nil
}
return json.Unmarshal(s, pojo)
}
model
db 連接
打開database.go文件
新建連接
db, err = gorm.Open(conf.DbType, fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", conf.DbUser, conf.DbPassword, conf.DbHost, conf.DbPort, conf.DbName))
自動新建表格
db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;").
AutoMigrate(&Test{})
添加索引
db.Model(&Test{}).AddIndex("idx_id", "id")
router 路由
打開 router.go 文件
路由設置
Mux.HandleFunc("/api/v1/test/index", interceptor(controller.Index))
跨域設置
func crossOrigin(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", conf.AccessControlAllowOrigin)
w.Header().Set("Access-Control-Allow-Methods", conf.AccessControlAllowMethods)
w.Header().Set("Access-Control-Allow-Headers", conf.AccessControlAllowHeaders)
h(w, r)
}
}
signal 信號設置
主要用於接收應用異常關閉信號,如Ctrl+C等,接收到信號之後關閉所有啓動的資源和goroutine防止內存泄露
打開 signal.go 文件
package main
import (
"log"
"net/http"
"os"
"os/signal"
)
// shutdownRequestChannel 用於關閉初始化
var shutdownRequestChannel = make(chan struct{})
// interruptSignals 定義默認的關閉觸發信號
var interruptSignals = []os.Signal{os.Interrupt}
// interruptListener 監聽關閉信號(Ctrl+C)
func interruptListener(s *http.Server) <-chan struct{} {
c := make(chan struct{})
go func() {
interruptChannel := make(chan os.Signal, 1)
signal.Notify(interruptChannel, interruptSignals...)
select {
case sig := <-interruptChannel:
log.Printf("收到關閉信號 (%s). 關閉...\n", sig)
s.Close()
case <-shutdownRequestChannel:
log.Println("關閉請求.關閉...")
s.Close()
}
close(c)
// 重複關閉信號處理
for {
select {
case sig := <-interruptChannel:
log.Printf("Received signal (%s). Already "+
"shutting down..\n", sig)
case <-shutdownRequestChannel:
log.Println("Shutdown requested. Already " +
"shutting down...")
}
}
}()
return c
}
func interruptRequested(interrupted <-chan struct{}) bool {
select {
case <-interrupted:
return true
default:
}
return false
}
main
打開 main.go文件