从零开始实现简单的webapi框架【Golang 入门系列十一】

2020-06-18 00:00:00 数据库 专区 架构 接口 也会

之前,已经讲过很多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-urlencodedfunc (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 <= { microcloud.ResultFail(w, "register fail") return } microcloud.ResultOk(w, "register success")}
//POST Content-Type=application/x-www-form-urlencodedfunc (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) == { microcloud.ResultFail(w, "user does not exist") return } if users[].Password != password { microcloud.ResultFail(w, "password error") return }
microcloud.ResultOk(w, "login success")}
// GET/POSTfunc (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 } id, err := result.LastInsertId() if err != nil { fmt.Println("Insert error") return } 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

 

 


相关文章