1
1
<div align =" center " >
2
2
<h1><img src="static/sailboat-solid-colorful.svg" alt="sailboat-solid" title="sailboat-solid" width="300" /></h1>
3
- </div >
3
+ </div >
4
4
5
5
[ ![ Go] ( https://github.com/keepchen/go-sail/actions/workflows/go.yml/badge.svg )] ( https://github.com/keepchen/go-sail/actions/workflows/go.yml )
6
6
[ ![ CodeQL] ( https://github.com/keepchen/go-sail/actions/workflows/codeql.yml/badge.svg )] ( https://github.com/keepchen/go-sail/actions/workflows/codeql.yml )
7
7
[ ![ Go Report Card] ( https://goreportcard.com/badge/github.com/keepchen/go-sail/v3 )] ( https://goreportcard.com/report/github.com/keepchen/go-sail/v3 )
8
8
[ ![ codecov] ( https://codecov.io/github/keepchen/go-sail/graph/badge.svg?token=UNLOORRJHA )] ( https://codecov.io/github/keepchen/go-sail )
9
9
[ ![ Dependabot Status] ( https://img.shields.io/badge/dependabot-active-brightgreen?logo=dependabot )] ( https://github.com/keepchen/go-sail/security/dependabot )
10
10
[ ![ Snyk Security] ( https://img.shields.io/badge/Snyk-Secure-blueviolet?logo=snyk )] ( https://snyk.io/test/github/keepchen/go-sail )
11
- [ ![ LICENSE: MIT] ( https://img.shields.io/github/license/keepchen/go-sail.svg?style=flat )] ( LICENSE )
11
+ [ ![ LICENSE: MIT] ( https://img.shields.io/github/license/keepchen/go-sail.svg?style=flat )] ( LICENSE )
12
12
13
13
简体中文 | [ English] ( ./README_EN.md )
14
14
15
- ## go-sail是什么?
15
+ ## go-sail是什么?
16
16
17
- ** go-sail** 是一个轻量的渐进式Web框架,使用Go语言实现。它并** 不是重复造轮子的产物** ,而是站在巨人的肩膀上,整合现有的优秀组件,旨在帮助使用者以最简单的方式构建稳定可靠的服务。
18
- 正如它的名字一般,你可以把它视作自己在golang生态的一个开始。go-sail将助力你从轻出发,扬帆起航。
17
+ ** go-sail** 是一个轻量的渐进式Web框架,使用Go语言实现。它并** 不是重复造轮子的产物** ,而是站在巨人的肩膀上,整合现有的优秀组件,旨在帮助使用者以最简单的方式构建稳定可靠的服务。
18
+ 正如它的名字一般,你可以把它视作自己在golang生态的一个开始。go-sail将助力你从轻出发,扬帆起航。
19
19
20
- ## 如何使用
21
- > 推荐go version >= 1.20
20
+ ## 如何使用
21
+ > 推荐go version >= 1.20
22
22
23
23
> go get -u github.com/keepchen/go-sail/v3
24
24
25
- ``` go
25
+ ``` go
26
26
import (
27
27
" net/http"
28
28
" github.com/gin-gonic/gin"
@@ -42,18 +42,18 @@ var (
42
42
func main () {
43
43
sail.WakeupHttp (" go-sail" , conf).Hook (registerRoutes, nil , nil ).Launch ()
44
44
}
45
- ```
46
- 当你看到终端如下图所示内容就表示服务启动成功了:
45
+ ```
46
+ 当你看到终端如下图所示内容就表示服务启动成功了:
47
47
48
- <img src =" static/launch.png " alt =" launch.png " title =" launch.png " width =" 600 " />
48
+ <img src =" static/launch.png " alt =" launch.png " title =" launch.png " width =" 600 " />
49
49
50
- ## 示例
51
- ### 配置读取
50
+ ## 示例
51
+ ### 配置读取
52
52
``` go
53
53
parseFn := func (content []byte , viaWatch bool ){
54
54
fmt.Println (" config content: " , string (content))
55
55
if viaWatch {
56
- // reload config...
56
+ // reload config...
57
57
}
58
58
}
59
59
etcdConf := etcd.Conf {
@@ -65,16 +65,16 @@ key := "go-sail.config.yaml"
65
65
66
66
sail.Config (true , parseFn).ViaEtcd (etcdConf, key).Parse (parseFn)
67
67
```
68
- ### 链路日志追踪
68
+ ### 链路日志追踪
69
69
``` go
70
70
func UserRegisterSvc (c *gin .Context ) {
71
71
...
72
72
sail.LogTrace (c).GetLogger ().Warn (" log something..." )
73
73
...
74
74
}
75
- ```
76
- ### JWT认证
77
- - 颁发令牌
75
+ ```
76
+ ### JWT认证
77
+ - 颁发令牌
78
78
``` go
79
79
func UserLoginSvc (c *gin .Context ) {
80
80
...
@@ -85,28 +85,28 @@ func UserLoginSvc(c *gin.Context) {
85
85
" avatar" : " https://go-sail.dev/assets/avatar/1.png" ,
86
86
...
87
87
}
88
- ok , claims , err := sail.JWT ().MakeToken (uid, exp, otherFields)
88
+ ok , token , err := sail.JWT ().MakeToken (uid, exp, otherFields)
89
89
...
90
90
}
91
- ```
92
- - 认证
91
+ ```
92
+ - 认证
93
93
``` go
94
94
func UserInfoSvc (c *gin .Context ) {
95
95
...
96
96
ok , claims , err := sail.JWT ().ValidToken (token)
97
97
...
98
98
}
99
- ```
100
- ### 组件
101
- #### 响应器
99
+ ```
100
+ ### 组件
101
+ #### 响应器
102
102
``` go
103
103
func UserInfoSvc (c *gin .Context ) {
104
104
sail.Response (c).Wrap (constants.ErrNone , resp).Send ()
105
105
}
106
- ```
106
+ ```
107
107
108
- #### 数据库
109
- - 读写分离
108
+ #### 数据库
109
+ - 读写分离
110
110
``` go
111
111
func UserInfoSvc (c *gin .Context ) {
112
112
uid := " user-1000"
@@ -118,11 +118,11 @@ func UserInfoSvc(c *gin.Context) {
118
118
sail.GetDBW ().Model (&models.User {}).
119
119
Where (" uid = ?" , uid).
120
120
Updates (map [string ]interface {}{
121
- " avatar" : " https://go-sail.dev/assets/avatar/2.png"
121
+ " avatar" : " https://go-sail.dev/assets/avatar/2.png"
122
122
})
123
123
}
124
- ```
125
- - 事务
124
+ ```
125
+ - 事务
126
126
``` go
127
127
func UserInfoSvc (c *gin .Context ) {
128
128
uid := " user-1000"
@@ -142,38 +142,38 @@ func UserInfoSvc(c *gin.Context) {
142
142
return e2
143
143
})
144
144
}
145
- ```
146
- #### Redis
145
+ ```
146
+ #### Redis
147
147
``` go
148
148
func UserInfoSvc (c *gin .Context ) {
149
149
...
150
150
sail.GetRedis ().Set (ctx, " go-sail:userInfo" , " user-1000" , time.Hour *24 ).Result ()
151
151
...
152
152
}
153
- ```
154
- ### 计划任务
155
- - 周期性的
153
+ ```
154
+ ### 计划任务
155
+ - 周期性的
156
156
``` go
157
157
func TodoSomething () {
158
158
fn := func () { ... }
159
159
sail.Schedule (" todoSomething" , fn).Daily ()
160
160
}
161
- ```
162
- - Linux Crontab风格的
161
+ ```
162
+ - Linux Crontab风格的
163
163
``` go
164
164
func TodoSomething () {
165
165
fn := func () { ... }
166
166
sail.Schedule (" todoSomething" , fn).RunAt (" */5 * * * *" )
167
167
}
168
- ```
169
- - 竞态检测
168
+ ```
169
+ - 竞态检测
170
170
``` go
171
171
func TodoSomething () {
172
172
fn := func () { ... }
173
173
sail.Schedule (" todoSomething" , fn).Withoutoverlapping ().RunAt (" */5 * * * *" )
174
174
}
175
- ```
176
- ### 分布式锁
175
+ ```
176
+ ### 分布式锁
177
177
``` go
178
178
func UpdateUserBalance () {
179
179
if !sail.RedisLocker ().TryLock (key) {
@@ -182,87 +182,105 @@ func UpdateUserBalance() {
182
182
defer sail.RedisLocker ().Unlock (key)
183
183
...
184
184
}
185
- ```
185
+ ```
186
186
187
- ## 文档
187
+ ## 文档
188
188
[ 文档传送门] ( https://go-sail.dev )
189
189
190
- ## 功能特性
191
- - [x] HTTP响应器
192
- - 统一响应字段
193
- - 管理HTTP状态码
194
- - 管理业务码
195
- - [x] 组件库
196
- - Database
197
- - Email
198
- - Jwt
199
- - Kafka
200
- - Logger
201
- - Nacos
202
- - Etcd
203
- - Nats
204
- - Redis
205
- - Valkey
206
- - [x] 服务注册与发现
207
- - Nacos
208
- - Etcd
209
- - [x] 工具类
210
- - 加解密
211
- - 文件
212
- - ip
213
- - 字符串
214
- - 随机数
215
- - 日期时间
190
+ ## 功能特性
191
+ - [x] HTTP响应器
192
+ - 统一响应字段
193
+ - 管理HTTP状态码
194
+ - 管理业务码
195
+ - [x] 组件库
196
+ - Database
197
+ - Email
198
+ - Jwt
199
+ - Kafka
200
+ - Logger
201
+ - Nacos
202
+ - Etcd
203
+ - Nats
204
+ - Redis
205
+ - Valkey
206
+ - [x] 服务注册与发现
207
+ - Nacos
208
+ - Etcd
209
+ - [x] 工具类
210
+ - 加解密
211
+ - 文件
212
+ - ip
213
+ - 字符串
214
+ - 随机数
215
+ - 日期时间
216
216
- ...
217
- - [x] 日志收集与导出
218
- - 本地文件
219
- - 导出器
220
- - Redis
221
- - Kafka
222
- - Nats
223
- - [x] 计划任务
224
- - 可取消的
225
- - 一次性的
226
- - 周期性的
227
- - Linux Crontab风格的
228
- - 竞态检测
229
- - [x] 遥测与可观测性
217
+ - [x] 日志收集与导出
218
+ - 本地文件
219
+ - 导出器
220
+ - Redis
221
+ - Kafka
222
+ - Nats
223
+ - [x] 计划任务
224
+ - 可取消的
225
+ - 一次性的
226
+ - 周期性的
227
+ - Linux Crontab风格的
228
+ - 竞态检测
229
+ - [x] 遥测与可观测性
230
230
- 调用链追踪
231
- - Prometheus
232
- - Pprof
233
- - 日志导出器
234
- - 性能检测
231
+ - Prometheus
232
+ - Pprof
233
+ - 日志导出器
234
+ - 性能检测
235
235
- Prometheus
236
236
- Pprof
237
- - [x] 接口错误码
238
- - 动态注入
239
- - 国际化
240
- - [x] 基于Redis的分布式锁
241
- - 阻塞式
242
- - 非阻塞式
243
- - [x] 接口文档
244
- - Redocly
245
- - Swagger
246
- - [x] 配置管理
247
- - File
248
- - Etcd
249
- - Nacos
237
+ - [x] 接口错误码
238
+ - 动态注入
239
+ - 国际化
240
+ - [x] 基于Redis的分布式锁
241
+ - 阻塞式
242
+ - 非阻塞式
243
+ - [x] 接口文档
244
+ - Redocly
245
+ - Swagger
246
+ - [x] 配置管理
247
+ - File
248
+ - Etcd
249
+ - Nacos
250
250
251
- #### 其他插件
252
- [ README.md] ( plugins/README.md )
251
+ #### 其他插件
252
+ [ README.md] ( plugins/README.md )
253
253
254
- ## 大感谢
255
- 感谢在体验、使用过程中提出宝贵建议和意见以及提供过其他各种帮助的各位小伙伴!
256
- - 配置模块化优化建议 [ @fujilin ] ( https://github.com/fujilin )
257
- - 响应器语法糖增强优化建议 [ @lichuanzhang ] ( https://github.com/lichuanzhang )
258
- - Logo美化 [ @ShuaiRen34 ] ( https://twitter.com/ShuaiRen34 )
254
+ ## 基准测试
255
+ ``` shell
256
+ ulimit -n 65535 && sh run_benchmark.sh
257
+ ```
258
+ 测试结果(真实的HTTP请求)
259
+ ``` text
260
+ goos: darwin
261
+ goarch: amd64
262
+ pkg: github.com/keepchen/go-sail/v3
263
+ cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
264
+ BenchmarkGoSailParallel-12 88252 12898 ns/op 8860 B/op 92 allocs/op
265
+ BenchmarkGinParallel-12 96548 11722 ns/op 7187 B/op 82 allocs/op
266
+ PASS
267
+ ok github.com/keepchen/go-sail/v3 3.663s
268
+ ```
269
+ ![ benchmark-result.png] ( static/benchmark-result.png )
259
270
260
- ## 其他
261
- - 欢迎大家提PR: [ pull request] ( https://github.com/keepchen/go-sail/compare )
262
- - 欢迎大家提出自己的想法: [ issue] ( https://github.com/keepchen/go-sail/issues/new/choose )
263
- - 感谢你的star如果你喜欢这个项目的话 :)
264
271
265
- ## 使用案例
272
+ ## 大感谢
273
+ 感谢在体验、使用过程中提出宝贵建议和意见以及提供过其他各种帮助的各位小伙伴!
274
+ - 配置模块化优化建议 [ @fujilin ] ( https://github.com/fujilin )
275
+ - 响应器语法糖增强优化建议 [ @lichuanzhang ] ( https://github.com/lichuanzhang )
276
+ - Logo美化 [ @ShuaiRen34 ] ( https://twitter.com/ShuaiRen34 )
277
+
278
+ ## 其他
279
+ - 欢迎大家提PR: [ pull request] ( https://github.com/keepchen/go-sail/compare )
280
+ - 欢迎大家提出自己的想法: [ issue] ( https://github.com/keepchen/go-sail/issues/new/choose )
281
+ - 感谢你的star如果你喜欢这个项目的话 :)
282
+
283
+ ## 使用案例
266
284
<table style =" text-align : center " >
267
285
<tr style =" height :200px " >
268
286
<td style="border: 1px solid black; padding: 8px;">
@@ -286,11 +304,10 @@ func UpdateUserBalance() {
286
304
<a href="https://fantagoal.io" target="_blank"><img src="static/usecases/fantaGoal-logo.png" alt="FantaGoal" width="200" title="https://fantagoal.io"/></a>
287
305
</td>
288
306
</tr >
289
- </table >
307
+ </table >
290
308
291
- ## 赞助
292
- [ ![ Powered by DartNode] ( https://dartnode.com/branding/DN-Open-Source-sm.png )] ( https://dartnode.com " Powered by DartNode - Free VPS for Open Source ")
309
+ ## 赞助
310
+ [ ![ Powered by DartNode] ( https://dartnode.com/branding/DN-Open-Source-sm.png )] ( https://dartnode.com " Powered by DartNode - Free VPS for Open Source ")
293
311
294
- ## Star历史
312
+ ## Star历史
295
313
![ star history] ( https://starchart.cc/keepchen/go-sail.svg )
296
-
0 commit comments