通常在向後端提交資料會使用以下兩種方式 :
傳統上,我們常常會使用 Form 表單請求
來傳輸資料到後端,但缺點是此方法往往會重刷整個頁面,造成額外的網頁頻寬消耗,而使用 AJAX 請求
則可以減少頁面重刷的次數
這邊先實作 Form 表單請求
的方法,下一章則會將其修改為 AJAX 請求
來比較兩者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 {{ block "content" . }} <h1 class='text-center'>{{ .Title }}</h1> <form action='/todo/' method='POST'> <div class='row'> <div class='offset-lg-1 col-lg-8 offset-md-1 col-md-7' style='margin-bottom: 5pt;'> <input type='text' class='form-control' name='todo' placeholder='Something to do.'> </div> <div class='col-lg-3 col-md-4'> <button class='btn btn-primary'>Add</button> </div> </div> </form> {{ range $t := .TODOs }} <form action='/todo/' method='POST'> <div class='row'> <div class='offset-lg-1 col-lg-8 offset-md-1 col-md-7 todo' style='margin-top: 5pt; margin-bottom: 5pt;'> <label class='col-form-label'>{{ $t.Item }}</label> <inupt name='index' name='index' value='{{ $t.Index }}' hidden> </div> </div> </form> {{ end }} {{ if .Message }} <div class='row'> <div class='offset-lg-2 col-lg-8 offset-md-1 col-md-10 col-sm-12'> <div class="alert alert-warning" role="alert"> {{ .Message }} </div> </div> </div> {{ end }} {{ end }}
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 package mainimport ( "fmt" "net/http" "os" "github.com/julienschmidt/httprouter" log "github.com/sirupsen/logrus" "github.com/urfave/negroni" negronilogrus "github.com/meatballhat/negroni-logrus" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/sqlite" ) type TODO struct { Item string Index uint } type TODOModel struct { ID uint `gorm:"PRIMARY_KEY,AUTO_INCREMENT"` Todo string } func (TODOModel) TableName () string { return "todos" } var db *gorm.DBfunc init () { var err error db, err = gorm.Open("sqlite3" , ":memory:" ) if err != nil { log.Fatal(err) } if !db.HasTable(&TODOModel{}) { db.CreateTable(&TODOModel{}) } } func main () { defer db.Close() host := "127.0.0.1" port := "8080" output := "D:\\Desktop\\GO\\log\\log.txt" args := os.Args[1 :] for { if len (args) < 2 { break } else if args[0 ] == "-h" || args[0 ] == "--host" { host = args[1 ] args = args[2 :] } else if args[0 ] == "-p" || args[0 ] == "--port" { port = args[1 ] args = args[2 :] } else if args[0 ] == "-l" || args[0 ] == "--log" { output = args[1 ] args = args[2 :] } else { log.Fatal(fmt.Sprintf("Unknown parameter : %s" , args[0 ])) } } mux := httprouter.New() mux.ServeFiles("/js/*filepath" , http.Dir("static/js" )) mux.ServeFiles("/css/*filepath" , http.Dir("static/css" )) mux.GET("/myexercise/todolist" , todolistindexHandler) mux.POST("/todo/" , addTODOHandler) mux.NotFound = http.HandlerFunc(notFound) mux.PanicHandler = errHandler l := log.New() var f *os.File var err error if output != "" { f, err = os.Create(output) if err != nil { log.Fatal(err) } defer f.Close() l.SetOutput(f) } n := negroni.Classic() n.Use(negronilogrus.NewMiddlewareFromLogger(l, "web" )) n.UseHandler(mux) server := http.Server{ Addr: fmt.Sprintf("%s:%s" , host, port), Handler: n, } fmt.Printf("服務器即將開啟, 訪問地址 http://%s:%s\n" , host, port) l.Println(fmt.Sprintf("服務器即將開啟, 訪問地址 http://%s:%s" , host, port)) l.Fatal(server.ListenAndServe()) }
init
main
defer db.Close()
關閉資料庫
將對應的路徑分配給對應的函式
todolistindexHandler
處理頁面的顯示
addTODOHandler
處理傳來的 Form 表單
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 func todolistindexHandler (w http.ResponseWriter, r *http.Request, p httprouter.Params) { t := template.Must(template.ParseFiles("./views/todolist/layout.html" , "./views/head.html" , "./views/todolist/todolist copy.html" )) var msg string if r.Header.Get("Message" ) != "" { msg = r.Header.Get("Message" ) r.Header.Set("Message" , "" ) } rows, err := db.Table("todos" ).Select("*" ).Rows() if err != nil { msg = "Unable to retrieve database" } var todos []TODO todos = make ([]TODO, 0 ) for rows.Next() { var todo struct { ID uint Todo string `gorm:"todo"` } db.ScanRows(rows, &todo) todos = append (todos, TODO{ Index: todo.ID, Item: todo.Todo, }) } data := struct { Title string TODOs []TODO Message string }{ Title: "代辦事項" , TODOs: todos, Message: msg, } err = t.ExecuteTemplate(w, "layout" , data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func addTODOHandler (w http.ResponseWriter, r *http.Request, p httprouter.Params) { r.ParseForm() todo := r.FormValue("todo" ) if todo == "" { r.Header.Set("Message" , "Empty TODO item" ) } else { db.Table("todos" ).Create(struct { Todo string `gorm:"todo"` }{ Todo: todo, }) } http.Redirect(w, r, "/myexercise/todolist" , http.StatusSeeOther) }
todolistindexHandler
最開始先檢查 header 中是否有錯誤訊息,有的話記錄起來並清空
接著對資料庫做查詢 db.Table("todos").Select("*").Rows()
,取出資料
以 rows.Next()
走訪每一個結果,並使用 db.ScanRows()
將該資料掃出,最後用 append()
放入變數中
addTODOHandler
結果