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

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

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


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


项目架构

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


Controller组合封装

Controller"基类"封装

packageframeworktypeControllerstruct{Datainterface{}}

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

packagecontrollerimport("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 */typeUserConterllerstruct{}varuserService =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")ifutils.Empty(username) || utils.Empty(password) {microcloud.ResultFail(w,"username or password can not be empty")return  }  id := userService.Insert(username, password)ifid <=0{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")ifutils.Empty(username) || utils.Empty(password) {microcloud.ResultFail(w,"username or password can not be empty")return  }  users := userService.SelectUserByName(username)iflen(users) ==0{microcloud.ResultFail(w,"user does not exist")return  }ifusers[0].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)}


数据访问层

packagedaoimport("micro-cloud/model""fmt"    )typeUserDaostruct{}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)iferr !=nil{fmt.Println("Insert error")return0    }    id, err := result.LastInsertId()iferr !=nil{fmt.Println("Insert error")return0    }returnid}func(p *UserDao)SelectUserByName(usernamestring)[]model.User{rows, err := framework.DB.Query("SELECT * FROM user WHERE username = ?", username)iferr !=nil{fmt.Println("selectuserbyname error")returnnil    }varusers []model.Userforrows.Next() {varuser model.User        err := rows.Scan(&user.ID, &user.Username, &user.Password, &user.CreateTime)iferr !=nil{fmt.Println("selectuserbyname error")continue        }users =append(users, user)    }    rows.Close()returnusers}func(p *UserDao)SelectAllUser()[]model.User{rows, err := framework.DB.Query("SELECT * FROM user")iferr !=nil{fmt.Println("SelectAllUser error")returnnil    }varusers []model.Userforrows.Next() {varuser model.User        err := rows.Scan(&user.ID, &user.Username, &user.Password, &user.CreateTime)iferr !=nil{fmt.Println("SelectAllUser error")continue        }users =append(users, user)    }    rows.Close()returnusers}

实体层

packagemodelimport"time"typeUserstruct{IDuint`json:"id"`Usernamestring`json:"username"`Passwordstring`json:"-"`CreateTime time.Time`json:"create_time"`}


database

数据库操作类的实现

packagemicrocloudimport("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数据库连接池varDB *sql.DBfuncInitDB(){//构建连接:"用户名:密码@tcp(IP:端口)/数据库?charset=uft8"//注意:要想解析time.Time类型,必须要设置parseTime=Truepath := 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)//验证连接iferr := DB.Ping(); err !=nil{        log.Panic(err)    }log.Println("database connect success")}funcCreateTable(){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)iferr !=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()iferr != nil {log.Panic(err)}


Router

路由处理的实现,其实也就是一个转发的功能

type RouterHandler struct {}varmux = make(map[string]func(http.ResponseWriter,*http.Request))func (p *RouterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {    fmt.Println(r.URL.Path)iffun, ok := mux[r.URL.Path]; ok {fun(w, r)return    }//静态资源ifstrings.HasPrefix(r.URL.Path,constant.STATIC_BAES_PATH){iffun, 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,权限验证等都没有加。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容

  • 一、数据类型转换 https://studygolang.com/articles/10838 package m...
    蓓蓓的万能男友阅读 1,066评论 0 1
  • 转发自:http://shanshanpt.github.io/2016/05/03/go-gin.html gi...
    dncmn阅读 6,033评论 0 1
  • golang http http 挂载方法 Head 发送 HEAD 请求func Head(url string...
    copyLeft阅读 569评论 0 0
  • 前言: golang处理http一般有这几种方式: 直接使用net包(这个是很底层的包,...
    coopbee阅读 2,854评论 0 3
  • 在我们的身边,每天发生许许多多的事情,很多事情随时间流去而淡忘。但有一件事,像一块发亮的鹅卵石,永远存留在记忆...
    Tom帅阅读 80评论 0 1