基于gin web框架搭建RESTful API服务
这篇主要学习go项目中的项目结构、项目规范等知识,ROM采用的
database/sql的写法。
1.技术框架
利用的是ginweb框架,然后ROM层选用database/sql,安装mysql驱动。安装方式如下:
//使用github上的gin托管地址
$ go get -u github.com/gin-gonic/gin
$ go get github.com/go-sql-driver/mysql
2.项目结构如下
项目结构分析:
- 1、main.go主要是存放路由,启动项目;
- 2、router主要存放路由信息,然后返回一个router;
- 3、apis存放router的Handler函数;
- 4、databases存放数据连接信息;
- 5、models存放数据模型,类似Java中POJO对象。
│  main.go
│
├─.idea
│  │  go.iml
│  │  misc.xml
│  │  modules.xml
│  │  workspace.xml
│  │
│  └─inspectionProfiles
├─apis
│      person.go
│
├─databases
│      mysql.go
│
├─models
│      person.go
│
└─router
        router.go

3.main.go代码解释
package main
import (
    //这里讲db作为go/databases的一个别名,表示数据库连接池
    db "go/databases"
    . "go/router"
)
func main() {
    //当整个程序完成之后关闭数据库连接
    defer db.SqlDB.Close()
    router := InitRouter()
    router.Run(":8080")
}
4.router.go代码解释
package router
import (
    "github.com/gin-gonic/gin"
    ."go/apis"
)
func InitRouter() *gin.Engine {
    router := gin.Default()
    //IndexApi为一个Handler
    router.GET("/", IndexApi)
    router.POST("/person", AddPersonApi)
    router.GET("/persons", GetPersonsApi)
    router.GET("/person/:id", GetPersonApi)
    router.PUT("/person/:id", ModPersonApi)
    router.DELETE("/person/:id", DelPersonApi)
    return router
}
5.mysql.go代码解释
package databases
import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "log"
)
//因为我们需要在其他地方使用SqlDB这个变量,所以需要大写代表public
var SqlDB *sql.DB
//初始化方法
func init() {
    var err error
    SqlDB, err = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?parseTime=true")
    if err != nil {
        log.Fatal(err.Error())
    }
    //连接检测
    err = SqlDB.Ping()
    if err != nil {
        log.Fatal(err.Error())
    }
}
使用sql.Open()方法会创建一个数据库连接池db。这个地步不是数据库连接,它是一个连接池,只有当真正的数据库通信的时候才创建连接。例如,这里的db.Ping()操作。db.SetMaxIdleConns(20)和db.SetMaxOpenConns(20)分别设置数据库的空闲连接和最大打开连接,即向Mysql服务端发出的所有连接的最大数目。
6.models中person.go代码解释
package models
import (
   "log"
   db "go/databases"
)
//定义person类型结构
type Person struct {
   Id        int    `json:"id"`
   FirstName string `json:"first_name"`
   LastName  string `json:"last_name"`
}
func (p *Person) AddPerson() (id int64, err error) {
   rs, err := db.SqlDB.Exec("INSERT INTO person(first_name, last_name) VALUES (?, ?)", p.FirstName, p.LastName)
   if err != nil {
      return
   }
   id, err = rs.LastInsertId()
   return
}
func (p *Person) GetPersons() (persons []Person, err error) {
   persons = make([]Person, 0)
   rows, err := db.SqlDB.Query("SELECT id, first_name, last_name FROM person")
   defer rows.Close()
   if err != nil {
      return
   }
   for rows.Next() {
      var person Person
      rows.Scan(&person.Id, &person.FirstName, &person.LastName)
      persons = append(persons, person)
   }
   if err = rows.Err(); err != nil {
      return
   }
   return
}
func (p *Person) GetPerson() (person Person, err error) {
   err = db.SqlDB.QueryRow("SELECT id, first_name, last_name FROM person WHERE id=?", p.Id).Scan(
      &person.Id, &person.FirstName, &person.LastName,
   )
   return
}
func (p *Person) ModPerson() (ra int64, err error) {
   stmt, err := db.SqlDB.Prepare("UPDATE person SET first_name=?, last_name=? WHERE id=?")
   defer stmt.Close()
   if err != nil {
      return
   }
   rs, err := stmt.Exec(p.FirstName, p.LastName, p.Id)
   if err != nil {
      return
   }
   ra, err = rs.RowsAffected()
   return
}
func (p *Person) DelPerson() (ra int64, err error) {
   rs, err := db.SqlDB.Exec("DELETE FROM person WHERE id=?", p.Id)
   if err != nil {
      log.Fatalln(err)
   }
   ra, err = rs.RowsAffected()
   return
}
执行非query操作,使用db的Exec方法,在MySQL中使用?做占位符。最后我们把插入后的Id返回给客户端。
GetPersons方法解释:
读取MySQL的数据需要有一个绑定的过程,db.Query()方法返回一个rows对象,这个数据库连接随即转移到这个对象,因此我们需要定义rows.Close()操作,然后创建一个[]Person的切片。
使用make,而不是直接使用
var persons []Person的声明方式。还是有所差别的,使用make的方式,当数组切片没有元素的时候,Json会返回[]。如果直接声明,json会返回null。
接下来就是使用rows对象的Next()方法,遍历所查询的数据,一个个绑定到person对象上,最后append到person切片。
7.apis中的person.go代码解释
package apis
import (
    "net/http"
    "log"
    "fmt"
    "strconv"
    "github.com/gin-gonic/gin"
     ."go/models"
)
func IndexApi(c *gin.Context) {
    c.String(http.StatusOK, "It works")
}
func AddPersonApi(c *gin.Context) {
    firstName := c.Request.FormValue("first_name")
    lastName := c.Request.FormValue("last_name")
    p := Person{FirstName: firstName, LastName: lastName}
    ra, err := p.AddPerson()
    if err != nil {
        log.Fatalln(err)
    }
    msg := fmt.Sprintf("insert successful %d", ra)
    c.JSON(http.StatusOK, gin.H{
        "msg": msg,
    })
}
func GetPersonsApi(c *gin.Context) {
    var p Person
    persons, err := p.GetPersons()
    if err != nil {
        log.Fatalln(err)
    }
    c.JSON(http.StatusOK, gin.H{
        "persons": persons,
    })
}
func GetPersonApi(c *gin.Context) {
    cid := c.Param("id")
    id, err := strconv.Atoi(cid)
    if err != nil {
        log.Fatalln(err)
    }
    p := Person{Id: id}
    person, err := p.GetPerson()
    if err != nil {
        log.Fatalln(err)
    }
    c.JSON(http.StatusOK, gin.H{
        "person": person,
    })
}
func ModPersonApi(c *gin.Context) {
    cid := c.Param("id")
    id, err := strconv.Atoi(cid)
    if err != nil {
        log.Fatalln(err)
    }
    p := Person{Id: id}
    err = c.Bind(&p)
    if err != nil {
        log.Fatalln(err)
    }
    ra, err := p.ModPerson()
    if err != nil {
        log.Fatalln(err)
    }
    msg := fmt.Sprintf("Update person %d successful %d", p.Id, ra)
    c.JSON(http.StatusOK, gin.H{
        "msg": msg,
    })
}
func DelPersonApi(c *gin.Context) {
    cid := c.Param("id")
    id, err := strconv.Atoi(cid)
    if err != nil {
        log.Fatalln(err)
    }
    p := Person{Id: id}
    ra, err := p.DelPerson()
    if err != nil {
        log.Fatalln(err)
    }
    msg := fmt.Sprintf("Delete person %d successful %d", id, ra)
    c.JSON(http.StatusOK, gin.H{
        "msg": msg,
    })
}
其实,整个项目的结构和CRUD操作跟Java中的思想比较类似,应该很容易上手。需要注意一点的是,如果需要将整个项目运行起来,项目的路径一定Gopath路径:F:\Go\Project\src;


