最近学习 go 试着用net/http做了个NOT SO RESTFUL API Server,后面考虑给博客加个评论功能,就用 go 来写(flag 先立起来)

准备工作

  1. 搭建 http 服务,需要net/http模块
  2. 安装 golang mysql 驱动

搭建 http 服务

首先构建一个 hello world 服务


package main

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

func helloWorld(w http.ResponseWriter, r *http.Request){
  fmt.Fprintf(w, "Hello World!")
}

func main() {
    checkErr(err)
    http.HandleFunc("/", )  //设置访问的路由
    err = http.ListenAndServe(":3000", nil) //设置监听的端口
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

加入 sql 支持

在 go 中使用除了官方的 sql 包外还需要自己引入对应数据库的驱动,
mysql 比较常用的是 github.com/go-sql-driver/mysql

基本流程:

  • sql.Open连接到数据库
  • db.Prepare准备执行的 sql 语句,Query 不许要准备
  • stat.Exec执行语句

package main

import (
    "database/sql"
    "encoding/json"
    _ "github.com/go-sql-driver/mysql"
    "log"
    "net/http"
)

// User类型定义,go中json定义的是key要大写,表示这是一个public字段,后面`json:"name"`表示该字段转换为json时的key
type User struct {
    Name string `json:"name"`
    Id   int    `json:"id"`
}

type DeleteUser struct {
    Id int `json:"id"`
}

type Return struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
}

func main() {
    db, err := sql.Open("mysql", "user:[email protected]/database")
    checkErr(err)

    users := func(w http.ResponseWriter, r *http.Request) {
        switch r.Method {
        case http.MethodGet: // GET请求
            rows, err := db.Query("SELECT * FROM users")
            checkErr(err)
            result := []User{}
            for rows.Next() {
                var id int
                var name string
                err = rows.Scan(&id, &name)
                checkErr(err)
                u := User{name, id}
                result = append(result, u)
            }
            jsonResult, err := json.Marshal(result)
            checkErr(err)
            w.Header().Set("Content-Type", "application/json")
            w.Write(jsonResult)
        case http.MethodPost: // POST请求
            decoder := json.NewDecoder(r.Body) //json转换
            var t User
            err := decoder.Decode(&t)
            checkErr(err)
            id := t.Id
            name := t.Name
            stmt, err := db.Prepare("INSERT INTO users VALUES (?,?)") //mysql 语句 ?表示 placeholder
            checkErr(err)
            _, err = stmt.Exec(id, name) //执行sql语句
            var ret Return
            if err != nil {
                w.WriteHeader(http.StatusInternalServerError)
                ret = Return{Code: -1, Message: err.Error()}
            } else {
                ret = Return{Code: 0, Message: "创建成功"}
            }
            jsonResult, err := json.Marshal(ret)
            checkErr(err)
            w.Header().Set("Content-Type", "application/json")
            w.Write(jsonResult)
        case http.MethodPut: // PUT请求
            decoder := json.NewDecoder(r.Body)
            var t User
            err := decoder.Decode(&t)
            checkErr(err)
            id := t.Id
            name := t.Name
            stmt, err := db.Prepare("UPDATE users SET name=? WHERE id=?")
            checkErr(err)
            _, err = stmt.Exec(name, id)
            var ret Return
            if err != nil {
                w.WriteHeader(http.StatusInternalServerError)
                ret = Return{Code: -1, Message: err.Error()}
            } else {
                ret = Return{Code: 0, Message: "更新成功"}
            }
            jsonResult, err := json.Marshal(ret)
            checkErr(err)
            w.Header().Set("Content-Type", "application/json")
            w.Write(jsonResult)
        case http.MethodDelete:// DELETE请求
            decoder := json.NewDecoder(r.Body)
            var t DeleteUser
            err := decoder.Decode(&t)
            checkErr(err)
            id := t.Id
            stmt, err := db.Prepare("DELETE FROM users WHERE id=?")
            checkErr(err)
            _, err = stmt.Exec(id)
            var ret Return
            if err != nil {
                w.WriteHeader(http.StatusInternalServerError)
                ret = Return{Code: -1, Message: err.Error()}
            } else {
                ret = Return{Code: 0, Message: "删除成功"}
            }
            jsonResult, err := json.Marshal(ret)
            checkErr(err)
            w.Header().Set("Content-Type", "application/json")
            w.Write(jsonResult)
        }

    }

    http.HandleFunc("/users", users)     //设置访问的路由
    err = http.ListenAndServe(":3000", nil) //设置监听的端口
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

总结

以上就是在 golang 中使用 mysql 的简单玩法,只是非常基础的玩法,后续深入研究。
PUT 和 DELETE 请求实际上并不符合 RESTFUL 规范,所以叫Not So Restful#(滑稽)。go 原生并不支持 http 路由的正则匹配,自己实现起来并不那么复杂,后面自己来搞一个。