拆箱gin框架

参考文档参考文档创建项目gin_grpc目录下写一个入口函数main.go

package main

import "github.com/gin-gonic/gin"

func main() {

r := gin.Default()

r.GET("/ping", func(c *gin.Context) {

c.JSON(200, gin.H{

"message": "pong",

})

})

r.Run() // listen and serve on 0.0.0.0:8080

}

开启gomod go mod init gin_grpc加载依赖 go mod tidy此时我们查看项目下多了一个go.mod文件

目录的配置

有了入口文件,我们再创建一个app目录,用来存放我们的项目代码在app目录下创建一个router目录存放路由,在app目录下创建一个controller存放控制器层的代码在app/router目录下创建api.go,用来注册api相关的路由

package router

import (

"gin_grpc/app/controller"

"github.com/gin-gonic/gin"

)

// UserRouter 用户模块的路由

func UserRouter(r *gin.Engine) {

r.GET("/index", controller.User.Index)

}

// InitRouter 路由注册

func InitRouter(r *gin.Engine) {

// 用户相关的路由注册

UserRouter(r)

}

在app/controller下创建user.go作为user的控制器

package controller

import (

"github.com/gin-gonic/gin"

)

// Controller controller基类

type Controller struct{}

// UserController 继承controller的user

type UserController struct {

Controller

}

// User UserController的变量

var User=UserController{

}

func (t *UserController)Index(c *gin.Context){

c.JSON(200, gin.H{

"message": "pong",

})

return

}

修改一下入口文件main.go,一个是启动gin服务,一个是注册路由

package main

import (

"gin_grpc/app/router"

"github.com/gin-gonic/gin"

)

func main() {

//r:=gin.New()//启动gin服务

r := gin.Default()//Default returns an Engine instance with the Logger and Recovery middleware already attached.

router.InitRouter(r)//注册路由

r.Run("127.0.0.1:8089") // listen and serve on 0.0.0.0:8080

}

至此,一个简易版本的gin部署完毕了。我们继续往下看

配置文件

我们读取mysql,读取redis配置,肯定少不了配置文件 这里,我们使用viper来读取配置文件 相关参考文档 安装vipergo get github.com/spf13/viper 在项目根目录下创建config文件夹,在config下创建base.yaml,因为yaml文件相对来说比json更轻量级

#项目相关配置

app:

name: gin_grpc

debug: true

#数据库相关配置

database:

driver: mysql

host: 127.0.0.1

port: 3306

username: acurd_com

dbname: cms

password: acurd_com

#redis相关配置

redis:

host: 127.0.0.1

port: 6379

在config目录下创建一个config.go,用来加载配置文件

package config

import (

"fmt"

"github.com/fsnotify/fsnotify"

"github.com/spf13/viper"

)

// InitConfig 初始化配置文件

func InitConfig() {

viper.AddConfigPath("./config")

viper.AddConfigPath(".")//多路径查找

viper.SetConfigName("base")

viper.SetConfigType("yaml")

if err := viper.ReadInConfig(); err != nil {

panic(err)

}

//监控并重新读取配置文件

viper.WatchConfig()

viper.OnConfigChange(func(e fsnotify.Event) {

// 配置文件发生变更之后会调用的回调函数

fmt.Println("Config file changed:", e.Name)

})

}

在入口文增加一个init函数,完成对配置文件的初始化

package main

import (

"gin_grpc/app/router"

"gin_grpc/config"

"github.com/gin-gonic/gin"

)

//初始化配置文件

func init() {

config.InitConfig()

}

func main() {

//r:=gin.New()//启动gin服务

r := gin.Default()//Default returns an Engine instance with the Logger and Recovery middleware already attached.

router.InitRouter(r)//注册路由

r.Run("127.0.0.1:8089") // listen and serve on 0.0.0.0:8080

}

gorm的使用

在config/config.go文件中写方法连接MySQL,这里使用gorm在app下创建model目录,在model目录下新建文件model.go

package model

import (

"fmt"

_ "github.com/go-sql-driver/mysql"

"github.com/jinzhu/gorm"

"github.com/spf13/viper"

"log"

)

// Db 用来承接db变量

var Db *gorm.DB

// InitDb 初始化数据库连接

func InitDb()*gorm.DB{

var (

Username = viper.GetString("database.username")

Password = viper.GetString("database.password")

Host = viper.GetString("database.host")

Port = viper.GetInt("database.port")

DbName = viper.GetString("database.dbname")

)

dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", Username, Password, Host, Port, DbName)

fmt.Println(Username)

db, err := gorm.Open("mysql", dsn)

if err != nil {

log.Fatal("数据库连接失败,报错信息"+err.Error())

}

// 设置连接池,空闲连接

db.DB().SetMaxIdleConns(50)

// 打开链接

db.DB().SetMaxOpenConns(100)

// 表明禁用后缀加s

db.SingularTable(true)

// 启用Logger,显示详细日志

db.LogMode(viper.GetBool("app.debug"))

return db

}

在model下继续创建文件blog,用于博文的model

package model

// Blog 定义博文结构体

