回顾
上一期上文中我们讲解了
- gin的中间件的使用
- post和get接口不同的获取参数方式
- ...
这一期我们的主要目标是
- 如何使用gin构建一个标准的web工程
- 如何使用gin写出标准的api接口
同样的我们接着上一期的工程继续
但是工程地址
的分支从这一期开始切换为server
分支。希望大家注意
查看一下目录
➜ go-gin-test tree -L 3
.
├── go.mod
├── go.sum
├── mian.go
└── routerex
└── router.go
Web工程
目标:
- 我们会使用常见的
MVC
模式来设计目录结构 - 借助go语言的interface封装一些
行为
或者业务
方便以后拓展和抽象 - 连接数据库
- ...
目录创建
我们会创建几个目录
- api 用来写web接口的目录
- service 用来写业务逻辑的目录
- model 用来存放对象结构体的目录
- server 用来服务管理
查看一下目录
➜ go-gin-test git:(main) tree -L 3
.
├── api
├── go.mod
├── go.sum
├── mian.go
├── model
├── server
├── routerex
│ ├── mid
│ │ └── mid.go
│ └── router.go
└── service
- 先修改一下
mid.go
和router.go
目的是删除之前的中间件,只使用跨域中间件
mid.go
package mid
import (
"net/http"
"github.com/gin-gonic/gin"
)
func MidCors(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin"))
c.Header("Access-Control-Allow-Headers", "*")
c.Header("Access-Control-Allow-Methods", "*")
c.Header("Access-Control-Allow-Credentials", "true")
//放行所有OPTIONS方法
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
// 处理请求
c.Next()
}
router.go
package routerex
import (
"example.com/m/v2/routerex/mid"
"github.com/gin-gonic/gin"
)
//用作注册请求地址
func RegRouter(g *gin.Engine) {
g1 := g.Group("/api")
//中间件
g1.Use(mid.MidCors)
}
- 在
server
目录下新建server.go
文件
server.go
package server
import (
"example.com/m/v2/routerex"
"github.com/gin-gonic/gin"
)
func ServerStart(port string) {
r := gin.Default()
routerex.RegRouter(r)
r.Run(":" + port) // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
- 修改
main.go
package main
import "example.com/m/v2/server"
//在main文件中我们尽量只有一个函数和一个调用,避免一些不必要坑,如果有任何需要请写到server里面去
func main() {
server.ServerStart("8080")
}
到了这一步,实际上一个大概的框架轮廓已经出现
➜ go-gin-test git:(main) tree -L 3
.
├── api web接口
├── go.mod
├── go.sum
├── mian.go 程序入口
├── model 数据库对应的结构体
├── server 管理服务
├── routerex 路由
│ ├── mid
│ │ └── mid.go
│ └── router.go
└── service 业务逻辑
数据库链接
数据库链接可以单独新建一个目录来管理
- 我们使用
xorm
用来作为持久层 - 同时使用
go-sql-driver/mysql
作为数据库驱动
运行以下命令导入
go get github.com/go-sql-driver/mysql
go get xorm.io/xorm
➜ go-gin-test git:(server) ✗ go get github.com/go-sql-driver/mysql
go: downloading github.com/go-sql-driver/mysql v1.6.0
go: github.com/go-sql-driver/mysql upgrade => v1.6.0
➜ go-gin-test git:(server) ✗ go get xorm.io/xorm
go: xorm.io/xorm upgrade => v1.0.7
➜ go-gin-test git:(server) ✗
新建db
目录和db.go
文件
db.go
package db
import (
"fmt"
"runtime/debug"
//这个是必须的驱动!注意这里不会自动引入
_ "github.com/go-sql-driver/mysql"
"xorm.io/xorm"
)
var MysqlDB *xorm.Engine
//这里可以改造为从yaml文件中获取配置。
func InitDB() error {
//防止程序崩溃
defer func() {
if err := recover(); err != nil {
fmt.Println(fmt.Errorf("InitMysql:%+v", err))
fmt.Println(fmt.Errorf("%s", string(debug.Stack())))
}
}()
//记得修改此处的用户、密码等
url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True",
"root",
"jimbir8520",
"106.52.197.141",
"7001",
"ycc")
//新建连接
db, err := xorm.NewEngine("mysql", url)
if err != nil {
fmt.Println(fmt.Sprintf("db init failed : %s", err.Error()))
return err
}
MysqlDB = db
fmt.Println("init db ok!")
return nil
}
到这里,我们的web工程就拥有了使用数据库的能力,接下来,我们尝试写一个业务接口
写一个业务接口
-
假设写一个用户注册的接口
-
我希望大家能够接着写用户登录和注销的接口(如果遇到问题可以通过以下方式联系我,我会帮你们解答。QQ群:
696502307
或者在公众号超级英雄吉姆
留言) -
在数据库新建一张
t_user
表。
字段为 id
,nick_name
,user_name
,pwd
,create_time
,deleted
- 在
model
新建user.go
package model
import "time"
type TUser struct {
Id int64 `xorm:"pk autoincr BIGINT(20)"`
//昵称
NickName string `xorm:"VARCHAR(255)"`
//用户名
UserName string `xorm:"VARCHAR(255)"`
//密码
Pwd string `xorm:"VARCHAR(255)"`
//是否已删除.0为正常,1为已删除
Deleted int `xorm:"default 0 TINYINT(1)"`
CreateTime time.Time `xorm:"not null comment('创建时间') DATETIME"`
}
//用来检查参数是否正确
func (c *TUser) Check() error {
//用来检查参数是否正确
func (c *TUser) Check() error {
if c.UserName == "" {
return errors.New("用户名不能为空")
}
if len(c.UserName) < 5 {
return errors.New("用户名必须大于4位")
}
user := &TUser{
UserName: c.UserName,
}
get, err := db.MysqlDB.Get(user)
if err != nil {
fmt.Println(fmt.Errorf("Check Get err : %v", err))
return errors.New("服务器繁忙请稍后重试")
}
if get {
return errors.New("用户名已存在")
}
if c.Pwd == "" {
return errors.New("密码不能为空")
}
compile, err := regexp.Compile(`^(.{6,16}[^0-9]*[^A-Z]*[^a-z]*[a-zA-Z0-9]*)$`)
if err != nil {
fmt.Println(fmt.Errorf("Check regexp err : %v", err))
return errors.New("服务器繁忙请稍后重试")
}
b := compile.MatchString(c.Pwd)
if !b {
return errors.New("密码不符合规则!密码应为6-16位(可以包含字母、数字、下划线)")
}
return nil
}
- 在
api
目录下新建api.go
编辑api.go
package api
import (
"fmt"
"net/http"
"time"
"example.com/m/v2/db"
"example.com/m/v2/model"
"github.com/gin-gonic/gin"
)
func Register(c *gin.Context) {
//此处我试用的json格式传输数据,通常情况下这里应该是form形式的提交,这里是我个人的喜好,比较方便,可灵活变换
u := &model.TUser{}
err := c.BindJSON(u)
if err != nil {
fmt.Println(fmt.Errorf("Register BindJSON err : %v", err))
c.JSON(http.StatusInternalServerError, gin.H{
"msg": "数据格式不正确",
})
return
}
err = u.Check()
if err != nil {
fmt.Println(fmt.Errorf("Register Check err : %v", err))
c.JSON(http.StatusInternalServerError, gin.H{
"msg": err.Error(),
})
return
}
u.CreateTime = time.Now()
_, err = db.MysqlDB.Insert(u)
if err != nil {
fmt.Println(fmt.Errorf("Register Insert err : %v", err))
c.JSON(http.StatusInternalServerError, gin.H{
"msg": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
}
编辑router.go
文件把我们的这个接口给注册
package routerex
import (
"example.com/m/v2/api"
"example.com/m/v2/routerex/mid"
"github.com/gin-gonic/gin"
)
//用作注册请求地址
func RegRouter(g *gin.Engine) {
g1 := g.Group("/api")
//中间件
g1.Use(mid.MidCors)
g1.POST("/register", api.Register)
}
- 同样的打包
go build -o hello
- 运行
./hello
➜ go-gin-test git:(server) ✗ go build -o hello
➜ go-gin-test git:(server) ✗ ./hello
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] POST /api/register --> example.com/m/v2/api.Register (4 handlers)
init db ok!
[GIN-debug] Listening and serving HTTP on :8080
使用postman
发送一个POST请求
可以看到我们请求成功了~
总结
-
恭喜你已经学会了一个标准的web工程结构和api编写
-
上诉的工程中,还有很多可以优化、改进的地方。大家可以尝试改一下
想获取工程的同学可以关注
超级英雄吉姆
,在公众号里发送gin
,获取工程。如果你有更多的想知道的内容或者有什么好的建议,可以在评论里回复,或者关注我的公众号
超级英雄吉姆
,在公众号留言,我看到后第一时间回复。- 建议大家关注一波公众号,gin框架的文章结束后,可以带大家一起协作做一个项目,提升大家的实战能力。第一时间会在公众号通知
下一期的内容预告
- 完善web框架
- gin框架的进阶
- ...