編程基礎 0004_Web_beego開發

beego 開始 2

文章的添加與刪除

  • 創建 TopicController
// controllers中添加topic.go
package controllers

import "github.com/astaxie/beego"

type TopicController struct {
    beego.Controller
}

func (c *TopicController) Get() {
    c.Data["Title"] = "文章"
    c.Data["IsTopic "] = true
    c.TplName = "topic.html"
}
//路由routers中添加
beego.Router("/topic", &controllers.TopicController{})
// beego有一個自動路由功能
beego.AutoRouter(&controllers.TopicController{})

beego 就會通過反射獲取結構體中所有實現的方法,你就可以通過如下的方式訪問到對應的方法。

  • /object/login 調用 ObjectController 中的 Login 方法
  • /object/logout 調用 ObjectController 中的 Logout 方法

除了前綴兩個/:controller/:method的匹配之外,剩下的 url beego 會幫你自動化解析為參數,保存在 this.Ctx.Input.Params 中,如下

/object/blog/2013/09/12 調用 ObjectController 中的 Blog 方法,參數是 map[0:2013,1:09,2:12]

現在已經可以通過自動識別出來下面類似的所有 url,都會把請求分發到 controller 的 simple 方法, 可以通過c.Ctx.Input.Param(":ext")獲取後綴名

/controller/simple
/controller/simple.html
/controller/simple.json
/controller/simple.xml

文章添類別添加時有個小坑(chrome 瀏覽器)chrome 有防止表單重復提交,如果你在該頁面上之前添加過一個類別,刪掉後再添加後出現,無法響應添加的問題,這是因為 chrome 認為你在重復提交。解決方法就是加個 token。為了不污染接口可以加錨點

go 原生表單處理

package main

import (
    "fmt"
    "html/template"
    "net/http"
)
const tpl = `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<form action="/" method="post">
  name <input type="text" name="username"><br/>
  pass <input type="password" name="pwd">
  <button type="submit">提交</button>
</form>
</body>
</html>
`
func main() {
    http.HandleFunc("/", SimpleForm)
    http.ListenAndServe(":9898", nil)
}

func SimpleForm(w http.ResponseWriter, r *http.Request) {
  if r.Method == "GET" {
      fmt.Println(r.Method)
      t:=template.New("hey")
      t.Parse(tpl)
      t.Execute(w,nil)
  } else {
      fmt.Println(r.FormValue("username"))
      fmt.Println(r.FormValue("pwd"))
  }
}

beego 文件上傳

附件上傳時注意表單的enctype="multipart/form-data",AddTopic 和 ModifyTopic 兩個 controller 中添加相關字段

func (c *TopicController) Post() {
    if !checkAccount(c.Ctx) {
        c.Redirect("/login", 302)
        return
    }
    //添加還是修改
    title := c.Input().Get("title")
    content := c.Input().Get("content")
    tid := c.Input().Get("tid")
    cate := c.Input().Get("cate")
    labels := c.Input().Get("labels")
    // ========上傳================
    //是否文件上傳
    _, fh, err := c.GetFile("attachment") //fh filehandler
    if err != nil {
        beego.Error(err)
    }
    var attachment string
    if fh != nil {
        //
        attachment = fh.Filename
        beego.Info(attachment)
        err=c.SaveToFile("attachment",path.Join("attachment",attachment))
    }
    //=========上傳結束(注意修改時要如果上傳新的,要把舊的刪除)==================
    if len(tid) == 0 {
        err = models.AddTopic(title, cate, labels, content,attachment)
    } else {
        err = models.ModifyTopic(tid, cate, title, labels, content,attachment)
    }

    if err != nil {
        beego.Error(err)
        return
    }
    c.Redirect("/topic", 302)
}

原生寫法

func (c *Controller) SaveToFile(fromfile, tofile string) error {
    file, _, err := c.Ctx.Request.FormFile(fromfile)
    if err != nil {
        return err
    }
    defer file.Close()
    f, err := os.OpenFile(tofile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
    if err != nil {
        return err
    }
    defer f.Close()
    io.Copy(f, file)
    return nil
}

國際化支持

bee new beegoi18n
cd beegoi18n && bee run
go get github.com/beego/i18n
dep ensure -add github.com/beego/i18n
//嵌套路由
package controllers

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

//創建base 替代beego.Controller
type baseController struct {
    beego.Controller
    i18n.Locale
}

//自己實現了Prepare()
//指定語言
//註冊本地化文件 local_en-US.ini 或 local_zh-CN.ini
func (this *baseController) Prepare() {
    //重寫
    lang := this.GetString("lang")
    if lang == "zh-CN" {
        this.Lang = lang
    } else {
        this.Lang = "en-US"
    }
}

type MainController struct {
    baseController
}

func (c *MainController) Get() {
    c.Data["Website"] = "beego.me"
    c.Data["Email"] = "astaxie@gmail.com"
    c.Data["Hi"] = "hi"
    c.Data["Bye"]="bye"
    c.TplName = "index.tpl"
}
// main.go中註冊

func main() {
    i18n.SetMessage("zh-CN","conf/local_zh-CN.ini")
    i18n.SetMessage("en-US","conf/locale_en-US.ini")
    //然後可以在控制器中Tr或在模板中Tr
    // 在模板中使用要註冊一下模板函數
    beego.Run()
}

分區功能

about=About
[about]
about=About Us
{{i18n .Lang .About}} <br />
{{i18n .Lang .about.about}}

文檔

自建 HTTP 中間件

  • 以類型形式
  • 以函數形式
  • 追回響應內容
  • 自定義響應內容
// 以類型的形式
package main

import "net/http"

type SingleHost struct {
    handler     http.Handler
    allowedHost string
}

func (this *SingleHost) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.Host == this.allowedHost {
        this.handler.ServeHTTP(w, r)
    } else {
        w.WriteHeader(403)
    }
}

func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello World!"))
}

func main() {
    single := &SingleHost{
        handler:     http.HandlerFunc(myHandler),
        allowedHost: "example.com",
    }
    http.ListenAndServe(":8080", single)
}
// 以函數的形式
package main

import "net/http"

func SingleHost(handler http.Handler, allowedHost string) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
        if r.Host == allowedHost {
            handler.ServeHTTP(w, r)
        } else {
            w.WriteHeader(403)
        }
    }
    return http.HandlerFunc(fn)
}

//正常處理的handler
func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello world"))
}

func main() {
    single := SingleHost(http.HandlerFunc(myHandler), "localhost:8080")
    http.ListenAndServe(":8080", single)
}
package main

import "net/http"

type AppendMiddleware struct {
    handler http.Handler
}

func (this *AppendMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    this.handler.ServeHTTP(w, r) //正常響應
    w.Write([]byte("Hey, this is middleware!"))
}

func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello world"))
}

func main() {
    mid := &AppendMiddleware{http.HandlerFunc(myHandler)}
    http.ListenAndServe(":8080", mid)
}
package main

import (
    "net/http"
    "net/http/httptest"
)

type ModifierMiddleware struct {
    handler http.Handler
}

func (this *ModifierMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    recoder := httptest.NewRecorder()  //它的作用是虛擬響應,不是真正響應,獲取正常的響應結果,
    this.handler.ServeHTTP(recoder, r) //記錄到recoder
    for k, v := range recoder.Header() {
        w.Header()[k] = v
    }
    //    自定義的一些操作
    w.Header().Set("go-web-foundation", "vip")
    w.WriteHeader(418)
    w.Write([]byte("hey,this is middleware! "))
    //
    w.Write(recoder.Body.Bytes())
}

func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello world"))
}

func main() {
    mid := ModifierMiddleware{http.HandlerFunc(myHandler)}
    http.ListenAndServe(":8080", &mid)
}

//curl --head "localhost:8080"

簡易 RPC 實現

  • 介紹一個 go--go 的通信
  • http rpc
  • tcp rpc
  • json rpc
// 基於http
// server.go
package main

import (
    "fmt"
    "github.com/kataras/iris/core/errors"
    "net/http"
    "net/rpc"
)

type Args struct {
    A, B int //首字母要大寫
}

type Math int

func (m *Math) Multiply(args *Args, reply *int) error {
    *reply = args.A * args.B
    return nil
}

//除法
type Quotient struct {
    Quo, Rem int
}

