Gone框架介绍17 - 创建一个可运行在生产环境的Web项目

gone是可以高效开发Web服务的Golang依赖注入框架
github地址:https://github.com/gone-io/gone
文档原地址:https://goner.fun/zh/guide/auto-gen-priest.html
请帮忙在github上点个 ⭐️吧,这对我很重要 ;万分感谢!!

文章目录

  • Web+MySQL
    • 安装gone辅助工具
    • 使用gone命令创建项目
    • 编译并运行
    • 测试接口
    • 项目简单介绍
      • 目录结构
      • 项目特点
      • 部分代码讲解
      • HTTP 注入
      • 请求处理函数参数

Web+MySQL

在本文中,我将演示如何创建一个可运行在生产环境的Web项目,并对项目做简单的介绍。项目的使用MySql作为数据库,使用docker-compose管理容器。

安装gone辅助工具

go install github.com/gone-io/gone/tools/gone@latest

关于gone命令,更多参考:gone辅助工具

使用gone命令创建项目

gone create -t web+mysql web-mysql-docker

上面命令会在当前目录中创建一个名为web-mysql-docker的目录。

编译并运行

假设你已经安装了make;如果没有安装请先安装,参考:安装make。
建设你已经安装了dockerdocker compose;如果没有,参考: https://docs.docker.com/engine/install/。

执行系列命令

# 进入项目目录
cd web-mysql-docker# 生成Priest函数:https://goner.fun/zh/guide/auto-gen-priest.html
make gone# 启动MySql服务
docker compose up -d mysql# 编译并运行
make run

日志打印如下:

➜  web-mysql-docker make run
make gone
make install-gone
go install github.com/gone-io/gone/tools/gone@latest
go mod tidy
go generate ./...
go run cmd/server/main.go
2024-05-14 12:42:03.574|INFO|Init|Revive github.com/gone-io/gone/heaven
2024-05-14 12:42:03.574|INFO|Init|Revive github.com/gone-io/gone/cemetery
2024-05-14 12:42:03.574|INFO|Init|Revive github.com/gone-io/gone/goner/tracer/tracer
2024-05-14 12:42:03.574|INFO|Init|Revive github.com/gone-io/gone/goner/logrus/logger
2024-05-14 12:42:03.574|INFO|Init|Revive github.com/gone-io/gone/goner/config/config
2024-05-14 12:42:03.574|INFO|Init|Revive github.com/gone-io/gone/goner/config/propertiesConfigure
2024-05-14 12:42:03.574|INFO|Init|Revive github.com/gone-io/gone/goner/logrus/logger
2024-05-14 12:42:03.574|INFO|Init|==>Use Env: local
2024-05-14 12:42:03.574|WARNING|Init|properties: /var/folders/jv/rn9b7nhs2ls1n1j_lqj005r80000gn/T/go-build521033176/b001/exe/config/default.properties not found. skipping
2024-05-14 12:42:03.574|WARNING|Init|properties: /var/folders/jv/rn9b7nhs2ls1n1j_lqj005r80000gn/T/go-build521033176/b001/exe/config/local.properties not found. skipping
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/config/config
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/config/propertiesConfigure
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/xorm/engine
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/cmux/server
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/gin/proxy
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/gin/router
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/gin/sysProcessor
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/gin/responser
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/gin/server
2024-05-14 12:42:03.575|INFO|Init|Revive github.com/gone-io/gone/goner/gin/httpInjector
2024-05-14 12:42:03.575|INFO|Init|Revive web-mysql/internal/controller/demoController
2024-05-14 12:42:03.575|INFO|Init|Revive web-mysql/internal/middleware/AuthorizeMiddleware
2024-05-14 12:42:03.575|INFO|Init|Revive web-mysql/internal/middleware/PubMiddleware
2024-05-14 12:42:03.575|INFO|Init|Revive web-mysql/internal/module/demo/db
2024-05-14 12:42:03.575|INFO|Init|Revive web-mysql/internal/module/demo/demoService
2024-05-14 12:42:03.575|INFO|Init|Revive web-mysql/internal/router/authRouter
2024-05-14 12:42:03.575|INFO|Init|Revive web-mysql/internal/router/pubRouter
[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] GET    /api/demo/show            --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func5 (8 handlers)
[GIN-debug] GET    /api/demo2/show           --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func5 (7 handlers)
[GIN-debug] GET    /api/demo2/error          --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func5 (7 handlers)
[GIN-debug] GET    /api/demo2/echo           --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func5 (7 handlers)
[GIN-debug] GET    /api/inject-query         --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] GET    /api/inject/:key          --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] POST   /api/inject-http-body     --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] GET    /api/inject-http-struct   --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] POST   /api/users                --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] GET    /api/users                --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] GET    /api/users/page           --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] GET    /api/users/:id            --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] PUT    /api/users/:id            --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
[GIN-debug] DELETE /api/users/:id            --> github.com/gone-io/gone/goner/gin.(*proxy).Proxy.(*proxy).proxyOne.func8 (7 handlers)
2024-05-14 12:42:03.576|INFO|/Users/jim/go/pkg/mod/github.com/gone-io/gone@v0.3.1/goner/gin/server.go:46||Server Listen At :8080
2024-05-14 12:42:03.576|INFO|/Users/jim/go/pkg/mod/xorm.io/xorm@v1.3.2/log/logger_context.go:90||PING DATABASE mysql
2024-05-14 12:42:03.585|INFO|/Users/jim/go/pkg/mod/github.com/gone-io/gone@v0.3.1/cemetery.go:329||Revive [Anonymous Goner]
2024-05-14 12:42:03.585|INFO|/Users/jim/works/gone-io/web-app/demo/web-mysql-docker/cmd/server/main.go:28||before start