项目启动结果如下:

熟悉了database/sql的写法后,下一步就是学习ROM框架gorm的写法,进而学习Docker进行部署。
基于gin web框架搭建RESTful API服务的更多相关文章
- 使用CodeIgniter框架搭建RESTful API服务
		使用CodeIgniter框架搭建RESTful API服务 发表于 2014-07-12 | 分类于 翻译笔记 | 6条评论 在2011年8月的时候,我写了一篇博客<使用Cod ... 
- Go实战--通过gin-gonic框架搭建restful api服务(github.com/gin-gonic/gin)
		生命不止,继续 go go go !!! 先插播一条广告,给你坚持学习golang的理由: <2017 软件开发薪酬调查:Go 和 Scala 是最赚钱的语言> 言归正传! 之前写过使用g ... 
- 基于Gin+Gorm框架搭建MVC模式的Go语言后端系统
		文/朱季谦 环境准备:安装Gin与Gorm 本文搭建准备环境:Gin+Gorm+MySql. Gin是Go语言的一套WEB框架,在学习一种陌生语言的陌生框架,最好的方式,就是用我们熟悉的思维去学.作为 ... 
- 基于Go语言快速构建RESTful API服务
		In this post, we will not only cover how to use Go to create a RESTful JSON API, but we will also ta ... 
