使用go搭建个人博客(二):数据库和路由

  上一篇文章简单介绍了选择的技术栈和怎么初始化一个Web项目,项目目录等,这篇就来介绍路由的配置和怎么连接数据库、使用xorm

路由配置

  上一章介绍了使用gin创建一个初始的web项目。现在,我们就使用gin提供的路由机制来配置。在main.go中进行添加:

main.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"io"
"os"

"github.com/gin-gonic/gin"
"github.com/zachrey/blog/routers"
)

func main() {
r := gin.New()

// 设置日志文件
f, _ := os.Create("gin.log")
gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
// 使用日志中间件
r.Use(gin.Logger())
// 设置静态文件夹
r.Static("/static", "./static")
// 加载路由
routers.LoadRouters(r)
r.Run(":8888")
}

routers.LoadRouters函数,我们放在routers/包下面,让所有的路由都统一管理:

routers/router.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package routers

import (
"log"
"net/http"

"github.com/gin-gonic/gin"
// ctrs "github.com/zachrey/blog/controllers"
)

// LoadRouters 初始化router
func LoadRouters(router *gin.Engine) {
loadRouters(router)
}

func loadRouters(router *gin.Engine) {
// 这里测试根路由
/*
控制器函数会接收一个`gin.Context`类型的指针,这个指针包含http的请求和响应信息和操作方法。
*/
router.GET("/", func(c *gin.Context) {
post := models.GetPostByID(1)
log.Println("@@ post", post)
// 返回一个json格式的数据
c.JSON(http.StatusOK, gin.H{
"Status": 0,
"data": post,
})
})
// 路由控制函数,我们全部放在controllers目录下
//router.GET("/get-posts", ctrs.GetPosts)

// ...... 很多很多路由。。。
}

ctrs.GetPosts这个控制器函数,之后结合数据库来进行演示。现在启动项目go run main.go,然后在浏览器中访问localhost:8888/来看,根路由会返回什么。

连接数据库

  由于个人博客功能不是很复杂,这里就直接使用了sqlite这种轻量级的数据库。GO没有内置的数据库驱动,但是GO定义了数据库驱动包接口database/sql/driver,所以就算对于不同的数据库,可以在这些接口的基础上来开发自己的驱动包。那么,需要连接sqlite数据库,我们就需要去找sqlite的数据驱动包。

1
github.com/mattn/go-sqlite3

以上就是需要用到的驱动包的地址,只需要在项目中导入初始化就行。

其他的驱动包列表:https://github.com/golang/go/wiki/SQLDrivers

在项目的入口文件main.go初始化(导入)数据库驱动:

main.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"io"
"os"

"github.com/gin-gonic/gin"
_ "github.com/mattn/go-sqlite3" // 只导入,并不需要去使用,所以注意前面的"_"下划线
)

func main() {
r := gin.New()
...
r.Run(":8888")
}

初始化数据库后,在database目录下,创建一个数据库配置文件,我们使用xorm来连接数据库。

database/sqlite3.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package database

import (
"log"

"github.com/xormplus/xorm" // 记得 go get 获取哦
)
// ORM xorm引擎的实例,供其他模块可以直接使用,注意**首字母大写**,因为`Go`语音的隐藏和公开的规则,大写为公开,小写为隐藏。
var ORM *xorm.Engine

func init() { // 使用init来自动连接数据库,并创建ORM实例
var err error
ORM, err = xorm.NewEngine("sqlite3", "./database/test.db")
if err != nil {
log.Fatalln(err)
return
}
err = ORM.Ping() // 测试能操作数据库
if err != nil {
log.Fatalln(err)
return
}
ORM.ShowSQL(true) // 测试环境,显示每次执行的sql语句长什么样子
}

上面的xorm操作,建议多看官方文档。我的github上有现成的测试的数据库文件,也就是这个博客系统的数据库文件,大家可以下载下来,连接试试。看会不会报错,ping操作能不能连通。这里有个注意的地方./database/test.db,这个相对路径,因为我把test.db这个文件放在sqlite3.go这个配置文件的同级目录下,如果你创建引擎的时候这样写./test.db,它并不会指向/database/test.db这个文件,而是会指向项目根目录下的/test.db,从而会创建一个新的空的/text.db文件。因为Go语言是已包来管理项目的,所以./表示的是包的同级目录,而不是包里面文件的同级目录。

创建ORM模板

  所有的模板都放在models下面,每一个model都对应一张数据库的表,我们可以使用sqlite数据库连接工具来看看,test.db有哪些表和具体字段,这里就展示model了,因为字段都是对应的。

models/post.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package models

import (
"log"

db "github.com/zachrey/blog/database" // 导入之前创建的数据库引擎实例,用来操作数据库
)

type MPost struct {
Id int64 `xorm:"pk autoincr"`
Title string `xorm:"'title'"`
FileName string `xorm:"file_name"`
TextAmount int64 `xorm:"text_amount"`
CreateTime int64 `xorm:"created 'create_time'"`
}

// GetPostByID 根据ID获取文章
func GetPostByID(Id int64) *MPost {
var post MPost
// 根据Id得到一个MPost类型的实例
has, err := db.ORM.Table("posts").Id(Id).Get(&post)
if err != nil {
log.Println("ERROR:", err)
return nil
}
if has == false {
return nil
}
return &post
}

// GetPosts 获取所有的文章
func GetPosts() *[]MPost {
var post []MPost
err := db.ORM.Table("posts").Find(&post)
if err != nil {
log.Println("ERROR:", err)
return nil
}
return &post
}

使用struct来对应数据库的表,表中字段的类型,约束等。注意结构体的属性首字母都是大写的,视情况而定,如果这个结构体需要被访问,最好全部都写错大写。关于类型的映射,可以看官网的“Go与字段类型对应表”目录,里面会有详细的说明。对于xorm:"pk autoincr"这样的东西,成为Tag,具体的Tag规则看官网的“Column属性定义”目录的介绍。

在控制器中使用模板上的方法

控制器全部放在controllers/下。

/controllers/posts.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package controllers

import (
"log"
"net/http"

"github.com/gin-gonic/gin"
"github.com/zachrey/blog/models"
)

//GetPosts 获取所有的文章
func GetPosts(c *gin.Context) {
labels := models.GetPosts() // 使用在模板中书写的方法
c.JSON(http.StatusOK, gin.H{
"status": 0,
"data": labels,
})
}

在路由中使用控制器

routers/router.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package routers

import (
"log"
"net/http"

"github.com/gin-gonic/gin"
ctrs "github.com/zachrey/blog/controllers"
)

// LoadRouters 初始化router
func LoadRouters(router *gin.Engine) {
loadRouters(router)
}

func loadRouters(router *gin.Engine) {
// 这里测试根路由
/*
控制器函数会接收一个`gin.Context`类型的指针,这个指针包含http的请求和响应信息和操作方法。
*/
router.GET("/", func(c *gin.Context) {
post := models.GetPostByID(1)
log.Println("@@ post", post)
// 返回一个json格式的数据
c.JSON(http.StatusOK, gin.H{
"Status": 0,
"data": post,
})
})
// 路由控制函数,我们全部放在controllers目录下
router.GET("/get-posts", ctrs.GetPosts)

// ...... 很多很多路由。。。
}

现在我们来访问localhost:8888/get-posts,查看返回的json数组。

最后

  该项目示例已经写完放在github上了,这第二篇,用来介绍配置路由和使用xorm操作数据库。欢迎讨论或者留言,也可以在我的github上克隆项目直接跑着看看。之后继续更新,中间遇到的问题和一些解决办法。