以項目爲鑰匙開啓Go的世界

本文不一樣於其餘Go語言學習的文章,將以項目開發所需爲基礎,帶你飛速踏入Go的世界,成爲能獨擋一面的強者。當你稍微花幾分鐘的時間,看完本文的時候,或許你會發現,駕馭Go語言爲己所用是如此簡單。
山不在高,有仙則名,水不在深,有龍則靈,文不在多,一篇足以。但願我這些小小的經驗和用心的分享,能真的幫助到您。css

1、Go 語言簡介

1 Go 語言介紹

Go 即Golang,是Google公司2009年11月正式對外公開的一門編程語言。
Go是靜態強類型語言,是區別於解析型語言的編譯型語言。mysql

解析型語言——源代碼是先翻譯爲中間代碼,而後由解析器對代碼進行解釋執行。
編譯型語言——源代碼編譯生成機器語言,而後由機器直接執行機器碼便可執行。linux

2 Go語言特性

  • 跨平臺的編譯型語言
  • 語法接近C語言
  • 管道(channel),切片(slice),併發(routine)
  • 有垃圾回收的機制
  • 支持面向對象和麪向過程的編程模式

3 Go 語言特點

  • 編程模式比較簡單,沒有複雜的設計模式
  • 所有源碼編譯到一個文件,編譯速度很快
  • 最新版本也有動態庫形式,對跨語言調用的支撐更到位
  • 開源框架比較成熟,新崛起的互聯網公司都在用
  • 如滴滴,uber,百度,阿里巴巴,oppo,vivo等
  • 微服務的開發模式下Go語言是新寵

4 Go 擅長領域

  • 服務開發,web的api開發,分佈式服務集羣的開發
  • 容器docker是go開源的產品,k8s等這些都是基於go語言的
  • 對高併發、高性能的系統和服務支撐,Go語言對比其餘語言有更快的開發速度,更高的開發效率
  • 獨有的語言特性和設計模式routine,channel,sync包支撐了海量並行的支持。

因此能看到這些領域都在使用Go語言:微服務開發模式,api開發,rpc服務開發,遊戲服務開發等等git

2、框架選擇

Go的開發框架比較多,比較知名的幾個分別是Gin、BeeGo、Iris、Echo、Revel、Buffalo。對比排名詳見: 《Go語言Web框架對比》github

框架的選擇上,本人主要遵循以下幾點原則,分別是:golang

  • star多
  • 易上手
  • 性能佳
  • 持續維護

選擇過程很少說,本人最終選擇了beego做爲本次入手的框架,本文餘下內容如無特別說明,均基於此框架。web

3、環境部署

1 Go 語言環境安裝

安裝包下載地址爲:https://golang.org/dl/
若是打不開可使用這個地址:https://golang.google.cn/dl/redis

【UNIX/Linux/Mac OS X, 和 FreeBSD 安裝】sql

  • 下載二進制包:go1.4.linux-amd64.tar.gz
  • 將下載的二進制包解壓至 /usr/local目錄
  • tar-C/usr/local-xzf go1.12.7.linux-amd64.tar.gz
  • 將 /usr/local/go/bin 目錄添加至PATH環境變量:
  • exportPATH=$PATH:/usr/local/go/bin

注意:MAC 系統下你可使用 .pkg 結尾的安裝包直接雙擊來完成安裝,安裝目錄在 /usr/local/go/ 下。
本文餘下內容如無特別說明,均默認Linux環境docker

【Windows 系統下安裝】
Windows 下可使用 .msi 後綴(在下載列表中能夠找到該文件,如 go1.12.7.windows-amd64.msi)的安裝包來安裝。
默認狀況下.msi文件會安裝在 c:\Go 目錄下。你能夠將 c:\Go\bin 目錄添加到 PATH 環境變量中。
添加後你須要重啓命令窗口才能生效。

安裝測試:
建立工做目錄 C:\>Go_WorkSpace

//test.go 文件代碼:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}

 

使用 go 命令執行以上代碼輸出結果以下:

C:\Go_WorkSpace>go run test.go
Hello, World!

 

2 Go 語言環境變量

以下環境變量,都是Go編譯和運行時必要的,若是安裝時沒有自動設置好,請務必本身手動添加。

  • GOROOT: Go 安裝後的根目錄(例如:/usr/local/go)
  • GOPATH: Go 的工做空間,就是咱們的開發和依賴包的目錄(例如:~/go)

添加環境變量方法:

  1. 命令行直接export(對當前終端有效)
  2. 將export加到 ~/.bashrc文件裏(對當前用戶有效,首次添加後記得 source~/.bashrc一下)
export GOPATH=~/go
export GOROOT=/usr/local/go

 

3 BeeGo 框架

【安裝】
安裝方式很是簡單,只要敲擊以下命令便可(bee工具能夠快速建立項目和自動監測運行,記得要安裝哦):

go get github.com/astaxie/beego
# bee 工具
go get github.com/beego/bee

 

 