func (m *Math) Divide(args *Args, quo *Quotient) error {
    if args.B == 0 {
        return errors.New("divide by zero")
    }
    quo.Quo = args.A / args.B
    quo.Rem = args.A % args.B
    return nil
}

func main() {
    math := new(Math)
    rpc.Register(math)
    rpc.HandleHTTP()
    err := http.ListenAndServe(":1234", nil)
    if err != nil {
        fmt.Println(err.Error())
    }
}
//client.og 類型這裡可以抽成公共引用
package main

import (
    "fmt"
    "log"
    "net/rpc"
    "os"
)


type Args struct {
    A, B int //首字母要大寫
}

//除法
type Quotient struct {
    Quo, Rem int
}

func main() {
    if len(os.Args) != 2 {
        fmt.Println("Usage:", os.Args[0], "server")
        os.Exit(1)
    }
    serverAddr := os.Args[1]
    client, err := rpc.DialHTTP("tcp", serverAddr+":1234")
    if err != nil {
        log.Fatal("dialog:", err)
    }
    args := Args{17, 8}
    var reply int
    err = client.Call("Math.Multiply", args, &reply)
    if err != nil {
        log.Fatal("Math error:", err)
    }
    fmt.Println("Math:%d*%d=%d\n", args.A, args.B, reply)

    var quo Quotient
    err = client.Call("Math.Divide", args, &quo)
    if err != nil {
        log.Fatal("Math error:", err)
    }
    fmt.Println("Math:%d/%d=%d\n", args.A, args.B, quo.Quo, quo.Rem)

}

命令行下運行go run http_rpc_client.go localhost

基於 tcp 的

// server
package main

import (
    "fmt"
    "github.com/kataras/iris/core/errors"
    "net"
    "net/rpc"
    "os"
)

type Args struct {
    A, B int //首字母要大寫
}

type Math int

func (m *Math) Multiply(args *Args, reply *int) error {
    *reply = args.A * args.B
    return nil
}

//除法
type Quotient struct {
    Quo, Rem int
}

func (m *Math) Divide(args *Args, quo *Quotient) error {
    if args.B == 0 {
        return errors.New("divide by zero")
    }
    quo.Quo = args.A / args.B
    quo.Rem = args.A % args.B
    return nil
}

func main() {
    math := new(Math)
    rpc.Register(math)
    //rpc.HandleHTTP()
    //err := http.ListenAndServe(":1234", nil)
    //if err != nil {
    //    fmt.Println(err.Error())
    //}
    /*
       tpc的rpc
    */
    tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
    if err != nil {
        fmt.Println("Fatal error:", err)
        os.Exit(2)
    }
    listener, err := net.ListenTCP("tcp", tcpAddr)
    if err != nil {
        fmt.Println("Fatal error:", err)
        os.Exit(2)
    }
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("conn error:", err)
            continue
        }
        rpc.ServeConn(conn)
    }
}
// client 只改了一行
package main

import (
    "fmt"
    "log"
    "net/rpc"
    "os"
)


type Args struct {
    A, B int //首字母要大寫
}

//除法
type Quotient struct {
    Quo, Rem int
}

func main() {
    if len(os.Args) != 2 {
        fmt.Println("Usage:", os.Args[0], "server")
        os.Exit(1)
    }
    serverAddr := os.Args[1]
    //只改一行DialHTTP改成Dial
    client, err := rpc.Dial("tcp", serverAddr+":1234")
    if err != nil {
        log.Fatal("dialog:", err)
    }
    args := Args{17, 8}
    var reply int
    err = client.Call("Math.Multiply", args, &reply)
    if err != nil {
        log.Fatal("Math error:", err)
    }
    fmt.Println("Math:%d*%d=%d\n", args.A, args.B, reply)

    var quo Quotient
    err = client.Call("Math.Divide", args, &quo)
    if err != nil {
        log.Fatal("Math error:", err)
    }
    fmt.Println("Math:%d/%d=%d\n", args.A, args.B, quo.Quo, quo.Rem)

}

jsonrpc

// server
package main

import (
    "fmt"
    "github.com/kataras/iris/core/errors"
    "net"
    "net/rpc"
    "net/rpc/jsonrpc"
    "os"
)

type Args struct {
    A, B int //首字母要大寫
}

type Math int