- 【PHP】基于ThinkPHP框架搭建OAuth2.0服务
		[PHP]基于ThinkPHP框架搭建OAuth2.0服务 http://leyteris.iteye.com/blog/1483403 
- 使用Yii2的Web框架搭建微服务框架
		方法 使用自己的Yii2镜像作为基础 使用Yii2的Web框架搭建,为了节省搭建Yii2框架的时间,直接使用现有的Yii2项目,删除了业务相关的逻辑类,将这个代码库作为搭建微服务框架的基础,本身已经积 ... 
- 【重学Node.js 第1&2篇】本地搭建Node环境并起RESTful Api服务
		本地搭建Node环境并起RESTful Api服务 课程介绍看这里:https://www.cnblogs.com/zhangran/p/11963616.html 项目github地址:https: ... 
- Gin Web框架简单介绍
		翻译自: https://github.com/gin-gonic/gin/blob/develop/README.md Gin Web框架 branch=master"> Gin是用 ... 
- 使用 Beego 搭建 Restful API 项目
		1 环境准备 首先你需要在你的环境安装以下软件: go:编程语言运行环境 git:版本控制工具 beego:go 语言流行的开发框架 bee:beego 配套的快速搭建工具 你喜欢的数据库:这里以 M ... 
随机推荐
- nginx lnmp之nginx+php
			配置如下(在server部分添加): location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/tmp/php-fcgi.sock; ... 
- 解决github clone慢的问题
			github clone非常慢,解决方法,首先要有vpn 参考 https://www.zhihu.com/question/27159393 第一种方法 这种是没有vpn的方法,测试从10k到 几十 ... 
- kafka shell
			停止 ./bin/kafka-server-stop.sh 启动 nohup sh kafka-server-start.sh ../config/server.properties & 创 ... 
- Kafka Offset Monitor页面显示空白
			下载包:https://github.com/Morningstar/kafka-offset-monitor.git 解决:jar包内\KafkaOffsetMonitor-assembly-0.2 ... 
- HashMap源码1
			jdk1.8之前是数组+链表的形式,后面会介绍jdk1.8对hashMap的改动:数组+链表+红黑树 transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分. 当一个对象被串 ... 
- AVLMap平衡二叉树
			public class AVLMap<K, V> implements Iterable<AVLEntry<K, V>> { private int size; ... 
- idea 2019.2 版本把菜单栏隐藏了恢复办法
			一不小心把idea的菜单栏给隐藏了(如图) ,搞了半天也恢复不了,网上也没有找到什么办法,可是搞得我焦头烂额呀,怎么找也找不到,也不见大神有过提示,最后没办法,想着去看看它的配置文件吧,于是便找到了默 ... 
- Effective.Java第45-55条(规范相关)
			45. 明智谨慎地使用Stream 46. 优先考虑流中无副作用的函数 47. 优先使用Collection而不是Stream作为方法的返回类型 48. 谨慎使用流并行 49. 检查参数有效 ... 
- drf面试题及总结
			drf面试题及总结 1.什么是前后端分离 2.什么是restful规范 3.模拟浏览器进行发送请求的工具 4.查找模板的顺序 5.什么是drf组件 6.drf组件提供的功能 7.drf继承过哪些视图类 ... 
- django开发_七牛云CNAME解析
			CNAME 简介 CNAME 即指别名记录,也被称为规范名字.这种记录允你将多个名字映射到同一台计算机. 当需要将域名指向另一个域名,再由另一个域名提供 ip地址,就需要添加 CNAME 记录. 为什 ... 
