Software engineering notes

Go Frameworks

Beego

上手資源

安裝

按照官網指令即可

Routers

基本語法

beego.Router("/api/:id", &controllers.RController{})
beego.Router("/api/list", &RestController{}, "*:ListFood")  # * = ANY, 可替換為 post / put
beego.Router("/api/list", &RestController{}, "get,post:ApiFunc")  # 指定兩個 Http method 到同一個 func
beego.Router("/api/list", &RestController{}, "get:GetFunc;post:PostFunc")  # 指定到不同 Http method 即不同的 Func
beego.AutoRouter("&controllers.ObjectController{}) # 自動 Match /object/blog/2013/09/12 -> ObjectController 的 blog 方法,參數: map[0: 2013 1:09 2:12]

Match

404

beego.ErrorHandler("404", page_not_found)

func page_not_found(rw http.ResponseWriter, r *http.Request) {
    rw.Write([]byte("404"))
}

match url path 直接在 router 層輸出

import "github.com/astaxie/beego/context"

beego.Get("/gl", func(ctx *context.Context) {
    ctx.Output.Body([]byte("ok"))
})

Controllers

基本語法

輸出字串

this.Ctx.WriteString("hello")
this.Ctx.Output.Body([]byte("ok"))

產生 view

this.Data["show"] = "Test"
this.TplName = "user/index.tpl"

改變輸出的 status code

this.Ctx.Output.SetStatus(400)

取得 parameters 變數

取得 form 變數

this.Ctx.Input.Param("user_id")    // 注意!有 `:`

取得 router 對應的變數 (url params mapping)

router:
    beego.Router("/users/:user_id/", &controllers.UserController{}, "post:update")
this.Ctx.Input.Param(":user_id")    // 注意!有 `:`

讓 struct int 參數支援選填

因為 int 初始值為 0, 所以這裡用 pointer 來支援 nil, 再額外判斷如果有值再放到 struct 裡

type AddReq struct {
    Gender *int
}

req := AddReq{}
age, err := this.GetInt("age")
if err == nil {
    req.Age = &age
}

log.Println(*req.Age)

conf

取得變數值

單一值

httpport = 8080

beego.AppConfig.String("httpport") # dev

Section 值/陣列

[demo]
peers = one;two;three

beego.AppConfig.Strings("demo::peers") # [one two three]

根據環境不同讀取不同的設定檔

app.conf

runmode = dev
sessionon = true            # 啟用 session, 預設使用 mem
copyrequestbody = true      # 要打開,否則 this.Ctx.Input.RequestBody 抓不到資料

[dev]
host = 127.0.0.1

[prod]
host = 137.111.120.179

取變數時 :

beego.AppConfig.String("runmode")

log

在 beego 目錄下產生 log file, 更多參數請參考官方文件

beego.SetLogger(logs.AdapterFile, `{"filename":"project.log"}`)
beego.Run()

// logs.SetLogger(logs.AdapterMultiFile, ``{"filename":"test.log","separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]}``)

ORM

Beego orm 相當地方便,雖然 beego orm 是包在 beego 裡面,但是它分的相當的乾淨,你可以在任何 project 上引入, 以下是使用 MySQL 的 example :

import (
    "fmt"

    "github.com/astaxie/beego/orm"
    _ "github.com/go-sql-driver/mysql"                  // 一定要 import
)

// 這是你的 Model, 用來跟 User Table Mapping 的,欄位名的規則是: user_id (mysql column name) => UserId (struct field)
type User struct {
    Id     int
    UserId string
    Email  string
    Name   string
}

func init() {
    orm.RegisterModel(new(User))
}

func main() {
    orm.RegisterDataBase("default", "mysql", "username:password@/your_db_name?charset=utf8")        // 第一個一定要是 default
    orm.SetMaxIdleConns("default", 5)
    orm.SetMaxOpenConns("default", 30)
    o := orm.NewOrm()
    user := User{UserId: "2c024jka-cc06-4fc1-8fd3-f1c72dw22dac"}            // 相當於是 WHERE 條件
    err := o.Read(&user, "user_id")
    if err == orm.ErrNoRows {
        fmt.Println("Not found")
    } else if err == orm.ErrMissPK {
        fmt.Println("Missed PK key")
    } else {
        fmt.Println(user.Email)
    }
}

WHERE 多項條件

user := User{UserId: "2c024jka-cc06-4fc1-8fd3-f1c72dw22dac", Name: "Jex"}
err := o.Read(&user, "user_id", "name")

切換到另一個 DB

err = orm.Using("another_db")

SELECT 取一筆 record (limit: 1)

var users []orm.Params
num, err := o.QueryTable(new(model.User)).Filter("user_id", user_id).OrderBy("-created_at").Limit(1).Values(&users)

var d Device
err := o.QueryTable(new(Device)).Filter("did", "A123").One(&d)

user := User{UserId: "2c024jka-cc06-4fc1-8fd3-f1c72dw22dac"}
err := o.Read(&user, "user_id")

Read vs Values : Read 取不到值時會擲 error, Values 則不會

Count

num, err = o.QueryTable(new(model.User)).Filter("user_id", user_id).Count()

Update 特定欄位

affected_num, err := o.QueryTable(new(model.User)).Filter("user_id", user_id).Update(orm.Params{
    "name": name,
})

Update 特定欄位

o := orm.NewOrm()
user.Name = "Jex"
user.Address = "Taiwan ... "
o.Update(user, "name", "address")

Raw Query

_, err = j.Service.MySQL.Raw("UPDATE user SET name = ? WHERE uid = ?", 'Bob', 'uid00001').Exec()