测试接口

我这里使用Goland内置Http Request插件测试。
使用Goland打开项目,打开文件tests/api/user.http,选择dev环境运行,如下:
请添加图片描述

执行结果:
请添加图片描述

项目简单介绍

目录结构

├── Dockerfile
├── Makefile
├── README.md
├── cmd
│   └── server
│       └── main.go #项目main方法所在文件
├── config          #项目配置目录
│   ├── default.properties #默认配置
│   ├── dev.properties     #开发环境配置
│   ├── local.properties   #本地环境配置
│   └── prod.properties    #生产环境配置
├── docker-compose.yaml    # docker-compose,定义了mysql 和 web 两个容器
├── go.mod
├── internal
│   ├── controller         #Controller
│   │   └── demo_ctr.go
│   ├── interface          #接口目录
│   │   ├── domain         #领域模型
│   │   │   ├── demo.go
│   │   │   ├── page.go
│   │   │   └── user.go
│   │   ├── entity         #实体模型
│   │   │   └── User.go
│   │   └── service        #服务接口
│   │       └── i_demo.go  #一个文件一般只放一个接口,文件名以`i_开口`,接口名以 `I`卡头,比如`IDemo`
│   ├── master.go
│   ├── middleware         #中间件目录,可以定义鉴权等统一处理逻辑
│   │   ├── authorize.go
│   │   └── pub.go
│   ├── module             #模块目录
│   │   └── demo           #demo模块
│   │       ├── db.go      #demo目录的数据库接口的实现
│   │       ├── demo_svc.go #demo Service,实现了`service.IDemo`接口
│   │       ├── error.go    # 当前目录错误码定义
│   │       └── i_db.go    #demo目录的数据库接口
│   ├── pkg                #公共工具目录
│   │   └── utils
│   │       └── error.go
│   ├── priest.go         #gone create 创建是没有该文件,运行 `make gone`生成的
│   └── router            #路由目录
│       ├── auth_router.go # 定义了需要鉴权的的路由组
│       └── pub_router.go  # 定义了无需鉴权的的路由组
├── scripts                # 脚本目录,用于存放一些脚本
│   └── mysql
│       └── initdb.d       #mysql initdb.d目录,docker-compose中定义的mysql首次启动时 会执行该目录下所有sql文件
│           └── user.sql
└── tests                  #集成测试目录└── api                #接口测试目录├── demo.http├── http-client.env.json└── user.http

