Golang 入門系列(十一)Go語言實現webapi

以前,已經講過不少Golang的東西,好比基礎語法,mysql的使用,redis的使用等等,感興趣的能夠看看之前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.htmlhtml

今天就用從頭寫一個完整的go的示例項目吧。mysql

 

本項目徹底使用原生開發,沒有使用任何WEB框架和ORM。雖然你們對mvc 呀,三層架構已經很瞭解了。可是,我仍是想從頭寫一個完整的示例項目。這樣你們有一個更深入的瞭解,這樣之後介紹web框架,orm框架的時候,學習起來應該會簡單一點。
 

項目架構

下圖這種架構模式相信你們應該十分清楚git

 

 

Controller組合封裝

Controller"基類"封裝github

package framework

type Controller struct {
Data interface{}
}

 

UserController定義了用戶註冊,登陸和查詢等簡單的三個接口web

package controller

import (
"net/http"
"micro-cloud/service"
"micro-cloud/utils"
"micro-cloud/framework"
)

/**
* r.PostFormValue : 能夠解析 Post/PUT Content-Type=application/x-www-form-urlencoded 或 Content-Type=multipart/form-data
*/

type UserConterller struct {

}

var userService = new(service.UserService)

func (p *UserConterller) Router(router *framework.RouterHandler) {
router.Router("/register", p.register)
router.Router("/login", p.login)
router.Router("/findAll", p.findAll)
}

//POST Content-Type=application/x-www-form-urlencoded
func (p *UserConterller) register(w http.ResponseWriter, r *http.Request) {
username := r.PostFormValue("username")
password := r.PostFormValue("password")
if utils.Empty(username) || utils.Empty(password) {
microcloud.ResultFail(w, "username or password can not be empty")
return
}
id := userService.Insert(username, password)
if id <= 0 {
microcloud.ResultFail(w, "register fail")
return
}
microcloud.ResultOk(w, "register success")
}

//POST Content-Type=application/x-www-form-urlencoded
func (p *UserConterller) login(w http.ResponseWriter, r *http.Request) {
username := r.PostFormValue("username")
password := r.PostFormValue("password")
if utils.Empty(username) || utils.Empty(password) {
microcloud.ResultFail(w, "username or password can not be empty")
return
}
users := userService.SelectUserByName(username)
if len(users) == 0 {
microcloud.ResultFail(w, "user does not exist")
return
}
if users[0].Password != password {
microcloud.ResultFail(w, "password error")
return
}

microcloud.ResultOk(w, "login success")
}

// GET/POST
func (p *UserConterller) findAll(w http.ResponseWriter, r *http.Request) {
users := userService.SelectAllUser()
framework.ResultJsonOk(w, users)
}

 

數據訪問層

package dao

import (
    "micro-cloud/model"
    "fmt"
    )

type UserDao struct {
}

func (p *UserDao) Insert(user *model.User) int64 {
    result, err := framework.DB.Exec("INSERT INTO user(`username`,`password`,`create_time`) value(?,?,?)", user.Username, user.Password, user.CreateTime)
    if err != nil {
        fmt.Println("Insert error")
        return 0
    }
    id, err := result.LastInsertId()
    if err != nil {
        fmt.Println("Insert error")
        return 0
    }
    return id
}

func (p *UserDao) SelectUserByName(username string) []model.User {
    rows, err := framework.DB.Query("SELECT * FROM user WHERE username = ?", username)
    if err != nil {
        fmt.Println("selectuserbyname error")
        return nil
    }
    var users []model.User
    for rows.Next() {
        var user model.User
        err := rows.Scan(&user.ID, &user.Username, &user.Password, &user.CreateTime)
        if err != nil {
            fmt.Println("selectuserbyname error")
            continue
        }
        users = append(users, user)
    }
    rows.Close()
    return users
}

