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

news2024/12/22 20:33:47

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 等 contentType
			req *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,默认是属性名Page
    PageSize int `form:"pageSize"`//使用form标签指定参数名为pageSize,默认是属性名PageSize
}

func handle(in struct{
    page int `gone:"http,query"` //未指定query参数名,去属性名为key
    thePage int `gone:"http,query=page"`//指定query参数名为page
    size int64 `gone:"http,query=pageSize` //指定query参数名为pageSize

    q *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.coloradmin.cn/o/1676950.html

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

相关文章

【爬虫之scrapy框架——尚硅谷(学习笔记two)--爬取电影天堂(基本步骤)】

爬虫之scrapy框架--爬取电影天堂——解释多页爬取函数编写逻辑 (1)爬虫文件创建(2)检查网址是否正确(3)检查反爬(3.1) 简写输出语句,检查是否反爬(3.2&#x…

Nginx生产环境最佳实践之配置灰度环境

你好呀,我是赵兴晨,文科程序员。 下面的内容可以说是干货满满建议先收藏再慢慢细品。 今天,我想与大家深入探讨一个我们日常工作中不可或缺的话题——灰度环境。你是否在工作中使用过灰度环境?如果是,你的使用体验如…

flutter开发实战-compute将工作交由isolate处理

flutter开发实战-compute将工作交由isolate处理 最近查看flutter文档时候,看到了compute可以将工作交由isolate处理。通过 Flutter 提供的 compute() 方法将解析和转换的工作移交到一个后台 isolate 中。这个 compute() 函数可以在后台 isolate 中运行复杂的函数并…

Leetcode 第 129 场双周赛题解

Leetcode 第 129 场双周赛题解 Leetcode 第 129 场双周赛题解题目1:3127. 构造相同颜色的正方形思路代码复杂度分析 题目2:3128. 直角三角形思路代码复杂度分析 题目3:3129. 找出所有稳定的二进制数组 I思路代码复杂度分析 题目4:…

JavaScript异步编程——11-异常处理方案【万字长文,感谢支持】

异常处理方案 在JS开发中,处理异常包括两步:先抛出异常,然后捕获异常。 为什么要做异常处理 异常处理非常重要,至少有以下几个原因: 防止程序报错甚至停止运行:当代码执行过程中发生错误或异常时&#x…

数字人解决方案——ID-Animator可保持角色一致生成视频动画

一、引 言 个性化或自定义生成在图像和视频生成领域是一个不断发展的研究方向,尤其是在创建与特定身份或风格一致的内容方面。您提到的挑战和解决方案为这一领域提供了有价值的见解: 训练成本高:这是一个普遍问题,因为个性化生成…

手机触控面板中应用的电容式触摸芯片

手机触控屏(Touch panel)又称为触控面板,是个可接收触头等输入讯号的感应式液晶显示装置,当接触了屏幕上的图形按钮时,屏幕上的触觉反馈系统可根据预先编程的程式驱动各种连结装置,可用以取代机械式的按钮面…

【AI】DeepStream(03):deepstream_test1_app

1、简介 deepstream-test1:演示各种 DeepStream 插件构建 GStreamer 管道。从文件中获取视频、解码、批处理,然后进行对象检测,最后在屏幕上渲染框。 源码路径:/opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-test1 先看下效果 2、编译 1)…

Redis-分片集群存储及读取数据详解

文章目录 Redis分片集群是什么?Redis分片集群的存储及读取数据? 更多相关内容可查看 Redis分片集群是什么? Redis分片集群是一种分布式部署方式,通过将数据分散存储在多个Redis节点上,从而提高了系统的性能、扩展性和…

【微记录】linux内核态日志如何持续观测?以及dmesg如何显示年月日时间戳?(dmesg -w ; -T)

文章目录 持续观测方法1方法2 dmes显示时间戳 持续观测 方法1 dmesg -w参考:https://man7.org/linux/man-pages/man1/dmesg.1.html 方法2 tail -f /var/log/kern.logdmes显示时间戳 dmesg -T #按照人类可读性高的时间戳 比如2024-05-15 01:20:16实操&#xff1…

快速学习SpringAi

Spring AI是AI工程师的一个应用框架,它提供了一个友好的API和开发AI应用的抽象,旨在简化AI应用的开发工序,例如开发一款基于ChatGPT的对话应用程序。通过使用Spring Ai使我们更简单直接使用chatgpt 1.创建项目 jdk17 引入依赖 2.依赖配置 …

敏捷开发最佳实践:自驱团队实践案例之心情曲线回顾会

调研发现,26%的中国企业认为最有价值管理实践是“团队回顾会”,而“团队回顾会”的确能够很好的引导团队走向自驱。在本节的实践案例中 “心情曲线回顾会”的具体做法较为典型,很值得参考。 本实践节选自《2021中国企业敏捷实践白皮书》&…

压力给到 Google,OpenAI 发布 GPT-4o 来了

北京时间5月14日凌晨1点,OpenAI 开启了今年的第一次直播,根据官方消息,这次旨在演示 ChatGPT 和 GPT-4 的升级内容。在早些时候 Sam Altman 在 X 上已经明确,「我们一直在努力开发一些我们认为人们会喜欢的新东西,对我…

OpenNJet产品体验:探索无限可能

文章目录 前言一、OpenNJet是什么?二、OpenNJet特性和优点三、OpenNJet功能规划四、OpenNJet快速上手五、OpenNJet的使用总结 前言 现代社会网络高速发展,同时也迎来了互联网发展的高峰,OpenNJet作为一个基于NGINX的面向互联网和云原生应用提…

爬虫入门经典(七) | 采集淘宝电场相关信息

大家好,我是不温卜火,昵称来源于成语—不温不火,本意是希望自己性情温和。 PS:由于现在越来越多的人未经本人同意直接爬取博主本人文章,博主在此特别声明:未经本人允许,禁止转载!&a…

string功能介绍(普及版)

目录 1。初始化(好几种方式),npos和string的使用说明 2。string的拷贝,隐式类型转换,[],size,iterator,begin,end,reverse,reverse_iterator&am…

【回溯】1240. 铺瓷砖

本文涉及知识点 回溯 LeetCode1240. 铺瓷砖 你是一位施工队的工长,根据设计师的要求准备为一套设计风格独特的房子进行室内装修。 房子的客厅大小为 n x m,为保持极简的风格,需要使用尽可能少的 正方形 瓷砖来铺盖地面。 假设正方形瓷砖的…

windows驱动开发-PCI和中断(二)

谈到中断使用PCI总线来作为例子是最合适的,在Windows发展过程中,PCI作为最成功的底层总线,集成了大量的外设,不夸张的说,目前PCI几乎是唯一的总线选择,故大部分情况下,只有PCI设备驱动程序会遇到…

前端 performance api使用 —— mark、measure计算vue3页面echarts渲染时间

文章目录 ⭐前言💖vue3系列文章 ⭐Performance api计算持续时间💖 mark用法💖 measure用法 ⭐计算echarts渲染的持续时间⭐结束 ⭐前言 大家好,我是yma16,本文分享关于 前端 performance api使用 —— mark、measure计…

java springboot连接sqlserver使用

pom.xml增加sqlserver驱动 <dependency><groupId>com.microsoft.sqlserver</groupId><artifactId>mssql-jdbc</artifactId><version>9.4.0.jre8</version></dependency>application.yml配置文件 server:port: 9001 #spring: …