任务概述
利用 web 客户端调用远端服务是服务开发本实验的重要内容。其中,要点建立 API First 的开发理念,实现前后端分离,使得团队协作变得更有效率
任务目标
- 选择合适的 API,实现从接口或资源(领域)建模,到 API 设计的过程
- 使用 API 工具,编制 API 描述文件,编译生成服务器、客户端原型
- 使用 Github 建立一个组织,通过 API 文档,实现客户端项目与 RESTful 服务项目同步开发
- 使用 API 设计工具提供 Mock 服务,两个团队独立测试 API
- 使用 travis 测试相关模块
成果展示
项目 github,我们小组选择开发一个极简博客,具有注册、登录、博客查看、评论等功能,前端使用 Vue.js 构建,后端使用 go 开发
设计说明
我在小组中负责数据库操作的封装,即为其它后端的组员提供可以直接操作数据库的接口,代码集中在db.go
中,经过与组员的沟通,确定需要实现的接口有:
PutArticles(articles []model.Article)
将博客保存到数据库PutUsers(users []model.User)
将用户保存到数据库GetArticles(id int64, page int64) []model.Article
由博客id获取博客内容GetUser(username string) model.User
由用户id获取用户信息
选择使用 mongoDB 进行数据的存储,因为其可以为 WEB 应用提供可扩展的高性能数据存储
1.封装数据库基本操作
引入通过 go 语言操作 mongoDB 的包 mgo
import (
...
"github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson"
)
初始化数据库,获取连接数据库需要的mgo.Session
var globalS *mgo.Session
func Init() {
dialInfo := &mgo.DialInfo{
Addrs: []string{host},
Source: dbsource,
Username: username,
Password: password,
}
s, err := mgo.DialWithInfo(dialInfo)
if err != nil {
log.Fatalln("create session error ", err)
}
globalS = s
}
对将要用到的插入、查询等数据库操作进行封装,包括连接数据库connect
以及对数据库进行操作两步
func connect(db, collection string) (*mgo.Session, *mgo.Collection) {
mgoSess := globalS.Copy()
mgoCollec := mgoSess.DB(db).C(collection)
return mgoSess, mgoCollec
}
func Insert(db, collection string, docs ...interface{}) error {
ms, mc := connect(db, collection)
defer ms.Close()
return mc.Insert(docs...)
}
func Find(db, collection string, query, selector, result interface{}) error {
ms, mc := connect(db, collection)
defer ms.Close()
return mc.Find(query).Select(selector).One(result)
}
func FindAll(db, collection string, query, selector, result interface{}) error {
ms, mc := connect(db, collection)
defer ms.Close()
return mc.Find(query).Select(selector).All(result)
}
2.实现接口
因为 mongoDB 使用需要,首先在各个model_xx.go
中的变量加入bson
变量名,然后通过调用我们封装好的基本操作实现各个需要的接口,以PutArticles
为例,只需要对传入的Article
数据循环调用Insert
即可
// PutArticles : put articles to database
func PutArticles(articles []model.Article) error {
for i := 0; i < len(articles); i++ {
err := Insert(dbsource, Atccollection, articles[i])
if err != nil {
return err
}
}
}
// PutUsers : put users to database
func PutUsers(users []model.User) error {
for i := 0; i < len(articles); i++ {
err := Insert(dbsource, Usrcollection, users[i])
if err != nil {
return err
}
}
}
// GetArticles : get articles by id from database
// if id == -1 ,find all articles and only return 'page' articles
func GetArticles(id int64, page int64) []model.Article {
var articles []model.Article
if id == -1 {
err := FindAll(dbsource, Atccollection, nil, nil, &articles)
if err != nil {
log.Fatal(err)
}
if len(articles) > 5
articles = articles[:5]
}
else {
err := Find(dbsource, Atccollection, bson.M{"id": id}, nil, &articles)
if err != nil {
log.Fatal(err)
}
}
return articles
}
// GetUser : get users by username from database
func GetUser(username string) model.User {
var result model.User
err := Find(dbsource, Usrcollection, bson.M{"username": username}, nil, &result)
if err != nil {
log.Fatal(err)
}
return result
}
任务总结
本次项目虽然实现的功能比较简单,但却是一个前后端兼备的项目。一个具有一定规模的项目经过系统的分割后成功由大家配合完成,让我收获了一次宝贵的前后端分离来开发软件的经验,也学习到了通过 API 文档,实现客户端与 RESTful 服务器端同步开发的方法。