編程基礎 0003_Web_beego開發

Web 開發之 Beego

使用 go get 安裝 bee 工具與 beego

使用 bee 工具初始化 Beego 項目

  • $GOPATH/src 目錄下執行 bee create myapp

使用 bee 工具熱編譯 Beego 項目

  • $GOPATH/src/myapp 目錄下執行 bee start myapp
// hello world
package main

import (
    "github.com/astaxie/beego"
)
type HomeController struct {
    beego.Controller
}
// 注意Get首字母大寫。要不會報method not allow
func (this *HomeController) Get() {
    this.Ctx.WriteString("Hello World")
}
func main() {
    beego.Router("/",&HomeController)
    beego.Run()
}

go http

三個包 io/log/net/http

package main

import (
    "io"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/",sayHello)
    err:=http.ListenAndServe(":8080",nil)
    if err!=nil {
        log.Fatal(err)
    }
}
func sayHello(w http.ResponseWriter,r *http.Request) {
   io.WriteString(w,"Hello world,this is is version 1.")
}

ListenAdnServe第二個參數添加 handler

package main

import (
    "io"
    "log"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    mux.Handle("/", &myHandler{})
    mux.HandleFunc("/hello",SayHelloV2) //處理func
    err := http.ListenAndServe("0.0.0.0:8080", mux)

    if err!=nil {
        log.Fatal(err)
    }
}

type myHandler struct{}

func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    io.WriteString(w, "URL:"+r.URL.String())
}
// 同樣mux也可以HandleFunc

func SayHelloV2(w http.ResponseWriter,r *http.Request)  {
    io.WriteString(w,"Hello world, this is version No.2.")
}

更底層的寫處理 HttpServer

package main

import (
    "io"
    "log"
    "net/http"
    "time"
)
//手動處理路由,在handler中只有一個ServerHTTP

var mx map[string]func(w http.ResponseWriter,r *http.Request)

func main()  {
    server:=http.Server{
        Addr:":8080",
        Handler: &myHandler1{},
        ReadHeaderTimeout:5*time.Second,
    }
    //路由註冊
    mx = make(map[string]func(w http.ResponseWriter,r *http.Request))
    mx["/hello"] =sayHello
    mx["/saybye"] = sayBye
    err:=server.ListenAndServe()
    if err!=nil {
        log.Fatal(err)
    }
}

type myHandler1 struct{}

func (*myHandler1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    //io.WriteString(w, "URL:"+r.URL.String())
    //這裏來做路由轉發
    if h,ok:=mx[r.URL.String()];ok{
        h(w,r)
        return
    }

    io.WriteString(w, "妹找到-->URL:"+r.URL.String())
}

func sayHello (w http.ResponseWriter, r *http.Request)  {
    io.WriteString(w,"Hello world, this is version no 3")
}

func sayBye(w http.ResponseWriter, r *http.Request)  {
    io.WriteString(w,"Bye bye, this is version no 3")
}

對於 mux 的擴展靜態服務

func main() {
    mux := http.NewServeMux()
    mux.Handle("/", &myHandler{})
    mux.HandleFunc("/hello", SayHelloV2)
    //創建靜態服務
    wd, err := os.Getwd()
    if err != nil {
        log.Fatal(err)
    }
    mux.Handle("/static/",
        http.StripPrefix("/static/", http.FileServer(http.Dir(wd))))
    err = http.ListenAndServe("0.0.0.0:8080", mux)
    if err != nil {
        log.Fatal(err)
    }
}

bee 命令的使用

文檔

  • 新建一個 web 項目 bee new myproject
  • 通過 api 命令可是用來創建 api 應用 bee api apiproject,其目錄結構中我們可以看出少了 static 和 views 目錄,多了一個 test 模塊,用來做單元測試
  • bee run命令是監控 beego 的項目,通過 fsnotify 監控文件系統。但是注意該命令必須在$GOPATH/src/appname下執行
  • bee pack pack 目錄用來發布應用的時候打包,會把項目打包成 zip 包,這樣我們部署的時候直接把打包之後的項目上傳,解壓就可以部署了
  • bee version 查看 bee beego 和 go 的版本
  • bee generate 命令,用來自動化生成代碼的,包含了從數據庫一鍵生成 model,還包含了 scaffold

beego 配置管理

conf/app.conf 怎麼獲取呢?

package controllers

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

type MainController struct {
    beego.Controller
}