func (p *UserDao) SelectAllUser() []model.User {
    rows, err := framework.DB.Query("SELECT * FROM user")
    if err != nil {
        fmt.Println("SelectAllUser error")
        return nil
    }
    var users []model.User
    for rows.Next() {
        var user model.User
        err := rows.Scan(&user.ID, &user.Username, &user.Password, &user.CreateTime)
        if err != nil {
            fmt.Println("SelectAllUser error")
            continue
        }
        users = append(users, user)
    }
    rows.Close()
    return users
}

 

實體層

package model

import "time"

type User struct {
    ID         uint      `json:"id"`
    Username   string    `json:"username"`
    Password   string    `json:"-"`
    CreateTime time.Time `json:"create_time"`
}

 

database

數據庫操做類的實現redis

package microcloud

import (
    "database/sql"
    "log"
    "strings" _ "github.com/go-sql-driver/mysql" ) //數據庫的配置 const ( username = "admin" password = "123456" ip = "10.2.1.5" port = "3306" dbName = "microcloud" driverName = "mysql" ) //DB數據庫鏈接池 var DB *sql.DB func InitDB() { //構建鏈接:"用戶名:密碼@tcp(IP:端口)/數據庫?charset=uft8" //注意:要想解析time.Time類型,必需要設置parseTime=True path := strings.Join([]string{username, ":", password, "@tcp(", ip, ":", port, ")/", dbName, "?charset=utf8&parseTime=True&loc=Local"}, "") //打開數據庫,前者是驅動名,因此要導入:_"github.com/go-sql-driver/mysql" DB, _ = sql.Open(driverName, path) //設置數據庫最大鏈接數 DB.SetConnMaxLifetime(100) //設置數據庫最大閒置鏈接數 DB.SetMaxIdleConns(10) //驗證鏈接 if err := DB.Ping(); err != nil { log.Panic(err) } log.Println("database connect success") } func CreateTable() { userTable := "CREATE TABLE IF NOT EXISTS `user`(" + "`id` INT UNSIGNED AUTO_INCREMENT," + "`username` VARCHAR(20) NOT NULL," + "`password` VARCHAR(40) NOT NULL," + "`create_time` DATETIME," + "PRIMARY KEY ( `id` )" + ")ENGINE=InnoDB DEFAULT CHARSET=utf8;" _, err := DB.Exec(userTable) if err != nil { log.Panic(err) } }

 

http

http server的實現
sql

    server := &http.Server{
        Addr:        ":8215",
        Handler:     microcloud.Router,
        ReadTimeout: 5 * time.Second,
    }
    RegiterRouter(microcloud.Router)
    err := server.ListenAndServe()
    if err != nil {
        log.Panic(err)
    }

 

Router

路由處理的實現,其實也就是一個轉發的功能數據庫

type RouterHandler struct {
}

var mux = make(map[string]func(http.ResponseWriter,*http.Request))

func (p *RouterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Println(r.URL.Path)
    if fun, ok := mux[r.URL.Path]; ok {
        fun(w, r)
        return
    }
    //靜態資源
    if strings.HasPrefix(r.URL.Path,constant.STATIC_BAES_PATH){
        if fun, ok := mux[constant.STATIC_BAES_PATH]; ok {
            fun(w, r)
            return
        }
    }
    http.Error(w, "error URL:"+r.URL.String(), http.StatusBadRequest)

}

func (p *RouterHandler) Router(relativePath string, handler func(http.ResponseWriter, *http.Request)) {
    mux[relativePath] = handler
}

 

演示

執行 go run main.go 以後,打開Postman,調相關的接口json

如下就是訪問API的請求與響應api

 /findAll 接口

 

/register 接口

 

最後

 以上,用Go語言實現webapi 的例子,已經介紹完了,雖然比較簡單,session,權限驗證等都沒有加。可是最主要的功能已經講完了,感興趣的能夠從頭編寫下相關的代碼。

完整例子下載:microcloud.rar

相關文章
相關標籤/搜索