安裝完以後,bee 可執行文件默認存放在 $GOPATH/bin 裏面,因此您須要把 $GOPATH/bin 添加到您的環境變量PATH中: exportPATH=$PATH:$GOPATH/bin

常見問題:

  1. git 沒有安裝,請自行安裝不一樣平臺的 git,如何安裝請看《Git官方安裝說明》
  2. git https 沒法獲取,請配置本地的 git,關閉 https 驗證: git config--globalhttp.sslVerifyfalse

【建立項目】
打開終端,進入 $GOPATH/src 所在的目錄,用bee工具建立一個項目: beenewfirstPro

【目錄結構】
這是一個典型的 MVC 架構的應用,main.go 是入口文件。目錄結構以下所示:

.
├── conf
│   └── app.conf
├── controllers
│   └── default.go
├── main.go
├── models
├── routers
│   └── router.go
├── static
│   ├── css
│   ├── img
│   └── js
│   └── reload.min.js
├── tests
│   └── default_test.go
└── views
└── index.tpl
10 directories, 7 files

 

【編譯運行】
cd $GOPATH/src/firstPro進入咱們建立的項目,使用 bee run 來運行該項目,這樣咱們的應用就在 8080 端口(beego 的默認端口)跑起來了,讓咱們打開瀏覽器看看效果吧:

4 命令使用

Go指令

  • 下載: goget
  • 編譯: go build
  • 運行: go run

Bee工具

  • 新建項目: bee api 或 beenew 分別建立 api應用 和 web項目,位於 $GOPATH/src 目錄下
  • 運行: bee run 該命令必須在 $GOPATH/src/appname 下執行
  • 打包: bee pack

以上是一些經常使用的命令,介紹雖比較簡單,但只要大概記住他的做用便可。
沒有把全部指令都列出來,由於咱們暫時還用不到,這些已經足夠咱們擺平項目的開發了,其餘的指令和高級用法,有興趣的小夥伴們能夠動動手自行查閱。

4、Go 基礎語法

1 變量

Go 語言變量名由字母、數字、下劃線組成,其中首個字符不能爲數字。

【聲明變量】

  1. 使用 var 關鍵字:
    varname type
  2. 一次聲明多個變量:
    varname1,name2 type
  3. 省略var形式:
    name:=value

【零值】
指定變量類型,若是沒有初始化,則變量默認爲零值。

  • 數值類型(包括complex64/128)爲 0
  • 布爾類型爲 false
  • 字符串爲 ""(空字符串)
  • 如下幾種類型爲 nil:
var a *int
var a []int
var a map[string] int
var a chan int
var a func(string) int
var a error // error 是接口

 

【示例】

package main
import "fmt"
func main() {
var a string = "yisonli"
fmt.Println(a)
var b, c int = 1, 2
fmt.Println(b, c)
d := []int{10,9,8,7}
fmt.Println(d)
var e = map[string]int{"one":1, "two":2}
fmt.Println(e)
}

 

以上示例輸出結果爲:

yisonli
1 2
[10 9 8 7]
map[one:1 two:2]

 

2 數據類型

類型 描述
布爾型 布爾型的值只能夠是常量 true 或者 false 
一個簡單的例子: varbbool=true
數字類型 有符號整型: int、int八、int1六、int3二、int64 
無符號整型: uint、uint八、uint1六、uint3二、uint64 
浮點型: float3二、float64 
複數: complex6四、complex128 
其餘: byte (相似uint8)、uintptr (存指針)、rune (相似int32)
字符串類型 一串固定長度的字符鏈接起來的字符序列,使用 UTF-8 編碼標識 Unicode 文本
派生類型 包括:
(a) 指針類型(Pointer)
(b) 數組類型
(c) 結構化類型(struct)
(d) Channel 類型
(e) 函數類型
(f) 切片類型
(g) 接口類型(interface)
(h) Map 類型

3 函數

Go 語言函數定義格式以下:

func function_name( [parameter list] ) [return_types] {
函數體
}

 

函數定義解析:

  • func:函數聲明關鍵字
  • function_name:函數名稱
  • parameter list:參數列表
  • 參數就像一個佔位符,當函數被調用時,你能夠將值傳遞給參數,這個值被稱爲實際參數。
  • 參數列表指定的是參數類型、順序、及參數個數。
  • 參數是可選的,也就是說函數也能夠不包含參數。
  • return_types:返回類型
  • 函數返回一列值, return_types 是該列值的數據類型。
  • 有些功能不須要返回值,這種狀況下 return_types 不是必須的。
  • 函數體:具體的代碼邏輯

【示例】

package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Golang", "yisonli")
fmt.Println(a, b)
}

 

以上示例輸出結果爲:

yisonli Golang

 

4 循環

for循環是一個循環控制結構,能夠執行指定次數的循環。Go語言的For循環有3種形式,具體定義以下:

// 1. 相似 C 語言的 for
for init; condition; post { }
// 2. 相似 C 的 while
for condition { }
// 3. 相似 C 的 for(;;)
for { }

 

  • init: 通常爲賦值表達式,給控制變量賦初值;
  • condition: 關係表達式或邏輯表達式,循環控制條件;
  • post: 通常爲賦值表達式,給控制變量增量或減量。