项目特点

  • 开箱可用,无需额外配置直接可以运行
  • 生成了Dockerfile,方便部署到各种容器环境
  • 使用Makefile整合了gone、go、docker、docker compose等命令
  • 自动生成Priest函数,使开发更顺畅
  • 使用了gone框架,引入了依赖注入
  • 使用接口解耦
  • 支持分环境编写配置
  • 集成了MySQL数据库

部分代码讲解

//...// demo数据 user 的增删改查,挂载到authRouter只为方便演示ctr.pubRouter.Group("/users").POST("", func(in struct {//Body注入,根据contentType将HTTP正文解析为一个结构体,支持json、xml、form-data、x-www-form-urlencoded 等 contentTypereq *domain.User `gone:"http,body"`}) error {return ctr.demoSvc.CreateUser(in.req)}).GET("", func() (any, error) {return ctr.demoSvc.ListUsers()}).GET("/page", func(in struct {query domain.PageQuery `gone:"http,query"` //Query注入}) (any, error) {return ctr.demoSvc.PageUsers(in.query)}).GET("/:id", func(in struct {id int64 `gone:"http,param"`              //Url参数注入,将注入路由上定义的`:id`}) (any, error) {return ctr.demoSvc.GetUserById(in.id)}).PUT("/:id", func(in struct {id  int64        `gone:"http,param"` //Url参数注入,将注入路由上定义的`:id`req *domain.User `gone:"http,body"`  //Body注入}) error {return ctr.demoSvc.UpdateUserById(in.id, in.req)}).DELETE("/:id", func(in struct {id int64 `gone:"http,param"` //Url参数注入,将注入路由上定义的`:id`}) error {return ctr.demoSvc.DeleteUser(in.id)})
//...

上面代码截取于internal/controller/demo_ctr.go文件。

HTTP 注入

可以看到,Gone在路由处理函数上也支持了依赖注入;注入的方式是在使用一个匿名结构体作为处理函数的入参,并给结构体属性做特殊标记。
上面代码用的注入标签:

  • gone:"http,body",Body注入,根据contentType将HTTP正文解析为一个结构体,支持json、xml、form-data、x-www-form-urlencoded 等 contentType,要求被注入的结构体属性的数据类型为结构体或者结构体指针
  • gone:"http,query",Query注入,被注入的结构体属性的数据类型可以为结构体结构体指针字符串Number(int、uint、float64 …)字符串或Number的Slice
  • gone:"http,param",Url参数注入,将注入路由上定义的参数;要求被注入的结构体属性的数据类型为字符串Number类型

下面对Query注入,句几个例子:

type Q struct {Page int `form:"page"` //使用form标签指定参数名为page,默认是属性名PagePageSize int `form:"pageSize"`//使用form标签指定参数名为pageSize,默认是属性名PageSize
}func handle(in struct{page int `gone:"http,query"` //未指定query参数名,去属性名为keythePage int `gone:"http,query=page"`//指定query参数名为pagesize int64 `gone:"http,query=pageSize` //指定query参数名为pageSizeq *Q `gone:"http,query"` //被注入类型为一个结构体keywords []string `gone:"http,query=keywords"` //使用数组结构,允许Query参数出现多次oneKeyword string `gone:"http,query=keywords"` //不使用数组,只获取Query中的第一个keyword
}){//todo
}

假设某个请求的Query为:?page=10&pageSize=20&keywords=today&keywords=weather,使用上面handle处理请求,参数in的值如下:

  • in.page = 10
  • in.thePage = 10
  • in.size = 20
  • in.q = {Page = 10, PageSize = 20}
  • in.keywords = [today, weather]
  • in.oneKeyword = today

另外,处理函数还支持注入一些特殊结构体或指针(推荐使用指针):

  • gone.Content 请求上下文
  • http.Request Http请求
  • http.Header 请求头
  • url.Url url