func (c *MainController) Get() {
    // c.Data["Website"] = "beego.me"
    // c.Data["Email"] = "astaxie@gmail.com"
    // c.TplName = "index.tpl"
    c.Ctx.WriteString("appName:"+beego.AppConfig.String("appname")+
    "\nhttpport"+beego.AppConfig.String("httpport")+
    "\nrunmode"+beego.Appconfig.String("runmode"))
    // 系統默認參數方式 貌似不帶這種方式了
   /*  hp:=strcovItoa(beego.HttpPort)
    c.Ctx.WriteString("appName:"+beego.AppName+
    "\nhttpport"+hp+
    "\nrunmode"+beego.RunMode) */

    //    日誌 及日誌級別
    /*
    LevelEmergency = iota // 緊急級別
        LevelAlert                   // 報警級別
        LevelCritical                // 嚴重錯誤級別
        LevelError                   // 錯誤級別
        LevelWarning              // 警告級別
        LevelNotice                 // 注意級別
        LevelInformational       // 報告級別
        LevelDebug                 // 除錯級別
    */
    log:=logs.NewLogger(10000)
    log.SetLevel(logs.LevelDebug)

}

模板

package controllers

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

type MainController struct {
    beego.Controller
}

func (c *MainController) Get() {
    c.Data["name"] = "name"
    // 模板中的條件判斷
    c.Data["TrueCond"] = true
    c.Data["FalseCond"] = false
    // 打印一個結構
    type u struct{
        Name string
        age int
        Sex string
    }
    user:=&u{
        Name:"Joe",
        Age:20,
        Sex:"Male"
    }
    c.Data["User"] = user
    // 循環輸出
    nums:=[]int{1,2,3,4,5,6,7,8,9,0}
    c.Data["Nums"] = nums
    // 給模板變量賦值
    c.Data["TplVar"] = "hey  guys"
    // 內置模板函數的功能
    c.Data["Html"] = "<div>Hello Beego</div>"
    c.Data["Pipe"] = "<div>Hello Beego</div>"
}
<!-- tpl -->
<div>
  <!-- 條件判斷 判斷值只能是True 或 false不能用表達式 -->
  {{if .TrueCond}} true condition content {{end}}
</div>
<div>
  <!-- 條件判斷 判斷值只能是True 或 false不能用表達式 -->
  {{if .FalseCond}} {{else}} false condition content {{end}}
</div>
<div>
  <!-- 結構顯示 -->
  {{.User.Name}} {{.User.Age}} {{.User.Sex}}
  <!-- 嵌套輸出 -->
  {{with .User}} {{.Name}} {{.Age}} {{.Sex}} {{end}}
</div>
<div>
  <!-- 單數組 只輸入一個.就可以了 -->
  {{range .Nums}} {{.}} {{end}}
  <!-- 如果是對象的話,因爲兼顧了with功能,所以只寫對象屬性就可以了`.屬性名` -->
</div>
<div>
  <!-- 模板變量使用$定義 -->
  {{$tplVar = .TplVar}} ==> {{$tplVar}}
</div>
<div>
  {{.html}}
  <!-- 模板函數 -->
  {{str2Html .html}}
</div>
<!-- 編碼 htmlquote函數-->
{{.Pipe | htmlquote}}

定義模板嵌套

{{define "test"}} 定義的模板塊 {{end}}

<html>
  <head></head>
  <body>
    {{template "test"}}
  </body>
</html>

實戰課 models 的建立

在 models 目錄下創建 models.go 文件(別搞混了,和我們之前的那個 xorm 不是一個哈)

// controllers/default.go
package controllers
import (
    "github.com/astaxie/beego"
)
type MainController struct {
    beego.Controller
}

func (c *MainController) Get() {
    c.TplName = "home.html"
}

// models/models.go 注意orm中後面是帶雙引號

type Category struct {
    Id              int64
    Title           string
    Created         time.Time `orm:"index;auto_now_add;type(datetime)"`
    Views           int64     `orm:"index"`
    TopicTime       time.Time `orm:"index;auto_now_add;type(datetime)"`
    TopicCount      int64
    TopicLastUserId int64
}

type Topic struct {
    Id              int64
    Uid             int64
    Title           string
    Content         string `orm:size(5000)`
    Attachment      string
    Created         time.Time `orm:"index;auto_now_add;type(datetime)"`
    Updated         time.Time `orm:"index;auto_now_add;type(datetime)"`
    Views           int64     `orm:"index"`
    Author          string
    ReplyTime       time.Time
    ReplyCount      int64
    ReplyLastUserId int64
}

func RegisterDB() {
    if !com.IsExist(_DB_NAME) {
        os.MkdirAll(path.Dir(_DB_NAME), os.ModePerm)
        os.Create(_DB_NAME)
    }
    orm.RegisterModel(new(Category), new(Topic))
    orm.RegisterDriver(_SQLITE3_DERIVER, orm.DRSqlite)
    //    強制要求必須有一個數據庫叫default 不管你有幾個數據庫 最大連接數10
    orm.RegisterDataBase("default", _SQLITE3_DERIVER, _DB_NAME, 10)
}


