Go语言如何用Gin和Gorm框架快速的搭建一个Web应用

前言

自从学会如何使用Go语言后端开发后,发现每次在做一个项目时前期都在做相同的事情,比如加载配置文件,用gorm连接数据库,连接redis,日志等基础架构,浪费很多时间,本文旨在隐藏这些操作,快速的搭建一个Web后端服务,并达到一个规范化并且高效率的开发目标
Github地址

1 快速开始

1.1 下载common包
#common包 一些常用库的二次封装以及连接mysql、redis、etcd、日志的公共包
go get -u github.com/tmnhs/common
1.2 克隆common示例
git clone https://github.com/tmnhs/common-test.git
1.3 编译项目
cd common-test
make
1.4 运行项目
#脚本运行项目
#脚本语法:./server.sh {start|stop|restart} {testing|production} 
#默认使用testing配置文件
./server.sh restart 

运行成功后可以访问浏览器http://localhost:8089/ping

若得到”pong“,则说明服务启动成功,之后便可以进行二次开发了

2 下面来聊一聊common-test

2.1 目录结构
目录说明
cmd入口函数 ,启动服务
conf配置文件目录
internal业务逻辑目录
haddler路由处理
middlerware路由中间件,比如jwt签名,common包自带跨域,无需配置
model结构体(请求/数据库)
service一些业务逻辑服务
2.2 cmd入口函数(启动服务)
func main() {
  	//参数为需要启动的服务(etcd/mysql/redis)
    //连接成功后可以通过dbclient.GetMysqlDB(),etcdClient.GetEtcd(),redisclient.GetRedis()获取对应的client
    //通过logger.GetLogger()获取日志处理器
    //通过common.GetConfigModels()获取配置文件的信息
	srv, err := server.NewApiServer(server.WithEtcd(),server.WithMysql(),server.WithRedis())
	if err != nil {
		logger.GetLogger().Error(fmt.Sprintf("new api server error:%s", err.Error()))
		os.Exit(1)
	}
	// 注册路由
	srv.RegisterRouters(handler.RegisterRouters)

	// 建表,当然,如果不需要可以直接注释掉
	err = service.RegisterTables(dbclient.GetMysqlDB())
	if err != nil {
		logger.GetLogger().Error(fmt.Sprintf("init db table error:%#v", err))
	}
	err = srv.ListenAndServe()
	if err != nil {
		logger.GetLogger().Error(fmt.Sprintf("startup api server error:%v", err.Error()))
		os.Exit(1)
	}
	os.Exit(0)
}

2.3 配置文件

配置文件在conf目录下,支持测试和生产两种环境,支持json、yaml、ini三种配置文件

├── conf
|     ├── production                #生产环境,支持json、yaml、ini三种配置文件
|     |          └── main.json
|     └── testing
|                └── main.json      #测试环境,支持json、yaml、ini三种配置文件

配置文件示例(测试环境json格式)

{
  "mysql": {
    "path": "127.0.0.1",
    "port": "3306",
    "config": "charset=utf8mb4&parseTime=True&loc=Local",
    "db-name": "common-test",
    "username": "",
    "password": "",
    "max-idle-conns": 100,
    "max-open-conns": 100,
    "log-mode": "info",
    "log-zap": false
  },
  "redis": {
    "addr": "127.0.0.1:6379",
    "password": "",
    "db": 0
  },
  "system": {
    "env": "testing",
    "addr": 8089,
    "version": "v1.0.2"
  },
  "etcd": {
    "endpoints": [
      "http://127.0.0.1:2379"
    ],
    "username": "",
    "password": "",
    "dial-timeout": 2,
    "req-timeout": 5
  },
  "email": {
    "port": 465,
    "from": "test@qq.com",
    "host": "smtp.qq.com",
    "is-ssl": true,
    "secret": "test",
    "nickname": "common-test",
    "to": [
      "test@test.mobi"
    ]
  },
  "webhook": {
    "url": "url",
    "kind": "feishu"
  },
  "log": {
    "level": "debug",
    "format": "console",
    "prefix": "[common]",
    "director": "logs",
    "showLine": false,
    "encode-level": "LowercaseLevelEncoder",
    "stacktrace-key": "stacktrace",
    "log-in-console": true
  }
}
2.4 配置路由(router.go)

func RegisterRouters(r *gin.Engine) {

	configRoute(r)

	configNoRoute(r)
}

func configRoute(r *gin.Engine) {

	hello := r.Group("/ping")
	{
		hello.GET("", func(c *gin.Context) {
			c.JSON(200, "pong")
		})
	}

	base := r.Group("")
	{
		base.POST("register", defaultUserRouter.Register)
		base.POST("login", defaultUserRouter.Login)
	}

	user := r.Group("/user")
	user.Use(middlerware.JWTAuth())
	{
		user.POST("del", defaultUserRouter.Delete)
		user.POST("update", defaultUserRouter.Update)
		user.POST("change_pw", defaultUserRouter.ChangePassword)
		user.GET("find", defaultUserRouter.FindById)
		user.POST("search", defaultUserRouter.Search)
	}
}

func configNoRoute(r *gin.Engine) {
	/*	r.LoadHTMLGlob("./dist/*.html") // npm打包成dist的路径
		r.StaticFile("favicon.ico", "./dist/favicon.ico")
		r.Static("/css", "./dist/css")
		r.Static("/fonts", "./dist/fonts")
		r.Static("/js", "./dist/js")
		r.Static("/img", "./dist/img")
		r.StaticFile("/", "./dist/index.html") // 前端网页入口页面*/
}

3. 可能出现的问题

如果引入包并且go mod tidy 出现以下错误时

go: finding module for package google.golang.org/grpc/naming
github.com/tmnhs/common-test/cmd imports
        github.com/tmnhs/common/server imports
        github.com/tmnhs/common/etcdclient imports
        github.com/coreos/etcd/clientv3 tested by
        github.com/coreos/etcd/clientv3.test imports
        github.com/coreos/etcd/integration imports
        github.com/coreos/etcd/proxy/grpcproxy imports
        google.golang.org/grpc/naming: module google.golang.org/grpc@latest found (v1.50.1), but does not contain package google.golang.org/grpc/naming

可以在go.mod中添加以下一行(这个报错和etcd连接的第三方库有版本冲突)

replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 GORM 框架中,可以使用 Go 语言的协程(goroutine)来实现并发操作。下面是一个示例: ```go package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type User struct { ID int Name string } func main() { db, err := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { panic("failed to connect database") } defer db.Close() // 创建一个协程来执行查询操作 go func() { var user User db.First(&user, 1) fmt.Println(user) }() // 创建另一个协程来执行插入操作 go func() { newUser := User{Name: "Alice"} db.Create(&newUser) }() // 等待一段时间,以确保协程有足够的时间执行 time.Sleep(time.Second) // 查询所有用户 var users []User db.Find(&users) fmt.Println(users) } ``` 在上面的示例中,我们使用了两个协程来执行数据库操作。第一个协程执行了查询操作,第二个协程执行了插入操作。通过使用协程,我们可以并发地执行这些操作,提高程序的性能。 需要注意的是,在使用协程时,我们需要确保数据库连接是线程安全的。在上面的示例中,我们使用了 `defer db.Close()` 来关闭数据库连接,以确保资源的释放。另外,为了确保协程有足够的时间执行,我们使用了 `time.Sleep(time.Second)` 来进行等待。 当然,具体的实现方式可能因为业务需求的不同而有所差异,上述示例仅供参考。在实际使用中,你可以根据自己的需求来选择合适的并发方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值