func (m *Math) Multiply(args *Args, reply *int) error {
    *reply = args.A * args.B
    return nil
}

//除法
type Quotient struct {
    Quo, Rem int
}

func (m *Math) Divide(args *Args, quo *Quotient) error {
    if args.B == 0 {
        return errors.New("divide by zero")
    }
    quo.Quo = args.A / args.B
    quo.Rem = args.A % args.B
    return nil
}

func main() {
    math := new(Math)
    rpc.Register(math)

    tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
    if err != nil {
        fmt.Println("Fatal error:", err)
        os.Exit(2)
    }
    listener, err := net.ListenTCP("tcp", tcpAddr)
    if err != nil {
        fmt.Println("Fatal error:", err)
        os.Exit(2)
    }
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("conn error:", err)
            continue
        }
        jsonrpc.ServeConn(conn)
        //rpc.ServeConn(conn)
    }
}
// client
package main

import (
    "fmt"
    "log"
    "net/rpc"
    "net/rpc/jsonrpc"
    "os"
)


type Args struct {
    A, B int //首字母要大寫
}

//除法
type Quotient struct {
    Quo, Rem int
}

func main() {
    if len(os.Args) != 2 {
        fmt.Println("Usage:", os.Args[0], "server")
        os.Exit(1)
    }
    serverAddr := os.Args[1]
    //只改jsonrpc
    client, err := jsonrpc.Dial("tcp", serverAddr+":1234")
    if err != nil {
        log.Fatal("dialog:", err)
    }
    args := Args{17, 8}
    var reply int
    err = client.Call("Math.Multiply", args, &reply)
    if err != nil {
        log.Fatal("Math error:", err)
    }
    fmt.Println("Math:%d*%d=%d\n", args.A, args.B, reply)

    var quo Quotient
    err = client.Call("Math.Divide", args, &quo)
    if err != nil {
        log.Fatal("Math error:", err)
    }
    fmt.Println("Math:%d/%d=%d\n", args.A, args.B, quo.Quo, quo.Rem)

}

擴展學習

  • REST 簡介 (GET/POST/PUT/DELETE/PATCH)
  • WebSocket
  • Gorilla WebSocket 包

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

(0)
Walker的頭像Walker
上一篇 11小時前
下一篇 1天前

相關推薦

  • 編程基礎 0002_名庫講解

    名庫講解 goconfig go 語言針對 windows 下常見的 ini 格式的配置文件解析器,該解析器在涵蓋了所有 ini 文件操作的基礎上,又針對 go 語言實際開發過程中遇到的一些需求進行了擴展。該解析器最大的優勢在於對注釋的極佳支持,除此之外,支持多個配置文件覆蓋加載也是非常特別但好用的功能。 提供與 windows api 一模一樣的操作 支持…

    14小時前
    100
  • Go工程師體系課 protobuf_guide

    Protocol Buffers 入門指南 1. 簡介 Protocol Buffers(簡稱 protobuf)是 Google 開發的一種語言無關、平台無關、可擴展的結構化數據序列化機制。與 JSON、XML 等序列化方式相比,protobuf 更小、更快、更簡單。 項目主頁:https://github.com/protocolbuffers/prot…

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

    概覽 下載開發: vi emacs idea eclipse vs sublimeIde: GoLand,liteIDE默認 gopath ~/go/src 基本語法 變量定義使用 var,函數外定義可以使用括號的方式 package main import "fmt" //函數外定義要使用var var aa=3 var ss=&quo…

    21小時前
    100
  • Go工程師體系課 003

    grpc grpc grpc-go grpc 無縫集成了 protobuf protobuf 習慣用 Json、XML 數據存儲格式的你們,相信大多都沒聽過 Protocol Buffer。 Protocol Buffer 其實是 Google 出品的一種輕量 & 高效的結構化數據存儲格式,性能比 Json、XML 真的強!太!多! protobuf…

  • Go工程師體系課 020

    性能優化與 pprof 1. 先測量後優化 "Premature optimization is the root of all evil." — Donald Knuth 優化流程:1. 先寫正確的代碼2. 用 Benchmark 確認性能瓶頸3. 用 pprof 定位具體位置4. 優化 → 再測量 → 對比 2. pprof 工具 2.1 在 HTTP …

簡體中文 繁體中文 English