Golang 入門系列(十一)從零開始實現一個完整的webapi項目!

之前,已經講過很多Golang的東西,比如基礎語法,mysql的使用,redis的使用等等,但是,很多人都說:講了那麼多都是golang的基礎內容,能不能做一個完整的項目。所以今天就給大家從頭將一個完整的go的示例項目:golang從零實現web api。

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

項目架構

本項目採用普通的三層架構實現,下圖這種架構模式相信大家應該十分清楚。

Golang 入門系列(十一)從零開始實現一個完整的webapi項目!

Controller

controller 控制器,定義一個controller 結構體,其他業務controller 會繼承這個 基礎的controller。

<code>package framework

type Controller struct {
Data interface{}
}/<code>

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

<code>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)
}/<code>

數據訪問層

數據庫訪問層負責操作數據庫,實現結構如下:

<code>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
}/<code>

實體層

實體層包含全部的實體類,實現如下:

<code>package model

import "time"

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

database

數據庫操作類的實現,使用go-sql-driver/mysql 庫,這個之前的文章介紹過如何使用:《 》

<code>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)
}
}/<code>

http

golang的net/http即可實現http 服務:

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

Router

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

<code>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
}/<code>

演示

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

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

/findAll 接口

Golang 入門系列(十一)從零開始實現一個完整的webapi項目!

/register 接口

Golang 入門系列(十一)從零開始實現一個完整的webapi項目!

最後

以上,用Go語言實現webapi 的例子,已經介紹完了,雖然比較簡單,session,權限驗證等都沒有加。但是最主要的功能已經講完了。分享關注(章為忠學架構

)獲取完整代碼。



分享到:


相關文章: