良许Linux教程网 干货合集 Gorilla Mux 和 GORM 的使用方法

Gorilla Mux 和 GORM 的使用方法

本文利用 Go 语言中非常实用的 Gorilla Mux 和 GORM 库、结合分布式 CockroachDB 数据库编写了一个简易的图书的 Restful API,最后通过 Apifox 测试工具验证了服务器 API 的正确。学习了 CockroachDB 数据的安装,了解到 Gorilla Mux 和 GORM 的使用方法。

一、前言

本文将使用功能强大的 Gorilla Mux、GORM 和 CockroachDB 编写可维护 RESTful API。利用到的 Go 语言相关技术有:

Gorilla/Mux:功能强大的 URL 路由器和调度组件。

CockroachDB:开源,云原生分布式 SQL 数据库系统。

GORM:神奇的 ORM 库。

运行环境:

Ubuntu 18.04.6 LTS。

开发工具:Visual Studio Code。

测试工具:APIfox:Apifox = Postman + Swagger + Mock + JMeter。

二、CockroachDB 介绍

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

CockrocreDB 是一个云原生分布式 SQL 数据库,旨在构建,扩展和管理现代数据密集型应用程序。

官方介绍翻译如下:

CockroachDB 是一个分布式关系型数据库,建立在事务性和强一致性键值存储之上,具有水平扩展、高可用、支持强一致性 ACID 事务隔离级别的特点,并提供统一的 SQL API 用于结构化、操作和查询数据。

简单来说,CockroachDB 充分利用了上一代数据库系统的优势、SQL 的强大能力以及关系数据模型和现代云原生法则,成为了一个与其他基于 SQL 的事务型数据库广泛兼容的数据库系统。

CockroachDB 对 Go 也有很好的支持,比如 pgx、pg、GORM 和 upper/db。

1、下载安装

针对最新版的 CockroachDB Linux 下载,点此处 可以看官方的教程写的很详细,这里本文将跟着照做一次。(选择其他系统,同理)。

下载适用于 Linux 的 CockroachDB 包和其支持库,并将二进制文件复制到您的 PATH 中,以便您可以从任何 shell 执行 cockroach 命令

curl https://binaries.cockroachdb.com/cockroach-v22.1.3.linux-amd64.tgz | tar -xz && sudo cp -i cockroach-v22.1.3.linux-amd64/cockroach /usr/local/bin/

如图所示:

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法
Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

CockroachDB 使用GEOS 库的定制版本。默认情况下,CockroachDB 在/usr/local/lib/cockroach 或 CockroachDB 二进制文件当前目录的lib 子目录中查找外部链接库。 所以,您可以将二进制文件复制到您的路径中,以便您可以从任何目录执行 Cockroach 命令

sudo cp -R cockroach-v22.1.3.linux-amd64/* /usr/local/bin

确保刚刚安装的 cockroach 已经成功安装:

which cockroach
Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法
Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

启动使用启动临时本地内存集群,使用cockroach demo 命令:

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法
Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

如果能看到上图,说明 CockroachDB 安装成功,恭喜~

2、使用本地集群

官方提供两种方式利用 GORM 使用 CockroachDB:一种是 CockroachDB Serverless(测试阶段),另一种是使用本地集群。

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法
Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法
cockroach start-single-node --advertise-addr 'localhost' --insecure

通过增加 –insecure 参数启动了一个不安全的单节点群集。

记录下 SQL Shell 中欢迎文本中以下连接信息:

CockroachDB node starting at 2022-07-14 13:21:35.179273246 +0000 UTC (took 1.6s)
build:               CCL v22.1.3 @ 2022/07/11 14:04:38 (go1.17.11)
webui:               http://localhost:8080
sql:                 postgresql://root@localhost:26257/defaultdb?sslmode=disable
sql (JDBC):          jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable&user=root
RPC client flags:    cockroach  --host=localhost:26257 --insecure
logs:                /home/yuzhou/cockroach-data/logs
temp dir:            /home/yuzhou/cockroach-data/cockroach-temp2801178939
external I/O path:   /home/yuzhou/cockroach-data/extern
store[0]:            path=/home/yuzhou/cockroach-data
storage engine:      pebble
clusterID:           43919fea-32cd-48f9-b585-713731d43ee9
status:              restarted pre-existing node
nodeID:              1

其中,postgresql://root@localhost:26257/defaultdb?sslmode=disable ,通过 SQL 连接字符串连接我们的 CockroachDB 集群中。

PS:这条信息需要加入到后续的数据库连接 datebase.go 文件中,请注意。

三、项目介绍

1、项目功能

本文创建一个应用是一个简单的 RESTful API 服务器:线上书店,它将公开书籍的访问和操作,主要包括如下功能:

创建一本书籍

获取书籍清单

获取一本书籍信息

更新已有书籍信息

删除一本书籍

2、API 接口规范

为了实现上述的功能,我们的应用需要提供给外界如下的 API 接口规范:

创建一本书籍:通过/book 响应有效的 POST 请求。

获取书籍清单:通过/books 响应有效的 GET 请求。

获取一本书籍:通过/book/{id} 响应对应的 GET 请求。

更新一本书籍:通过/book/{id} 响应对应的 PUT 请求。

删除一本书籍:通过/book/{id} 响应对应的 DELETE 请求。

通过 {id} 能够有效确定某本书籍。

3、项目结构

本文将创建一个非常简单的应用程序结构,这是本文使用的 mybook 应用的项目结构:

.
├── go.mod
├── go.sum
├── handlers.go
├── main.go
└── model
   ├── database.go
   └── model.go

4、安装项目依赖

安装 go get -u github.com/gorilla/mux,如下。

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法
Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

安装 go get -u gorm.io/gorm。

安装 go get -u gorm.io/driver/postgres。

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法
Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

四、应用功能设计

首先创建一个 mybook 的目录(应用文件夹),然后使用 go mod init mybook。

接着在其中创建我们的 model 文件夹,接下来,在 model 文件夹下新建一个 model.go 文件。

1、model.go

我们需要设计出 book 模型,这里即将使用 GORM 进行创建,编写我们的 model.go 函数:

package model

import (
   "gorm.io/gorm"
)
type Book struct {
   gorm.Model
   ID          string  `json:"id"`
   Name        string  `json:"name"`
   Author      string  `json:"author"`
   Description string  `json:"description"`
   Price       float64 `json:"price"`
   Category    string  `json:"category"`
}

如上所示,书籍的结构体中进行简单设计包含 id(ID)、书名(Name)、作者(Author)、书籍描述(Description)、价格(Price)和类别(Category)。

2、database.go

该程序将创建数据库连接,需要使用到 postgresql://root@localhost:26257/defaultdb?sslmode=disable 传入到 gorm.Open() 的连接参数中,代码如下:

package model
import (
   "log"
   "time"
   "gorm.io/driver/postgres"
   "gorm.io/gorm"
)
func SetupDB() (*gorm.DB, error) {
   dsn := "postgresql://root@localhost:26257/defaultdb?sslmode=disable"
   db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
   if err != nil {
       log.Fatal("can't connect to database", err)
   }
   var now time.Time
   db.Raw("SELECT NOW()").Scan(&now)
   log.Println(now)
   if err = db.AutoMigrate(&Book{}); err != nil {
       log.Println(err)
   }
   return db, err
}

3、handler.go

回到 mybook 文件夹下,创建 handler.go :

package main
import (
   "encoding/json"
   "net/http"
   "mybook/model"
   "github.com/gorilla/mux"
   "gorm.io/gorm"
)
type Server struct {
   db *gorm.DB
}
type UpdateBook struct {
   Price       float64 `json:"price"`
   Description string  `json:"decription"`
   Category    string  `json:"category"`
}
func NewServer(db *gorm.DB) *Server {
   return &Server{db: db}
}
func (s *Server) RegisterRouter(router *mux.Router) {
   router.HandleFunc("/books", s.getBooks)
   router.HandleFunc("/book/{id}", s.getBook).Methods("GET")
   router.HandleFunc("/book", s.createBook).Methods("POST")
   router.HandleFunc("/book/{id}", s.updateBook).Methods("PUT")
   router.HandleFunc("/book/{id}", s.deleteBook).Methods("DELETE")
}
func (s *Server) getBooks(w http.ResponseWriter, r *http.Request) {
   w.Header().Set("Content-Type""application/json;charset=UTF-8")
   var books []model.Book

   if err := s.db.Find(&books).Error; err != nil {
       http.Error(w, err.Error(), http.StatusInternalServerError)
       return
   }
   w.WriteHeader(http.StatusOK)
   json.NewEncoder(w).Encode(books)
}
func (s *Server) createBook(w http.ResponseWriter, r *http.Request) {
   w.Header().Set("Content-Type""application/json; charset=UTF-8")
   var book model.Book
   if err := json.NewDecoder(r.Body).Decode(&book); err != nil {
       http.Error(w, err.Error(), http.StatusInternalServerError)
       return
   }
   newBook := model.Book{Price: book.Price, Description: book.Description, Category: book.Category}
   if err := s.db.Create(newBook).Error; err != nil {
       http.Error(w, err.Error(), http.StatusInternalServerError)
       return
   }
   w.WriteHeader(http.StatusOK)
   json.NewEncoder(w).Encode(newBook)
}
func (s *Server) getBook(w http.ResponseWriter, r *http.Request) {
   w.Header().Set("Content-Type""application/json; charset=UTF-8")
   var book model.Book
   vars := mux.Vars(r)
   id := vars["id"]

   if err := s.db.Where("id = ?", id).First(&book).Error; err != nil {
       http.Error(w, err.Error(), http.StatusNotFound)
       return
   }
   w.WriteHeader(http.StatusOK)
   json.NewEncoder(w).Encode(book)
}
func (s *Server) updateBook(w http.ResponseWriter, r *http.Request) {
   w.Header().Set("Content-Type""application/json; charset=UTF-8")
   var updateBook UpdateBook
   var book model.Book
   vars := mux.Vars(r)
   id := vars["id"]
   if err := json.NewDecoder(r.Body).Decode(&updateBook); err != nil {
       http.Error(w, err.Error(), http.StatusInternalServerError)
       return
   }
   if err := s.db.Where("id = ?", id).First(&book).Error; err != nil {
       http.Error(w, err.Error(), http.StatusNotFound)
       return
   }
   if err := s.db.Model(&book).Updates(&model.Book{
       Price:       updateBook.Price,
       Description: updateBook.Description,
       Category:    updateBook.Category}).Error; err != nil {
       http.Error(w, err.Error(), http.StatusInternalServerError)
       return
   }
   w.WriteHeader(http.StatusOK)
   json.NewEncoder(w).Encode(book)
}
func (s *Server) deleteBook(w http.ResponseWriter, r *http.Request) {
   w.Header().Set("Content-Type""application/json; charset=UTF-8")
   var book model.Book
   vars := mux.Vars(r)
   id := vars["id"]
   if err := s.db.Where("id = ?", id).First(&book).Error; err != nil {
       http.Error(w, err.Error(), http.StatusNotFound)
       return
   }
   if err := s.db.Delete(&book).Error; err != nil {
       http.Error(w, err.Error(), http.StatusInternalServerError)
       return
   }
   w.WriteHeader(http.StatusOK)
   json.NewEncoder(w).Encode("Book Deleted Successfully!")
}

4、main.go

在 main.go 中,我们初始化数据库,创建一个路由器实例,将变量 db 作为参数传递给我们的服务器初始化,然后将路由器实例作为参数传递给方法 registryRouter()。然后,我们使用侦听器来运行服务器。

package main
import (
   "log"
   "net/http"

   "github.com/gorilla/mux"

   "mybook/model"
)
func main() {
   db, err := model.SetupDB()
   if err != nil {
       log.Println("Failed setting up database")
   }
   router := mux.NewRouter()
   server := NewServer(db)
   server.RegisterRouter(router)
   log.Fatal(http.ListenAndServe(":8000", router))
}

当写完所有的程序后,运行 go run . 命令,启动成功如下:

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

此时,运行 cockcoach sql 进入数据库命令行,然后运行 show tables; 命令,可以看到在默认数据库 defaultdb 中已经生成一个 books 数据库表(与我们的模型 books 同名),如下所示:

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

我们执行 select * from books 查看我们生成的表信息:

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

可以看到已经生成了我们定义的字段 id、name、author、description、price、category 以外,GORM 还默认帮忙增加了 created_at (创建时间)、updated_at(更新时间)和 deleted_at(删除时间)三个字段。

五、API 测试

为了方便我们测试这个 book 应用的 API 功能正常,我们将利用 APIfox 工具来进行测试。先在数据库中新增一条记录,如下:

INSERT INTO books (id, name, author, description, price, category)
VALUES(1, 'Go程序设计语言(英文版)''艾伦A.A.多诺万 (Alan A.A.Donovan) / 布莱恩W.柯尼汉 (Brian W.Kemighan)''被誉为 Go 语言圣经的书,非常值得一读', 79.00, 'Golang');
Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

获取书籍清单:/books测试。

插入成功,我们访问后台 http://127.0.0.1:8000/books 路径,可以看到如下成功,说明获取书籍清单的 API 是成功的,恭喜。

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

接下来为了测试,下载 Linux 版本的 Apifox 帮助我们快速测试其他接口。

获取一本书籍:/book/1 测试。

Gorilla Mux 和 GORM 的使用方法Gorilla Mux 和 GORM 的使用方法

其他接口测试类似。

总结

本文利用 Go 语言中非常实用的 Gorilla Mux 和 GORM 库、结合分布式 CockroachDB 数据库编写了一个简易的图书的 Restful API,最后通过 Apifox 测试工具验证了服务器 API 的正确。学习了 CockroachDB 数据的安装,了解到 Gorilla Mux 和 GORM 的使用方法。

显然本文还是有很多不足,比如并没有充分利用到 CockroachDB 数据库的分布式特性,而且没有为 API 编写测试代码,测试并不一定完善,这些都可以溜给读者一些优化思路。

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部