【示例】

package main
import "fmt"
func main() {
var b int = 7
var a int
numbers := [6]int{1, 2, 3, 5}
/* for 循環 */
for a := 0; a < 5; a++ {
fmt.Printf("a 的值爲: %d\n", a)
}
for a < b {
a++
fmt.Printf("a 的值爲: %d\n", a)
}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
}

 

以上示例輸出結果爲:

a 的值爲: 0
a 的值爲: 1
a 的值爲: 2
a 的值爲: 3
a 的值爲: 4
a 的值爲: 1
a 的值爲: 2
a 的值爲: 3
a 的值爲: 4
a 的值爲: 5
a 的值爲: 6
a 的值爲: 70 位 x 的值 = 11 位 x 的值 = 22 位 x 的值 = 33 位 x 的值 = 54 位 x 的值 = 05 位 x 的值 = 0

 

5 條件語句

 

語句 描述
if 語句 if 語句 由一個布爾表達式後緊跟一個或多個語句組成。
if...else 語句 if 語句 後可使用可選的 else 語句, 
else 語句中的表達式在布爾表達式爲 false 時執行。
if 嵌套語句 你能夠在 if 或 else if 語句中嵌入一個或多個 if 或 else if 語句。
switch 語句 switch 語句用於基於不一樣條件執行不一樣動做。
select 語句 select 語句相似於 switch 語句,可是select會隨機執行一個可運行的case。
若是沒有case可運行,它將阻塞,直到有case可運行。

注意:Go 沒有三目運算符,因此不支持 ?: 形式的條件判斷。

【示例】

package main
import "fmt"
func main() {
/* 局部變量定義 */
var a int = 100;
/* 判斷布爾表達式 */
if a < 20 {
/* 若是條件爲 true 則執行如下語句 */
fmt.Printf("a 小於 20\n" );
} else {
/* 若是條件爲 false 則執行如下語句 */
fmt.Printf("a 不小於 20\n" );
}
fmt.Printf("a 的值爲 : %d\n", a);
}

 

以上示例輸出結果爲:

a 不小於 20
a 的值爲 : 100

 

6 Package包

【包的定義和特性】

  • 包是結構化代碼的一種方式
  • 每一個程序都由包(一般簡稱爲 pkg)的概念組成
  • 每一個 Go 文件都屬於且僅屬於一個包
  • 一個包能夠由許多以 .go 爲擴展名的源文件組成
  • 你必須在源文件中非註釋的第一行指明這個文件屬於哪一個包,如: packagemain
  • 每一個 Go 應用程序都包含一個名爲 main 的包
  • 經過 import 關鍵字能夠將一組包連接在一塊兒,在你的應用中導入後方可以使用

【注意事項】

  1. 若是你導入了一個包卻沒有使用它,則會在構建程序時引起錯誤,如 importedandnotused:os,這正是遵循了 Go 的格言:「沒有沒必要要的代碼!「。
  2. 可見性規則
  • 當標識符(包括常量、變量、類型、函數名、結構字段等等)以一個大寫字母開頭,如:Group1,那麼使用這種形式的標識符的對象就能夠被外部包的 代碼所使用(客戶端程序須要先導入這個包),這被稱爲導出(像面嚮對象語言中的 public);
  • 標識符若是以小寫字母開頭,則對包外是不可見的,可是他們在整個包的內部是可見而且可用的(像面嚮對象語言中的 private )。

7 類型轉換

【普通類型轉換】

  1. type_name(expression)

 

其中type_name 爲類型,expression 爲表達式。

【格式化輸出】
格式化在邏輯中很是經常使用。使用格式化函數,要注意寫法:

  1. fmt.Sprintf(格式化樣式, 參數列表…)
  • 格式化樣式:字符串形式,格式化動詞以%開頭。
  • 參數列表:多個參數以逗號分隔,個數必須與格式化樣式中的個數一一對應,不然運行時會報錯。

【json轉換】
這裏說的json實際上是json格式的string字符串類型,一般json須要轉換成struct結構體、或者轉換成map映射,正向轉換和反向轉換其實會常常用到。
在此,咱們須要藉助Go的標準庫 "encoding/json" 來幫咱們完成轉換的操做了。

// struct或map 轉成 json字符串
str, err := json.Marshal(object)
// json字符串 轉成 struct或map
err := json.Unmarshal([]byte(str), &object)

 

擴展:網上有些Go的開發小夥伴們在抱怨說標準庫的json效率比較低,並且有幾個不錯的開源json庫能夠提高2-3倍的轉換性能。該如何取捨就全憑我的喜愛了,有興趣的小夥伴們能夠自行去深刻了解,本文就再也不展開了。

【示例】