type Blog struct {

AutoID uint `gorm:"column:auto_id;primary_key;AUTO_INCREMENT"` // ID

ID string `gorm:"column:id;NOT NULL"` // 业务id

Title string `gorm:"column:title;NOT NULL"` // 标题

TitleStyle string `gorm:"column:title_style;NOT NULL"` // 标题样式

Thumb string `gorm:"column:thumb;NOT NULL"` // 缩略图

Keywords string `gorm:"column:keywords;NOT NULL"` // 关键词

Description string `gorm:"column:description;NOT NULL"` // 描述

Content string `gorm:"column:content;NOT NULL"` // 内容

CreateTime uint `gorm:"column:create_time;default:0;NOT NULL"` // 创建时间

UpdateTime uint `gorm:"column:update_time;default:0;NOT NULL"` // 更新时间

Author string `gorm:"column:author;NOT NULL"` // 作者

Source string `gorm:"column:source;NOT NULL"` // 来源

Summary string `gorm:"column:summary;NOT NULL"` // 摘要

}

// TableName 标记Blog结构体使用的表名

func (m *Blog) TableName() string {

return "cms_blog"

}

// BlogModel 用来继承model

type BlogModel struct{

}

// GetOne 获取一篇文章

func (m *BlogModel)GetOne(i int)Blog{

var blog Blog

Db.First(&blog,i)

return blog

}

增加一个路由,用来获取文章

// BlogRouter 博客相关路由

func BlogRouter(r *gin.Engine) {

r.GET("/blog/:id", controller.Blog.GetOne)

}

在入口文件中增加对MySQL的初始化

func main() {

//r:=gin.New()//启动gin服务

r := gin.Default()//Default returns an Engine instance with the Logger and Recovery middleware already attached.

model.Db=model.InitDb()

defer model.Db.Close()

router.InitRouter(r)//注册路由

r.Run("127.0.0.1:8089") // listen and serve on 0.0.0.0:8080

}

访问路由

使用grpc完成服务间的调用

grpc的入门的例子,我再之前的文章golang入门微服务 中详细的讲过,这里简单记录一下步骤

定义protobuf文件

//我们定义一个博文的数据结构,

syntax="proto3";

package blog;

option go_package="/Users/zhangguofu/website/gin_grpc/app/proto/gen/go;blog";//生成的go文件存放目录在哪;包名叫什么

message Blog {

uint32 auto_id = 1; // ID

string id = 2; // 业务id

string title = 4; // 标题

string title_style = 5; // 标题样式

string thumb = 6; // 缩略图

string keywords = 7; // 关键词

string description = 8; // 描述

string content = 9; // 内容

uint32 create_time = 14; // 创建时间

uint32 update_time = 15; // 更新时间

string author = 16; // 作者

string source = 17; // 来源

string summary = 18; // 摘要

}

// 定义blog服务

service BlogInfo{

//定义方法

rpc getBlog(Id) returns(Blog);

}

//定义id的消息类型

message Id{

int64 value=1;

}

在proto文件目录下执行命令 生成pb文件,其中,blog.pb.go中定义了结构体,字段映射等信息,blog_grpc.pb.go中定义了一些和rpc交互的一些方法,包括获取grpc客户端,和我们在protobuf文件中顶一顶

│ ├── proto │ │ ├── blog.proto │ │ └── gen │ │ └── go │ │ └── blog │ │ ├── blog.pb.go │ │ └── blog_grpc.pb.go

gprc服务端实现

接下来我们改造一下,由原来的请求MySQL 改为请求grpc

func (t *BlogController) RpcGetOne(c *gin.Context) {

id := c.Param("id")

id_int, _ := strconv.Atoi(id)

//监听端口

conn, err := grpc.Dial("localhost:9988", grpc.WithInsecure())

if err!=nil {

log.Fatal(err)

}

defer conn.Close()

//取到客户端连接

client:=blog2.NewBlogInfoClient(conn)

//组装结构体

blogId:=new(blog2.Id)

blogId.Value=int64(id_int)

info, _ :=client.GetBlog(context.Background(),blogId)

fmt.Println(id)

c.JSON(200, gin.H{

"message": "success",

"data": info,

})

return

}

gprc服务端实现

接下来我们编写服务端的实现

package main

import (

"context"

"fmt"

"github.com/blog-server/proto/gen/go/blog"

"google.golang.org/grpc"

"log"

"net"

"strconv"

)

type Server struct{

}

/**

* @Description

* @Author 老a技术联盟

* @Date 2023/2/6 11:48

**/

func main() {

listen, err := net.Listen("tcp", "localhost:9988")

if err != nil {

return

}

//创建grpc服务

s:=grpc.NewServer()

blog.RegisterBlogInfoServer(s,Server{})

if err := s.Serve(listen); err != nil {

log.Println("failed to serve...", err)

return

}

}

//继承接口

func (s Server)GetBlog(c context.Context,b *blog.Id) (*blog.Blog, error) {

//从mysql中取数据的过程忽略,直接返回结果

blog:=new(blog.Blog)

blog.Id= strconv.Itoa(int(b.Value))

fmt.Printf("接收到的id是:%d",b.Value)

blog.Author="grpc返回"

return blog,nil

}

重启服务

先启动grpc服务端,在启动客户端然后请求获取一条博文

服务端信息打印其中 pb文件在项目中往往是作为一个包文件被引用的,这样就不会重复拷贝文件到目录

参考链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。