// main.go
package main
import (
    "beeapp/controllers"
    "beeapp/models"
    _ "beeapp/routers"
    "github.com/astaxie/beego"
    "github.com/astaxie/beego/orm"
)
func init()  {
    models.RegisterDB()
}
func main() {
    orm.Debug = true //調度模式
    //自動建表
    orm.RunSyncdb("default",false,true)
    beego.Router("/",&controllers.MainController{})
    beego.Run()
}

登錄及分類管理

拆分模板,將上例中的模板內容拆分成不同塊以備後續開發複用使用。如將網頁頭問提取出來命名爲T_header.tpl

{{define "header"}}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
    />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <link rel="shortcut icon" href="/static/img/favicon.ico" />
    <link rel="stylesheet" href="/static/css/bootstrap.min.css" />
    <title>首頁</title>
  </head>
  <body style="padding-top: 70px">
    {{end}}
  </body>
</html>

在 home.html 模板中刪除對應的內容,並改爲 beego 模板引入語法;定義模板要用{{define "header"}} {{end}}

注意最後面的那個.,如果在模板中使用使用變量則需要這個點,如果是純靜態資源可以省略

{{template "header" .}}
<!-- 模板輸出變量{{.變量名}} -->

這裏使用 glide 來做包管理工具,也會碰到 go get golang.org/x/不能下載問題,可以使用添加映像來管理;這裏只添加了 tools net sys
~~坑已經狠狠的踩過了,千萬不要用 glide~~ 還有個坑就是 terminal 翻牆

glide mirror set https://golang.org/x/mobile https://github.com/golang/mobile --vcs git
glide mirror set https://golang.org/x/crypto https://github.com/golang/crypto --vcs git
glide mirror set https://golang.org/x/net https://github.com/golang/net --vcs git
glide mirror set https://golang.org/x/tools https://github.com/golang/tools --vcs git
glide mirror set https://golang.org/x/text https://github.com/golang/text --vcs git
glide mirror set https://golang.org/x/image https://github.com/golang/image --vcs git
glide mirror set https://golang.org/x/sys https://github.com/golang/sys --vcs git

別改一個標題請使用 dep

github,遇到 golang.org 下載不了問題看這裏 。 基本上就是解決 terminal 下科學上網問題

cate 列表業務

<!-- category模板 -->
{{template "header" .}} {{template "navbar" .}}
<div class="container">
  <form class="form-inline" action="/cate" method="get">
    <div class="form-group">
      <label for="cate_name">類別名稱</label>
      <input
        type="text"
        style="width: 260px"
        class="form-control"
        id="cate_name"
        name="catename"
        placeholder="Please enter category name"
      />
      <input type="hidden" name="op" value="add" />
    </div>
    <button type="submit" class="btn btn-default">添加</button>
  </form>
  <table class="table table-striped">
    <thead>
      <th>#</th>
      <th>名稱</th>
      <th>文章數</th>
      <th>操作</th>
    </thead>
    <tbody>
      {{range .Categories}}
      <td>{{.Id}}</td>
      <td>{{.Title}}</td>
      <td>{{.TopicCount}}</td>
      <td>
        <a href="/cate?op=del&id={{.Id}}">刪除</a>
      </td>
      {{end}}
    </tbody>
  </table>
</div>
{{template "footer" .}}

寫業務

// CategoryController
package controllers

import (
    "beeapp/models"
    "github.com/astaxie/beego"
)

type CategoryController struct {
    beego.Controller
}

func (c *CategoryController) Get() {
    op := c.Input().Get("op")

    // 添加 刪除 顯示列表
    switch op {
    case "add":
        name := c.Input().Get("catename")
        if len(name) == 0 {
            break
        }

        err := models.AddCategory(name)
        if err != nil {
            beego.Error(err)
        }
        //添加成功 重定向cate
        c.Redirect("/cate", 301)
        // 記得return
        return

    case "del":
        id := c.Input().Get("id")
        if len(id) == 0 {
            break
        }
        err := models.DeleteCategory(id)
        if err != nil {
            beego.Error(err)
        }
        c.Redirect("/cate", 301)
        return

    }

    c.Data["Title"] = "分類"
    c.Data["IsCategory"] = true
    c.TplName = "category.html"
    var err error
    c.Data["Categories"], err = models.GetAllCategories()
    if err != nil {
        beego.Error(err)
    }
}
// models中添加如下方法
// 添加分類