package main
import (
"encoding/json"
"fmt"
)
func main () {
// 1. 普通類型轉換
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum)/float32(count)
fmt.Printf("mean 的值爲: %f\n",mean)
fmt.Println()
// 2. 格式化
title := fmt.Sprintf("已採集%d個藥草, 還須要%d個完成任務。", sum, count)
fmt.Println(title)
fmt.Println()
// 3. json字符串 轉成 struct或map
var jsonBlob = [] byte (`[
{ "Name" : "Platypus" , "Order" : "Monotremata" } ,
{ "Name" : "Quoll" , "Order" : "Dasyuromorphia" }
]`)
type Animal struct {
Name string
Order string
}
var animals [] Animal
err := json.Unmarshal(jsonBlob, &animals)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v\n", animals)
var animalsMap []map[string]interface{}
err1 := json.Unmarshal(jsonBlob, &animalsMap)
if err1 != nil {
fmt.Println("error:", err1)
}
fmt.Printf("%+v\n", animalsMap)
fmt.Println()
// 4. struct或map 轉成 json字符串
type ColorGroup struct {
ID int
Name string
Colors [] string
}
group := ColorGroup {
ID : 1 ,
Name : "Reds" ,
Colors : [] string {"Crimson", "Red", "Ruby", "Maroon"} ,
}
groupStr , err2 := json.Marshal(group)
if err2 != nil {
fmt.Println("error:", err2)
}
fmt.Printf("%s\n", groupStr)
var groupMap = map[string]interface{} {"ID":1,"Name":"Reds","Colors":[] string {"Crimson", "Red", "Ruby", "Maroon"}}
groupStr1 , err3 := json.Marshal(groupMap)
if err3 != nil {
fmt.Println("error:", err3)
}
fmt.Printf("%s\n", groupStr1)
}

 

以上示例輸出結果爲:

mean 的值爲: 3.400000
已採集17個藥草, 還須要5個完成任務。
[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
[map[Name:Platypus Order:Monotremata] map[Name:Quoll Order:Dasyuromorphia]]
{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
{"Colors":["Crimson","Red","Ruby","Maroon"],"ID":1,"Name":"Reds"}

 

5、項目開發 - 必備知識點

根據項目難易程度,須要掌握的技術知識點會有所不一樣;本文會根據項目中經常使用的、基礎的、必須掌握的功能點,逐個進行講解和示例,但願我這些小小的經驗和用心的分享,能真的幫助到你,讓你在Go的世界裏翱翔。

1 BeeGo的執行過程

  • main 函數是入口函數
  • main 引入了一個路由包: _"firstPro/routers"
  • 路由包執行了路由註冊,定位了對應的 Controller: beego.Router("/",&controllers.MainController{})
  • Controller 負責完成具體的業務邏輯

2 路由配置

BeeGo支持的路由配置方式有不少,但正由於多因此短期理解起來會比較難,因此這裏只列出了大體的分類,以及最爲基本的配置方式。先把簡單的理解了,若是我的確實有額外特殊的需求,再另行深刻,也會清晰得多。

【基礎路由】
普通的Get和Post,參見以下代碼:

beego.Get("/",func(ctx *context.Context){
ctx.Output.Body([]byte("this is get"))
})
beego.Post("/save",func(ctx *context.Context){
ctx.Output.Body([]byte("this is post"))
})

 

【RESTful路由】

// 全匹配, 自動找Controller內對應REST的方法
beego.Router("/", &controllers.MainController{})
// 自定義規則, 第三個參數就是用來設置對應 method 到函數名
beego.Router("/api/list",&RestController{},"*:List")
beego.Router("/api/create",&RestController{},"post:Create")

 

【註解路由】
用戶無需在 router 中註冊路由,只須要 Include 相應地 controller,而後在 controller 的 method 方法上面寫上 router 註釋( // @router)就能夠了。

func init() {
ns :=
beego.NewNamespace("/v1",
beego.NSNamespace("/customer",
beego.NSInclude(
&controllers.CustomerController{},
&controllers.CustomerCookieCheckerController{},
),
),
beego.NSNamespace("/cms",
beego.NSInclude(
&controllers.CMSController{},
),
),
)
beego.AddNamespace(ns)
}

 

注意:爲了生成swagger自動化文檔,只支持 Namespace+Include 寫法的解析,其餘寫法函數不會自動解析,並且只支持二級解析(一級版本號,二級分別表示應用模塊)

3 請求數據處理

【參數獲取】
咱們常常須要獲取用戶傳遞的數據,包括 Get、POST 等方式的請求,beego 裏面會自動解析這些數據,你能夠經過以下方式獲取數據:

GetString(key string) string
GetStrings(key string) []string
GetInt(key string) (int64, error)
GetBool(key string) (bool, error)
GetFloat(key string) (float64, error)

 

【解析到Struct】
適用於Form表單提交的形式,使用方法也很簡單,先定義個結構體,而後調用 this.ParseForm(結構體指針) 便可。

注意:

  • 定義 struct 時,字段名後若是有 form 這個 tag,則會以把 form 表單裏的 name 和 tag 的名稱同樣的字段賦值給這個字段,不然就會把 form 表單裏與字段名同樣的表單內容賦值給這個字段。
  • 調用 ParseForm 這個方法的時候,傳入的參數必須爲一個 struct 的指針,不然對 struct 的賦值不會成功並返回 xx must be a struct pointer 的錯誤。
  • 若是要忽略一個字段,有兩種辦法,一是:字段名小寫開頭,二是:form 標籤的值設置爲 -

【原始請求數據】

  1. 在配置文件 app.conf 裏設置 copyrequestbody=true
  2. 在 Controller 中使用 this.Ctx.Input.RequestBody 獲取

更多其餘的 request 的信息,用戶能夠經過 this.Ctx.Request 獲取

【json參數返回】
在 Controller 中給 this.Data["json"] 賦值, 而後調用 this.ServeJSON() 便可

【示例】

package controllers
import (
"github.com/astaxie/beego"
"fmt"
)
type MainController struct {
beego.Controller
}
type user struct {
Id int `form:"-"`
Name interface{} `form:"username"`
Age int `form:"age"`
Email string
}
func (this *MainController) Post() {
email := this.GetString("Email")
fmt.Println(email)
body := this.Ctx.Input.RequestBody
fmt.Printf("%s\n", string(body))
u := user{}
if err := this.ParseForm(&u); err != nil {
//handle error
this.Data["json"] = map[string]interface{}{"code":-1, "message":"ParseForm fail", "result":err}
} else {
fmt.Printf("%+v\n", u)
this.Data["json"] = map[string]interface{}{"code":0, "message":"ok"}
}
this.ServeJSON()
this.StopRun()
}

 

以上示例控制檯結果爲:

// 模擬請求:curl -X POST -d "username=yisonli&age=18&Email=yisonli@vip.qq.com" "http://127.0.0.1:8080"
yisonli@vip.qq.com
username=yisonli&age=18&Email=yisonli@vip.qq.com
{Id:0 Name:yisonli Age:18 Email:yisonli@vip.qq.com}

 

4 數據庫

使用數據庫前需先裝好數據庫驅動,其實只要執行 goget-u 指令便可。
已支持數據庫驅動:

【鏈接數據庫】

  1. 將你須要使用的 driver 加入 import 中
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
)

 

按我的項目需求來選擇便可,本文將以mysql爲例進行演示和說明

  1. 以本身實際的數據庫配置,初始化並鏈接數據庫
orm.RegisterDriver("mysql", orm.DRMySQL)
orm.RegisterDataBase("default", "mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8&loc=Local")

 

注:

  1. loc=Local 是將操做數據庫的時區,設置成跟本地時區同樣。
  2. 若是你想像我同樣,在本機運行mysql的服務端,而你又剛好裝了Docker,那麼恭喜你,只須要一條指令啓動docker鏡像便可:
    docker run--name mysqlserver-e MYSQL_ROOT_PASSWORD=123456-d-i-p3306:3306mysql:5.7

【原生CRUD】

package controllers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
_ "github.com/go-sql-driver/mysql"
"fmt"
)
type TestController struct {
beego.Controller
}
func (this *TestController) Get() {
orm.RegisterDriver("mysql", orm.DRMySQL)
orm.RegisterDataBase("default", "mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8&loc=Local")
orm.Debug = true //是否開啓sql調試,開啓時能夠打印全部執行的sql語句,不設置時默認爲false
o := orm.NewOrm()
o.Using("default") //若是鏈接了多個數據庫,此方法能夠用來切換,不設置時默認是default的DataBase
var maps []orm.Params
num1, err1 := o.Raw("SELECT * FROM users").Values(&maps)
if num1 > 0 && err1 == nil {
for _,term := range maps{
fmt.Printf("%+v\n",term)
}
}
res2, err2 := o.Raw("INSERT INTO `users` (`name`, `age`, `email`) VALUES ('Test', 27, 'test@gmail.com')").Exec();
if err2 == nil {
num2, _ := res2.RowsAffected()
fmt.Println("mysql row affected nums: ", num2)
}
res3, err3 := o.Raw("UPDATE `users` SET `age`=18 WHERE `name`='Test'").Exec()
if err3 == nil {
num3, _ := res3.RowsAffected()
fmt.Println("mysql row affected nums: ", num3)
}
res4, err4 := o.Raw("DELETE FROM `users` WHERE `name`='Test'").Exec()
if err4 == nil {
num4, _ := res4.RowsAffected()
fmt.Println("mysql row affected nums: ", num4)
}
this.Data["json"] = map[string]interface{}{"code":0, "message":"ok"}
this.ServeJSON()
}

 

運行結果:

[ORM]2019/07/17 15:30:51 -[Queries/default] - [ OK / db.Query / 0.9ms] - [SELECT * FROM users]
map[email:Lily@qq.com id:1 name:Lily age:18]
map[id:2 name:Lucy age:20 email:Lucy@gmail.com]
map[email:Honey@foxmail.com id:3 name:Honey age:30]
[ORM]2019/07/17 15:30:51 -[Queries/default] - [ OK / db.Exec / 6.9ms] - [INSERT INTO `users` (`name`, `age`, `email`) VALUES ('Test', 27, 'test@gmail.com')]
mysql row affected nums: 1
[ORM]2019/07/17 15:30:51 -[Queries/default] - [ OK / db.Exec / 3.1ms] - [UPDATE `users` SET `age`=18 WHERE `name`='Test']
mysql row affected nums: 1
[ORM]2019/07/17 15:30:51 -[Queries/default] - [ OK / db.Exec / 6.4ms] - [DELETE FROM `users` WHERE `name`='Test']
mysql row affected nums: 1
2019/07/17 15:30:51.054 [D] [server.go:2741] | 127.0.0.1| 200 | 28.352094ms| match| GET /test/ r:/test

 

【ORM】
ORM是一個比較強大的功能,他可讓咱們的表結構,經過Struct定義的方式表現&關聯起來,方便使用。
目前該框架仍處於開發階段,讓咱們來看看官網的示例吧:

models.go

package main
import (
"github.com/astaxie/beego/orm"
)
type User struct {
Id int
Name string
Profile *Profile `orm:"rel(one)"` // OneToOne relation
Post []*Post `orm:"reverse(many)"` // 設置一對多的反向關係
}
type Profile struct {
Id int
Age int16
User *User `orm:"reverse(one)"` // 設置一對一反向關係(可選)
}
type Post struct {
Id int
Title string
User *User `orm:"rel(fk)"` //設置一對多關係
Tags []*Tag `orm:"rel(m2m)"`
}
type Tag struct {
Id int
Name string
Posts []*Post `orm:"reverse(many)"`
}
func init() {
// 須要在init中註冊定義的model
orm.RegisterModel(new(User), new(Post), new(Profile), new(Tag))
}

 

main.go

package main
import (
"fmt"
"github.com/astaxie/beego/orm"
_ "github.com/go-sql-driver/mysql"
)
func init() {
orm.RegisterDriver("mysql", orm.DRMySQL)
orm.RegisterDataBase("default", "mysql", "root:root@/orm_test?charset=utf8")
}
func main() {
o := orm.NewOrm()
o.Using("default") // 默認使用 default,你能夠指定爲其餘數據庫
profile := new(Profile)
profile.Age = 30
user := new(User)
user.Profile = profile
user.Name = "slene"
fmt.Println(o.Insert(profile))
fmt.Println(o.Insert(user))
}

 

BeeGo還封裝了不少高級的查詢方法,有興趣的小夥伴能夠額外深刻了解一下;由於篇幅有限,這裏就再也不展開了。

5 Http請求

httplib 庫主要用來模擬客戶端發送 HTTP 請求,相似於 Curl 工具,支持 JQuery 相似的鏈式操做。

// 首先導入包
import (
"github.com/astaxie/beego/httplib"
)
// 而後初始化請求方法,返回對象
req := httplib.Get("http://yyeer.com/")
// 超時時間、Header頭均可以按需設置
req.SetTimeout(100 * time.Second, 30 * time.Second)
req.Header("Host","yyeer.com")
// 而後咱們就能夠獲取數據了
str, err := req.String()
if err != nil {
fmt.Println(err)
}
fmt.Println(str)

 

【支持的方法對象】

  • Get(url string)
  • Post(url string)
  • Put(url string)
  • Delete(url string)
  • Head(url string)

【獲取返回結果】

  • 返回 Response 對象, req.Response() 方法
  • 這個是 http.Response 對象,用戶能夠本身讀取 body 的數據等。
  • 返回 bytes, req.Bytes() 方法
  • 返回 string, req.String() 方法
  • 保存爲文件, req.ToFile(filename) 方法
  • 解析爲 JSON 結構, req.ToJSON(&result) 方法
  • 解析爲 XML 結構, req.ToXml(&result) 方法

6 Swagger文檔

BeeGo框架內自動集成了swagger模塊,要使得文檔工做,你須要作幾個事情,

  1. 第一開啓應用內文檔開關,在配置文件中設置: EnableDocs=true,
  2. 而後在你的 main.go 函數中引入 _"beeapi/docs"(beego 1.7.0 以後版本不須要添加該引用)。
  3. 這樣你就已經內置了 docs 在你的 API 應用中,而後你就使用 bee run-gendoc=true-downdoc=true, 讓咱們的 API 應用跑起來
  • -gendoc=true 表示每次自動化的 build 文檔,
  • -downdoc=true 就會自動的下載 swagger 文檔查看器
  1. 最後,router 和 controller 內的配置和註釋按照規範編寫,便可

【全局註釋】
必須設置在 routers/router.go 中,文件的註釋,最頂部:

// @APIVersion 1.0.0
// @Title mobile API
// @Description mobile has every tool to get any job done, so codename for the new mobile APIs.
// @Contact astaxie@gmail.com
package routers

 

全局的註釋如上所示,是顯示給全局應用的設置信息,有以下這些設置

  • @APIVersion
  • @Title
  • @Description
  • @Contact
  • @TermsOfServiceUrl
  • @License
  • @LicenseUrl

【應用註釋】

// CMS API
type CMSController struct {
beego.Controller
}
// @Title getStaticBlock
// @Description get all the staticblock by key
// @Param key path string true "The email for login"
// @Success 200 {object} models.ZDTCustomer.Customer
// @Failure 400 Invalid email supplied
// @Failure 404 User not found
// @router /staticblock/:key [get]
func (c *CMSController) StaticBlock() {
}

 

首先是 CMSController 定義上面的註釋,這個是用來顯示這個模塊的做用。

接下來就是每個函數上面的註釋,這裏列出來支持的各類註釋:

  • @Title
  • 這個 API 所表達的含義,是一個文本,空格以後的內容所有解析爲 title
  • @Description
  • 這個 API 詳細的描述,是一個文本,空格以後的內容所有解析爲 Description
  • @Param
  • 參數,表示須要傳遞到服務器端的參數,有五列參數,使用空格或者 tab 分割,五個分別表示的含義以下
  • 參數名
  • 參數類型,能夠有的值是 formData、 query、 path、 body、 header,formData 表示是 post 請求的數據,query 表示帶在 url 以後的參數,path 表示請求路徑上得參數,例如上面例子裏面的 key,body 表示是一個 raw 數據請求,header 表示帶在 header 信息中得參數。
  • 參數類型
  • 是否必須
  • 註釋
  • @Success
  • 成功返回給客戶端的信息,三個參數,三個參數必須經過空格分隔
    • 第一個是 status code。
    • 第二個參數是返回的類型,必須使用 {} 包含,
    • 第三個是返回的對象或者字符串信息,若是是 {object} 類型,那麼 bee 工具在生成 docs 的時候會掃描對應的對象。
  • @Failure
  • 失敗返回的信息,包含兩個參數,使用空格分隔
    • 第一個表示 status code,
    • 第二個表示錯誤信息
  • @router
  • 路由信息,包含兩個參數,使用空格分隔,
    • 第一個是請求的路由地址,支持正則和自定義路由,和以前的路由規則同樣,
    • 第二個參數是支持的請求方法,放在 [] 之中,若是有多個方法,那麼使用 , 分隔。

7 日誌

【常規使用】
首先引入包:

import (
"github.com/astaxie/beego/logs"
)

 

而後添加輸出引擎:

  • 第一個參數是引擎名:
  • logs.SetLogger("console")
  • 第二個參數,用來表示配置信息:
  1. logs.SetLogger(logs.AdapterFile,{"filename":"project.log","level":7,"maxlines":0,"maxsize":0,"daily":true,"maxdays":10,"color":true}`)

log 支持同時輸出到多個引擎,包括:console、file、conn、smtp、es、multifile

使用方式:

  1. beego.Emergency("this is emergency")
  2. beego.Alert("this is alert")
  3. beego.Critical("this is critical")
  4. beego.Error("this is error")
  5. beego.Warning("this is warning")
  6. beego.Notice("this is notice")
  7. beego.Informational("this is informational")
  8. beego.Debug("this is debug")

【自定義格式】
若是框架自帶的日誌功能還沒法知足你的需求,那可能就得麻煩一點,自定義日誌格式。

操做流程大體爲:

  1. 打開要寫入的文件,不存在則建立, os.OpenFile
  2. 建立一個自定義的日誌對象 log.New
  3. 使用時按所需格式輸出日誌 Printf
File, err := os.OpenFile(logdir, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if nil != err {
log.Fatal(err)
}
MyLog = log.New(io.MultiWriter(File,os.Stderr), "", 0)
MyLog.Printf("本身定義的格式... %s\n", 本身定義的參數, fmt.Sprintf(formating, args...))

 

實際使用時, 能夠把 MyLog.Printf 封裝成一個全局方法,這樣整個項目裏均可使用。

8 加解密

加解密在多方對接的時候,常常會用到,因此稍微瞭解一點也是必要的。
由於這塊使用的人比較多,因此只要肯稍微花點時間,在網上都是能夠找到答案的。

【MD5】
MD5主要是用做簽名,具體生成方法以下:

import (
"crypto/md5"
"encoding/hex"
)
func MyMd5(Str string, Key string) string {
md5ctx := md5.New()
md5ctx.Write([]byte(Str + Key))
return hex.EncodeToString(md5ctx.Sum(nil))
}

 

【AES】
AES主要是用做加解密,還分好幾種不一樣的模式如:ECB、CBC、CFB等。
網上找到一份看起來還不錯的《AES的加解密實現》,原諒個人小偷懶(尚未在實際項目驗證過),God Bless。

其餘還有SHA、DES、RSA等加解密方式,具體就得根據各小夥伴不一樣項目所需了。
Go Go Go !去吧,你能夠的!

9 緩存使用

// 首先引入包:
import (
"github.com/astaxie/beego/cache"
)
// 而後初始化一個全局變量對象:
bm, err := cache.NewCache("memory", `{"interval":60}`)
// 而後咱們就可使用bm增刪改緩存:
bm.Put("astaxie", 1, 10*time.Second)
bm.Get("astaxie")
bm.IsExist("astaxie")
bm.Delete("astaxie")

 

【配置說明】

  • memory
  • 配置信息以下所示,配置的信息表示 GC 的時間,表示每一個 60s 會進行一次過時清理:
  • {"interval":60}
  • file
  • 配置信息以下所示,配置 CachePath 表示緩存的文件目錄,FileSuffix 表示文件後綴,DirectoryLevel 表示目錄層級,EmbedExpiry 表示過時設置
  • {"CachePath":"./cache","FileSuffix":".cache","DirectoryLevel":"2","EmbedExpiry":"120"}
  • redis
  • 配置信息以下所示,redis 採用了庫 redigo:
  • {"key":"collectionName","conn":":6039","dbNum":"0","password":"thePassWord"}
    • key: Redis collection 的名稱
    • conn: Redis 鏈接信息
    • dbNum: 鏈接 Redis 時的 DB 編號. 默認是0.
    • password: 用於鏈接有密碼的 Redis 服務器.
  • memcache
  • 配置信息以下所示,memcache 採用了 vitess的庫,表示 memcache 的鏈接地址:
  • {"conn":"127.0.0.1:11211"}

【示例】

import (
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/cache"
_ "github.com/astaxie/beego/cache/redis"
"time"
)
func (this *TestController) Test() {
bm, err := cache.NewCache("redis", `{"key":"127.0.0.1","conn":":6379","dbNum":"0","password":""}`)
if err != nil {
fmt.Println(err)
}
fmt.Printf("bm = %+v\n",bm)
err1 := bm.Put("yisonli", 1, 10*time.Second)
if err1 != nil {
fmt.Println(err1)
}
redisValue := bm.Get("yisonli")
fmt.Printf("redisValue = %s\n",redisValue)
this.Ctx.Output.Body([]byte("OK"))
}

 

執行效果:

bm = &{p:0xc000210240 conninfo::6379 dbNum:0 key:127.0.0.1 password: maxIdle:3}
redisValue = 1

 

注:

  1. 示例中使用了redis做爲緩存,若是不依賴beego的cache模塊,redis還有不少很好用的數據類型和功能方法,如:Hash散列、List列表、Set集合、SortedSet有序集合。
  2. 本機啓動redis服務,和上文啓動mysql相似,只須要一條指令啓動docker鏡像便可:
    docker run--namelocal-redis-p6379:6379-v $PWD/data:/data-d redis redis-server--appendonly yes

10 Session

beego 內置了 session 模塊,使用 session 至關方便。

方式一、 在 main 入口函數中設置:
beego.BConfig.WebConfig.Session.SessionOn=true

方式二、 經過配置文件配置:
sessionon=true

session默認採用 memory 的方式進行存儲,若是須要更換別的引擎(以redis爲例),須要修改&設置以下配置:

beego.BConfig.WebConfig.Session.SessionProvider = "redis"
beego.BConfig.WebConfig.Session.SessionProviderConfig = "127.0.0.1:6379"

 

【示例】

func (this *MainController) Get() {
v := this.GetSession("asta")
if v == nil {
this.SetSession("asta", int(1))
this.Data["num"] = 0
} else {
this.SetSession("asta", v.(int)+1)
this.Data["num"] = v.(int)
}
this.Data["Website"] = "beego.me"
this.Data["Email"] = "astaxie@gmail.com"
fmt.Printf("%+v\n", this.Data)
this.TplName = "index.tpl"
}

 

運行後,屢次訪問首頁的debug輸出結果:

2019/07/17 20:25:20.235 [I] [asm_amd64.s:1333] http server Running on http://:8080
map[RouterPattern:/ num:0 Website:beego.me Email:astaxie@gmail.com]
2019/07/17 20:25:25.141 [D] [server.go:2741] | 127.0.0.1| 200 | 4.63737ms| match| GET / r:/
map[num:1 Website:beego.me Email:astaxie@gmail.com RouterPattern:/]
2019/07/17 20:25:46.021 [D] [server.go:2741] | 127.0.0.1| 200 | 5.116566ms| match| GET / r:/
map[RouterPattern:/ num:2 Website:beego.me Email:astaxie@gmail.com]
2019/07/17 20:26:00.084 [D] [server.go:2741] | 127.0.0.1| 200 | 1.573909ms| match| GET / r:/
map[RouterPattern:/ num:3 Website:beego.me Email:astaxie@gmail.com]
2019/07/17 20:26:12.470 [D] [server.go:2741] | 127.0.0.1| 200 | 2.652028ms| match| GET / r:/

 

掌握了以上那麼多技能,如今,你對項目的開發有多少把握了呢?
其實,基本已經差很少了,剩下的就是動手實踐了。

古人學問無遺力,少壯工夫老始成。
紙上得來終覺淺,絕知此事要躬行。

我是Yison,若是我有幫助到你,也請你幫助一下我,隨手一個贊對你來講無足輕重,但倒是使我不斷前行的動力!

相關文章
相關標籤/搜索