框架还支持更多的注入标签和类型,请参考文档http 注入说明

请求处理函数参数

请求处理函数返回参数可以为如下几种形式:

  1. 不返回参数
  2. 返回一个非error的参数
  3. 返回数据和error

上一篇:Gone框架介绍16 - 自动生成Priest

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/838136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Unity-Timeline进度条显示与拖动】

利用Unity 自带的Timeline 可轻松实现场景的巡检漫游效果, 基本使用参考以下链接: Unity中的Timeline Unity学习笔记——TimeLine的简单使用方法(一) 这里主要介绍如何通过滑动条控制播放的进度,效果图附上。 话不多说&#xff…

Minecraft 我的世界服务器Java版开服联机教程

本教程使用Paper核心开服 1、进入控制面板 1.2、第一次购买服务器会安装游戏端,大约5分钟左右,如果长时间处于安装状态请联系客服 2、开启服务器 2.1、等待出现同意Minecraft EULA 协议时,点击“我接受” 2.2、等待running出现服务器就打开了…

【C++】 C++ 编写 鸡兔同笼程序

文章目录 “鸡兔同笼”问题是一个经典的数学问题,要求根据总头数和总腿数来计算鸡和兔的数量。假设鸡有 2 条腿,兔有 4 条腿。可以通过以下步骤求解这个问题: 1 .设鸡的数量为 x,兔的数量为 y。2.根据题意,我们有以下…

vue 微信小程序 uniapp 微信头像上传裁剪功能

效果如图&#xff1a; 操作流程&#xff1a; 个人中心–点击设置头像–选择图片-裁剪–选取–上传 template <view class"meilan" style"position: relative;"><u-row justify"space-between"><u-col span"3">设置头…

nn.BatchNorm中affine参数的作用

在PyTorch的nn.BatchNorm2d中&#xff0c;affine参数决定是否在批归一化&#xff08;Batch Normalization&#xff09;过程中引入可学习的缩放和平移参数。 BN层的公式如下&#xff0c; affine参数决定是否在批归一化之后应用一个可学习的线性变换&#xff0c;即缩放和平移。具…

冒险岛vcruntime140_1.dll无法继续执行代码要怎么处理?教你一键修复vcruntime140_1.dll

当你在玩着冒险岛的时候&#xff0c;突然弹出一个vcruntime140_1.dll无法继续执行代码&#xff0c;这时候你是不是一脸懵逼&#xff1f;不知道怎么去解决&#xff1f;其实不需要担心&#xff0c;这是一个小问题&#xff0c;vcruntime140_1.dll文件是一个非常常用的dll文件&…

STM32最小系统

组件描述主控芯片STM32F103C8T6等时钟源外部晶体振荡器或者陶瓷谐振器&#xff0c;通常在4MHz到25MHz之间复位电路包括复位按钮和复位电路&#xff0c;用于将单片机置于初始状态电源电路提供稳定的电压&#xff0c;通常为3.3V或5V编程/调试接口SWD接口或JTAG接口等&#xff0c;…

JavaScript基础知识强化:变量提升、作用域逻辑及TDZ的全面解析

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 ⭐️ 引言&#x1f3af; 变量提升(Hoisting)&#x1f47b; 暂时性死区&#xff08;Temporal Dead Zone, TDZ&#xff09;解释&#x1f4e6; var声明&#x1f512; let与const声明&#x1f4d6; 函数声明 与 函数表达式函数声…

JavaScript-BOM编程

BOM对象 1 什么是BOM2 window对象的常见属性3 window对象的常见方法4 通过BOM编程控制浏览器行为演示5 通过BOM编程实现会话级和持久级数据存储 1 什么是BOM BOM是Browser Object Model的简写&#xff0c;即浏览器对象模型。 BOM由一系列对象组成&#xff0c;是访问、控制、修…

【网络安全】【Frida实战案例】某图xx付费功能逆向分析(二)

