最近在研究Go,打算基于Go做点Web API,于是经过初步调研,打算用Beego这个框架,然后再结合其中提供的ORM以及Swagger的集成,可以快速搭建一个RESTful API的网站。
下面是具体做法:
1. 在Ubuntu中安装Go 1.8
默认Ubuntu apt-get提供的是Go 1.6,而我们要用最新的Go 1.8需要执行以下操作:
1.1 添加apt-get源并刷新
1.2 安装Go 1.8
1.3 设置环境变量
等安装完毕后,Go会被安装到/usr/lib/go-1.8目录。我们要执行go命令和建立自己项目的话,需要增加一些环境变量。
我们以后代码要放在当前用户下的Go目录下,需要先创建2个目录:
然后设置当前用户的环境变量:
保存后,重新刷新环境变量
接下来我们验证一下我们的Go版本,输入
我当前返回的是go version go1.8.1 linux/amd64说明我们的Go 1.8已经安装成功
2. 下载Beego、Bee工具和MysqL驱动
Beego是一个非常适合Go初学者的Web框架,提供了很多的功能,有些人说他臃肿,不过对于我这个Go初学者来说,不在乎是否臃肿,而在乎是否快速解决问题,是否简单。下面我们来安装Beego,这个很简单,只需要执行以下命令:
其中beego是框架的源代码,而bee是一个快速创建运行Beego项目的工具。
我们的目标是要实现ORMapping,那么连接数据库是必不可少的,需要另外下载Go版的MysqL驱动:
这些通过go get下载下来的文件都在~/go/src中,而bee工具是在~/go/bin中。
3. 创建api项目并运行
直接使用bee工具创建一个简单的RESTful API项目是个不二的选择,假设我们的项目名字叫testApi,那么只需要执行:
那么程序就会创建对应的文件在目录~/go/src/testApi
接下来我们需要运行这个项目。首先切换到到项目文件夹,然后运行bee run命令:
这个时候我们可以看到系统已经运行在8080端口,我们切换到浏览器,访问这个网站的Swagger地址:
就可以看到我们熟悉的Swagger界面了:
4. 修改代码,实现ORMapping
如果我们来到testApi项目文件夹,会看到类似MVC的结构,不过由于Web API不需要真正的View, 所有view文件夹被Swagger替换。下面我们要新建一个Student对象,并实现对Student增删改查的Web API。
4.1 新建Student model和对应的表
我们可以先在MysqL中创建Student表:
然后在model文件夹下新建Student.go文件,增加Student对象:
4.2初始化ORM模块
我们要通过ORM来操作对象和数据库,但是ORM需要初始化才能使用,我们需要在main.go文件中增加以下内容:
这里需要注意的是数据库连接字符串和普通的写法不一样,要写成如下格式:
用户名:密码@tcp(MysqL服务器地址:端口)/数据库名字?charset=utf8
4.3 提供数据库查询Student的方法
接下来就是数据库访问方法了。我们可以仿照user.go一样,把方法都写在Student.go文件里面。这是完整的Student.go文件:
<span style="color: #800000;">"<span style="color: #800000;">github.com/astaxie/beego/orm<span style="color: #800000;">"
<span style="color: #800000;">"<span style="color: #800000;">fmt<span style="color: #800000;">"
<span style="color: #800000;">"<span style="color: #800000;">time<span style="color: #800000;">"<span style="color: #000000;">
)
type Student <span style="color: #0000ff;">struct<span style="color: #000000;"> {
Id <span style="color: #0000ff;">int<span style="color: #000000;">
Name <span style="color: #0000ff;">string<span style="color: #000000;">
Birthdate <span style="color: #0000ff;">string<span style="color: #000000;">
Gender <span style="color: #0000ff;">bool<span style="color: #000000;">
score <span style="color: #0000ff;">int<span style="color: #000000;">
}
func GetAllStudents() []<span style="color: #000000;">Student {
o :=<span style="color: #000000;"> orm.NewOrm()
o.Using(<span style="color: #800000;">"<span style="color: #800000;">default<span style="color: #800000;">"<span style="color: #000000;">)
<span style="color: #0000ff;">var students []<span style="color: #000000;">Student
q:= o.QueryTable(<span style="color: #800000;">"<span style="color: #800000;">student<span style="color: #800000;">"<span style="color: #000000;">)
q.All(&<span style="color: #000000;">students)
<span style="color: #0000ff;">return<span style="color: #000000;"> students
}
func GetStudentById(id <span style="color: #0000ff;">int<span style="color: #000000;">) Student{
u:=<span style="color: #000000;">Student{Id:id}
o :=<span style="color: #000000;"> orm.NewOrm()
o.Using(<span style="color: #800000;">"<span style="color: #800000;">default<span style="color: #800000;">"<span style="color: #000000;">)
err := o.Read(&<span style="color: #000000;">u)
<span style="color: #0000ff;">if err ==<span style="color: #000000;"> orm.ErrNoRows {
fmt.Println(<span style="color: #800000;">"<span style="color: #800000;">查询不到<span style="color: #800000;">"<span style="color: #000000;">)
} <span style="color: #0000ff;">else <span style="color: #0000ff;">if err ==<span style="color: #000000;"> orm.ErrMissPK {
fmt.Println(<span style="color: #800000;">"<span style="color: #800000;">找不到主键<span style="color: #800000;">"<span style="color: #000000;">)
}
<span style="color: #0000ff;">return<span style="color: #000000;"> u
}
func AddStudent(student Student) <span style="color: #0000ff;">int<span style="color: #000000;">{
o :=<span style="color: #000000;"> orm.NewOrm()
o.Using(<span style="color: #800000;">"<span style="color: #800000;">default<span style="color: #800000;">"<span style="color: #000000;">)
o.Insert(student)
<span style="color: #0000ff;">return<span style="color: #000000;"> student.Id
}
func UpdateStudent(student <span style="color: #000000;">Student) {
o :=<span style="color: #000000;"> orm.NewOrm()
o.Using(<span style="color: #800000;">"<span style="color: #800000;">default<span style="color: #800000;">"<span style="color: #000000;">)
o.Update(student)
}
func DeleteStudent(id <span style="color: #0000ff;">int<span style="color: #000000;">){
o :=<span style="color: #000000;"> orm.NewOrm()
o.Using(<span style="color: #800000;">"<span style="color: #800000;">default<span style="color: #800000;">"<span style="color: #000000;">)
o.Delete(&<span style="color: #000000;">Student{Id:id})
}
func init() {
<span style="color: #008000;">//<span style="color: #008000;"> 需要在init中注册定义的model
orm.RegisterModel(<span style="color: #0000ff;">new<span style="color: #000000;">(Student))
}
4.4 创建StudentController对外提供Student的增加、删除、修改、查询一个、查询所有的方法
这里我们也可以仿照usercontroller,直接改写成我们需要的StudentController.go。这是内容:
import (
<span style="color: #800000;">"<span style="color: #800000;">testApi/models<span style="color: #800000;">"
<span style="color: #800000;">"<span style="color: #800000;">encoding/json<span style="color: #800000;">"<span style="color: #000000;">
)
type StudentController <span style="color: #0000ff;">struct<span style="color: #000000;"> {
beego.Controller
}
<span style="color: #008000;">//<span style="color: #008000;"> @Title 获得所有学生
<span style="color: #008000;">//<span style="color: #008000;"> @Description 返回所有的学生数据
<span style="color: #008000;">//<span style="color: #008000;"> @Success 200 {object} models.Student
<span style="color: #008000;">//<span style="color: #008000;"> @router / [get]
func (u <span style="color: #000000;">StudentController) GetAll() {
ss :=<span style="color: #000000;"> models.GetAllStudents()
u.Data[<span style="color: #800000;">"<span style="color: #800000;">json<span style="color: #800000;">"] =<span style="color: #000000;"> ss
u.ServeJSON()
}
<span style="color: #008000;">//<span style="color: #008000;"> @Title 获得一个学生
<span style="color: #008000;">//<span style="color: #008000;"> @Description 返回某学生数据
<span style="color: #008000;">//<span style="color: #008000;"> @Param id path int true "The key for staticblock"
<span style="color: #008000;">//<span style="color: #008000;"> @Success 200 {object} models.Student
<span style="color: #008000;">//<span style="color: #008000;"> @router /:id [get]
func (u <span style="color: #000000;">StudentController) GetById() {
id,_:= u.GetInt(<span style="color: #800000;">"<span style="color: #800000;">:id<span style="color: #800000;">"<span style="color: #000000;">)
s :=<span style="color: #000000;"> models.GetStudentById(id)
u.Data[<span style="color: #800000;">"<span style="color: #800000;">json<span style="color: #800000;">"] =<span style="color: #000000;"> s
u.ServeJSON()
}
<span style="color: #008000;">//<span style="color: #008000;"> @Title 创建用户
<span style="color: #008000;">//<span style="color: #008000;"> @Description 创建用户的描述
<span style="color: #008000;">//<span style="color: #008000;"> @Param body body models.Student true "body for user content"
<span style="color: #008000;">//<span style="color: #008000;"> @Success 200 {int} models.Student.Id
<span style="color: #008000;">//<span style="color: #008000;"> @Failure 403 body is empty
<span style="color: #008000;">//<span style="color: #008000;"> @router / [post]
func (u <span style="color: #000000;">StudentController) Post() {
<span style="color: #0000ff;">var<span style="color: #000000;"> s models.Student
json.Unmarshal(u.Ctx.Input.RequestBody,&<span style="color: #000000;">s)
uid := models.AddStudent(&<span style="color: #000000;">s)
u.Data[<span style="color: #800000;">"<span style="color: #800000;">json<span style="color: #800000;">"] =<span style="color: #000000;"> uid
u.ServeJSON()
}
<span style="color: #008000;">//<span style="color: #008000;"> @Title 修改用户
<span style="color: #008000;">//<span style="color: #008000;"> @Description 修改用户的内容
<span style="color: #008000;">//<span style="color: #008000;"> @Param body body models.Student true "body for user content"
<span style="color: #008000;">//<span style="color: #008000;"> @Success 200 {int} models.Student
<span style="color: #008000;">//<span style="color: #008000;"> @Failure 403 body is empty
<span style="color: #008000;">//<span style="color: #008000;"> @router / [put]
func (u <span style="color: #000000;">StudentController) Update() {
<span style="color: #0000ff;">var<span style="color: #000000;"> s models.Student
json.Unmarshal(u.Ctx.Input.RequestBody,&<span style="color: #000000;">s)
models.UpdateStudent(&<span style="color: #000000;">s)
u.Data[<span style="color: #800000;">"<span style="color: #800000;">json<span style="color: #800000;">"] =<span style="color: #000000;"> s
u.ServeJSON()
}
<span style="color: #008000;">//<span style="color: #008000;"> @Title 删除一个学生
<span style="color: #008000;">//<span style="color: #008000;"> @Description 删除某学生数据
<span style="color: #008000;">//<span style="color: #008000;"> @Param id path int true "The key for staticblock"
<span style="color: #008000;">//<span style="color: #008000;"> @Success 200 {object} models.Student
<span style="color: #008000;">//<span style="color: #008000;"> @router /:id [delete]
func (u *<span style="color: #000000;">StudentController) Delete() {
id,_:= u.GetInt(<span style="color: #800000;">"<span style="color: #800000;">:id<span style="color: #800000;">"<span style="color: #000000;">)
models.DeleteStudent(id)
u.Data[<span style="color: #800000;">"<span style="color: #800000;">json<span style="color: #800000;">"] = <span style="color: #0000ff;">true<span style="color: #000000;">
u.ServeJSON()
}
这里需要注意的是,函数上面的注释是很重要的,有一定的格式要求,Swagger就是根据这些注释来展示的,所以必须写正确。
4.5 将StudentController注册进路由
现在大部分工作已经完成,我们只需要把新的StudentController注册进路由即可,打开router.go,增加以下内容:
当然对于系统默认的user和object,如果我们不需要,可以注释掉。
4.6 运行并通过Swagger测试
我们的编码已经完成。接下来使用bee命令来运行我们的项目:
我们就可以看到我们新的student Controller了。并且可以通过调用API来完成对student表的CRUD操作。