func AddCategory(name string) error {
    o := orm.NewOrm()
    cate := &Category{Title: name}
    qs := o.QueryTable("category")
    err := qs.Filter("title", name).One(cate)
    if err == nil {
        //err爲空說明找到了
        return err
    }
    // 不存在 要做一個insert
    _, err = o.Insert(cate)
    if err != nil {
        return err
    }
    return nil
}

func GetAllCategories() ([]*Category, error) {
    o := orm.NewOrm()
    cates := make([]*Category, 0)
    qs := o.QueryTable("category")
    //注意下面的取址符號
    _, err := qs.All(&cates)
    return cates, err
}

func DeleteCategory(id string) error {
    cid, err := strconv.ParseInt(id, 10, 64)
    if err != nil {
        return err
    }
    o := orm.NewOrm()
    cate := &Category{Id: cid}
    _, err = o.Delete(cate)
    return err
}

simple http coookie

package main

import (
    "io"
    "strings"
    "net/http"
)

func main() {
   http.HandleFunc("/",Cookie)
   http.HandleFunc("/2",Cookie2)
   http.ListenAndServe(":9090",nil)
}

func Cookie(w http.ResponseWriter, r *http.Request) {
    //第一種設置方法
    ck := &http.Cookie{
        Name:   "myCookie",
        Value:  "hello",
        Path:   "/",
        Domain: "localhost",
        MaxAge: 120,
    }
    http.SetCookie(w, ck)
    ck2, err := r.Cookie("myCookie")
    if err != nil {
        io.WriteString(w, err.Error())
        return
    }
    io.WriteString(w, ck2.Value)
}


func Cookie2(w http.ResponseWriter, r *http.Request) {
    //第二種設置方法
    ck := &http.Cookie{
        Name:   "myCookie",
        Value:  strings.Replace("hello World"," ","%20",-1), //空格在cookie中是非法字符,需要替換處理,將其替換成非空格字符,注意cookie中的非法字符
        Path:   "/",
        Domain: "localhost",
        MaxAge: 120,
    }
    w.Header().Set("Set-Cookie",ck.String())
    ck2, err := r.Cookie("myCookie")
    if err != nil {
        io.WriteString(w, err.Error())
        return
    }
    io.WriteString(w, ck2.Value)
}

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/6717

(0)
Walker的頭像Walker
上一篇 12小時前
下一篇 15小時前

相關推薦

  • Go工程師體系課 018

    API 網關與持續部署入門(Kong & Jenkins) 對應資料目錄《第 2 章 Jenkins 入門》《第 3 章 通過 Jenkins 部署服務》,整理 Kong 與 Jenkins 在企業級持續交付中的實戰路徑。即便零基礎,也能順著步驟搭建出自己的網關 + 持續部署流水線。 課前導覽:什麼是 API 網關 API 網關位於客戶端與後端微服務…

  • Go工程師體系課 002

    GOPATH 與 Go Modules 的區別 1. 概念 GOPATH 是 Go 的早期依賴管理機制。 所有的 Go 項目和依賴包必須放在 GOPATH 目錄中(默認是 ~/go)。 一定要設置 GO111MODULE=off 項目路徑必須按照 src/包名 的結構組織。 不支持版本控制,依賴管理需要手動處理(例如 go get)。 查找依賴包的順序是 g…

    13小時前
    100
  • Go工程師體系課 015

    Docker 容器化 —— Go 項目實戰指南 一、Docker 核心概念 1.1 什麼是 Docker Docker 是一個開源的容器化平臺,它可以將應用程序及其所有依賴項打包到一個標準化的單元(容器)中,從而實現"一次構建,到處運行"。對於 Go 開發者而言,Docker 解決了以下痛點: 開發環境與生產環境不一致 依賴管理複雜(數據庫、緩存、消息隊列等…

  • Go資深工程師講解(慕課) 002

    go(二) string 字符串 package main import ( "fmt" "unicode/utf8" ) func main() { s := "Yes我愛Go語言" fmt.Println(len(s)) for _, b := range []byte(s) { fmt.Pri…

    後端開發 22小時前
    100
  • Go工程師體系課 008

    訂單及購物車 先從庫存服務中將 srv 的服務代碼框架複製過來,查找替換對應的名稱(order_srv) 加密技術基礎 對稱加密(Symmetric Encryption) 原理: 使用同一個密鑰進行加密和解密 就像一把鑰匙,既能鎖門也能開門 加密速度快,適合大量數據傳輸 使用場景: 本地文件加密 數據庫內容加密 大量數據傳輸時的內容加密 內部系統間的快速通…

簡體中文 繁體中文 English