文章目录 一、目标应用二、环境三、步骤1、重打包2、运行打包后apk3、找到签名信息&#xff08;1&#xff09;、查看apk签名信息&#xff08;2&#xff09;、hook Android方法获取apk签名信息&#xff08;3&#xff09;、转为md5验证 4、hook apk签名信息 四、总结五、相关源码…

Learn Next.js(浅全栈)

Learn Next.js 中文教程

Pytorch代码基础—张量

Pytorch代码—张量 Pytorch张量 张量的属性&#xff1a; data&#xff1a;被包装的Tensorgrad&#xff1a;data的梯度grad_fn:创建Tensor的Function&#xff0c;是自动求导的关键requires_grad&#xff1a;指示是否需要梯度isleaf&#xff1a;指示是否是叶子结点&#xff0…

2.4 IDEA开发词频统计项目

文章目录 2.4.1 词频统计准备工作2.4.2 本地模式运行Spark项目2.4.3 集群模式运行Spark项目 2.4.1 词频统计准备工作 2.4.2 本地模式运行Spark项目 2.4.3 集群模式运行Spark项目

Etsy和其他平台的不同之处

Etsy平台每月的访问量大概是3.9亿&#xff0c;活跃用户有近9000万。区别于现在大部分的电商平台都是以快消产品为主&#xff0c;产品竞争激烈&#xff0c;而Etsy平台售卖的定制性原创产品便脱颖而出&#xff0c;更受消费者欢迎。 Etsy可以说是一个线上市场&#xff0c;提供一个…

AI预测福彩3D采取887定位大底=23策略+杀断组+杀组选+杀和尾+杀和值012缩水测试5月15日预测第1弹

昨天与一位玩3D的彩友通过视频直播的形式聊了下&#xff0c;受益匪浅&#xff0c;给我提供了一些比较有价值的建议&#xff0c;比如&#xff0c;对于887的定位策略&#xff0c;方向是没问题的&#xff0c;但是8873的话&#xff0c;还是缺乏一定的命中率&#xff0c;如果88723&a…

静态IP地址:网络通信的稳定之锚

在数字化时代&#xff0c;网络通信是企业运营和个人生活不可或缺的一部分。而在这个过程中&#xff0c;IP地址扮演着至关重要的角色。静态IP地址&#xff0c;作为一种特殊的网络配置&#xff0c;为网络通信提供了稳定性和可靠性。本文将从五个方面深入探讨静态IP地址的重要性、…

二进制部署k8s---下篇

一 master02 节点部署 1 先在master01 添加映射master02 对master02进行环境初始化 3 从 master01 节点上拷贝证书文件、各master组件的配置文件和服务管理文件到 master02 节点 scp -r /opt/etcd/ root192.168.11.12:/opt/ scp -r /opt/kubernetes/ root192.168.11.12:/opt…

贪心算法----最大数

今日题目&#xff1a;leetcode179------点击跳转题目 分析&#xff1a; 要把这些数组组成最大的数&#xff0c;首先我们把数字转化为字符串&#xff0c;根据自定义的排序规则把这些字符串字数排列&#xff0c;再用一个字符串接受这些字符串数字拼接成最大的字符串数字 排序规则…

秋招算法复习——5/15——三数之和

文章目录 问题描述思路分析实现代码分析与总结 问题描述 思路分析 三个之和为零&#xff0c;即a b c 0 &#xff0c;将这个拆解为b c -a &#xff0c;那就变成了两数之和问题。两重指针的模版来解决。 虽然列表中存在重复的数字&#xff0c;但是结果不允许存在重复的组合…

Find My OBD|苹果Find My技术与OBD结合,智能防丢,全球定位

OBD是英文On-Board Diagnostics的缩写&#xff0c;中文翻译为“车载自动诊断系统”。这个系统将从发动机的运行状况随时监控汽车是否尾气超标&#xff0c;一旦超标&#xff0c;会马上发出警示。当系统出现故障时&#xff0c;故障(MIL)灯或检查发动机(Check Engine)警告灯亮&…