• Golang 入门系列(十一)Go语言实现webapi


    之前,已经讲过很多Golang的东西,比如基础语法,mysql的使用,redis的使用等等,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html

    今天就用从头写一个完整的go的示例项目吧。

     

    本项目完全使用原生开发,没有使用任何WEB框架和ORM。虽然大家对mvc 呀,三层架构已经很了解了。但是,我还是想从头写一个完整的示例项目。这样大家有一个更深刻的了解,这样以后介绍web框架,orm框架的时候,学习起来应该会简单一点。
     

    项目架构

    下图这种架构模式相信大家应该十分清楚

     

    Controller组合封装

    Controller"基类"封装

    package framework

    type Controller struct {
    Data interface{}
    }

    UserController定义了用户注册,登录和查询等简单的三个接口

    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

    数据库操作类的实现

    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的实现

        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,调相关的接口

    以下就是访问API的请求与响应

     /findAll 接口

    /register 接口

    最后

     以上,用Go语言实现webapi 的例子,已经介绍完了,虽然比较简单,session,权限验证等都没有加。但是最主要的功能已经讲完了,感兴趣的可以从头编写下相关的代码。

    完整例子下载:microcloud.rar

  • 相关阅读:
    Makefile学习
    Tmux使用
    Linux进程管理学习资料
    Linux内存管理学习资料
    Python常用的软件包
    Docker 学习
    Intel处理器技术文档
    Firefly-RK3399笔记
    Linux Kernel API
    ARM 技术文档
  • 原文地址:https://www.cnblogs.com/zhangweizhong/p/9755137.html
Copyright © 2020-2023  润新知