Kaynağa Gözat

改成支持单数据库和单服务

qdy 2 ay önce
ebeveyn
işleme
17faf20519

BIN
.DS_Store Dosyayı Görüntüle


BIN
bootstraps/.DS_Store Dosyayı Görüntüle


+ 388
- 388
bootstraps/bootstrap.go Dosyayı Görüntüle

@@ -1,403 +1,403 @@
1 1
 package bootstraps
2 2
 
3
-import (
4
-	"context"
5
-	"fmt"
6
-	"log"
7
-	"net/http"
8
-	"os"
9
-	"os/signal"
10
-	"syscall"
11
-	"time"
12
-
13
-	"git.x2erp.com/qdy/go-base/client"
14
-	"git.x2erp.com/qdy/go-base/config"
15
-	"git.x2erp.com/qdy/go-base/consul"
16
-	"git.x2erp.com/qdy/go-base/logger"
17
-)
18
-
19
-// 定义接口
20
-type ShutdownHandler interface {
21
-	OnShutdown()
22
-}
23
-
24
-// WebService Web服务实例
25
-type WebService struct {
26
-	serviceName     string
27
-	HttpServer      *http.Server
28
-	Router          *http.ServeMux
29
-	quit            chan os.Signal
30
-	shutdownHandler ShutdownHandler
31
-	Port            int
32
-	Ip              string
33
-}
34
-
35
-// Bootstrapper 服务启动器
36
-type Bootstrapper struct {
37
-	appName    string
38
-	appVersion string
39
-	Cfg        config.IConfig
40
-	services   map[string]*WebService // 存储多个服务实例
41
-	quit       chan os.Signal
42
-}
43
-
44
-// NewBootstrapper 创建启动器
45
-func NewBootstrapper(name, version string) *Bootstrapper {
46
-	b := &Bootstrapper{
47
-		appName:    name,
48
-		appVersion: version,
49
-		quit:       make(chan os.Signal, 1),
50
-		services:   make(map[string]*WebService),
51
-	}
52
-
53
-	b.init()
54
-
55
-	return b
56
-}
57
-
58
-// Init 初始化配置和日志
59
-func (b *Bootstrapper) init() *Bootstrapper {
60
-	// 1. 初始化启动日志
61
-	if err := logger.InitBootLog(b.appName); err != nil {
62
-		log.Fatal("无法初始化启动日志: ", err)
63
-	}
64
-
65
-	// 2. 加载配置
66
-	log.Println("正在加载配置...")
67
-	cfg, err := config.GetConfig()
68
-	if err != nil {
69
-		log.Fatalf("加载配置失败: %v", err)
70
-	}
71
-	cfg.SetAppName(b.appName)
72
-	cfg.SetAppVersion(b.appVersion)
73
-	b.Cfg = cfg
74
-
75
-	// 3. 初始化运行时日志
76
-	logger.InitRuntimeLogger(b.appName, b.appVersion, b.Cfg.GetLog())
77
-	log.Println("配置和日志初始化完成")
78
-
79
-	return b
80
-}
81
-
82
-// CreateService 创建Web服务实例
83
-func (b *Bootstrapper) createService(yamlNode string) *WebService {
84
-
85
-	serviceCfg := b.Cfg.GetServiceConfig(yamlNode)
86
-
87
-	// 检查是否已存在同名服务
88
-	if _, exists := b.services[yamlNode]; exists {
89
-		logger.Debug("服务 %s 已存在,将返回现有实例", yamlNode)
90
-		return b.services[yamlNode]
91
-	}
92
-
93
-	io := client.GetServiceIP("")
94
-	// 创建新的服务实例
95
-	ws := &WebService{
96
-		serviceName: serviceCfg.ServiceName,
97
-		Router:      http.NewServeMux(),
98
-		quit:        make(chan os.Signal, 1),
99
-		Port:        serviceCfg.Port,
100
-		Ip:          io,
101
-	}
102
-
103
-	// 创建HTTP服务器
104
-	ws.HttpServer = &http.Server{
105
-		Addr:         fmt.Sprintf(":%d", serviceCfg.Port),
106
-		Handler:      ws.Router,
107
-		ReadTimeout:  15 * time.Second,
108
-		WriteTimeout: 15 * time.Second,
109
-		IdleTimeout:  60 * time.Second,
110
-	}
111
-
112
-	// 存储服务实例
113
-	b.services[yamlNode] = ws
114
-
115
-	logger.Debug("已创建服务实例: %s (端口: %d)", serviceCfg.ServiceName, serviceCfg.Port)
116
-
117
-	return ws
118
-}
119
-
120
-// GetAllServices 获取所有服务实例
121
-func (b *Bootstrapper) GetAllServices() map[string]*WebService {
122
-	return b.services
123
-}
124
-
125
-// StartService 启动指定服务
126
-func (b *Bootstrapper) StartService(yamlNode string) *Bootstrapper {
127
-
128
-	service := b.createService(yamlNode)
129
-
130
-	log.Printf("正在启动服务: %s ", service.serviceName)
131
-	log.Printf("模式: 独立运行 (net/http)")
132
-	log.Printf("服务端口: :%d", service.Port)
133
-
134
-	return b
135
-}
136
-
137
-// Run 运行所有服务
138
-func (b *Bootstrapper) Run(shutdownHandler ShutdownHandler) {
139
-	if len(b.services) == 0 {
140
-		log.Fatal("没有要运行的服务,请先创建服务实例")
141
-	}
142
-
143
-	log.Printf("开始运行 %d 个服务...", len(b.services))
144
-
145
-	// 设置全局信号监听
146
-	signal.Notify(b.quit, syscall.SIGINT, syscall.SIGTERM)
147
-
148
-	// 启动所有服务
149
-	for serviceName, service := range b.services {
150
-		go func(name string, ws *WebService) {
151
-
152
-			consul.Register(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
153
-
154
-			log.Printf("启动服务 %s 在 %s", name, ws.HttpServer.Addr)
155
-			if err := ws.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
156
-				log.Fatalf("服务 %s 运行失败: %v", name, err)
157
-			}
158
-		}(serviceName, service)
159
-	}
160
-
161
-	// 等待中断信号
162
-	b.waitForShutdown(shutdownHandler)
163
-}
164
-
165
-// RunSingle 运行单个服务
166
-func (b *Bootstrapper) RunSingle(yamlNode string, shutdownHandler ShutdownHandler) {
167
-	service := b.createService(yamlNode)
168
-
169
-	log.Printf("服务 %s 开始运行...", service.serviceName)
170
-
171
-	// 设置服务级别的信号监听
172
-	signal.Notify(service.quit, syscall.SIGINT, syscall.SIGTERM)
173
-
174
-	// 启动服务
175
-	go func() {
176
-		log.Printf("服务器启动在 %s", service.HttpServer.Addr)
177
-		if err := service.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
178
-			log.Fatalf("服务运行失败: %v", err)
179
-		}
180
-	}()
181
-
182
-	consul.Register(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
183
-
184
-	// 等待中断信号
185
-	b.waitForServiceShutdown(service, shutdownHandler)
186
-}
187
-
188
-// RunTLS 运行HTTPS服务
189
-func (b *Bootstrapper) RunTLS(serviceName, certFile, keyFile string, shutdownHandler ShutdownHandler) {
190
-	service := b.createService(serviceName)
191
-
192
-	log.Printf("服务 %s 开始运行(HTTPS)...", service.serviceName)
193
-
194
-	// 设置服务级别的信号监听
195
-	signal.Notify(service.quit, syscall.SIGINT, syscall.SIGTERM)
196
-
197
-	// 启动HTTPS服务器
198
-	go func() {
199
-		log.Printf("HTTPS服务器启动在 %s", service.HttpServer.Addr)
200
-		if err := service.HttpServer.ListenAndServeTLS(certFile, keyFile); err != nil && err != http.ErrServerClosed {
201
-			log.Fatalf("服务运行失败: %v", err)
202
-		}
203
-	}()
204
-
205
-	// 等待中断信号
206
-	b.waitForServiceShutdown(service, shutdownHandler)
207
-}
208
-
209
-// waitForShutdown 等待关闭信号(关闭所有服务)
210
-func (b *Bootstrapper) waitForShutdown(handler ShutdownHandler) {
211
-	log.Println("按 Ctrl+C 停止所有服务")
212
-
213
-	// 等待信号
214
-	<-b.quit
215
-	log.Println("接收到终止信号,正在优雅关闭所有服务...")
216
-
217
-	// 创建关闭上下文,给30秒完成当前请求
218
-	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
219
-	defer cancel()
220
-
221
-	// 关闭所有服务
222
-	shutdownComplete := make(chan bool, len(b.services))
223
-
224
-	for serviceName, service := range b.services {
225
-		go func(name string, ws *WebService) {
226
-			log.Printf("正在关闭服务: %s", name)
227
-			//退出注册中心
228
-			consul.Deregister(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
229
-
230
-			if err := ws.HttpServer.Shutdown(ctx); err != nil {
231
-				log.Printf("服务 %s 关闭失败: %v", name, err)
232
-			} else {
233
-				log.Printf("服务 %s 已关闭", name)
234
-			}
235
-			shutdownComplete <- true
236
-		}(serviceName, service)
237
-	}
238
-
239
-	// 等待所有服务关闭完成
240
-	for i := 0; i < len(b.services); i++ {
241
-		<-shutdownComplete
242
-	}
243
-
244
-	// 执行关闭处理
245
-	if handler != nil {
246
-		handler.OnShutdown()
247
-	}
248
-
249
-	// 停止日志写入
250
-	logger.StopESWriter()
251
-	log.Println("所有服务优雅关闭完成")
252
-
253
-	// 等待一小段时间确保日志写入完成
254
-	time.Sleep(100 * time.Millisecond)
255
-	os.Exit(0)
256
-}
257
-
258
-// waitForServiceShutdown 等待单个服务关闭
259
-func (b *Bootstrapper) waitForServiceShutdown(service *WebService, handler ShutdownHandler) {
260
-
261
-	log.Printf("按 Ctrl+C 停止服务 %s", service.serviceName)
262
-
263
-	// 等待信号
264
-	<-service.quit
265
-	log.Printf("接收到终止信号,正在优雅关闭服务 %s...", service.serviceName)
266
-
267
-	//退出注册中心
268
-	consul.Deregister(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
269
-
270
-	// 创建关闭上下文,给30秒完成当前请求
271
-	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
272
-	defer cancel()
273
-
274
-	// 停止接收新请求,完成当前请求
275
-	if err := service.HttpServer.Shutdown(ctx); err != nil {
276
-		log.Printf("服务 %s 关闭失败: %v", service.serviceName, err)
277
-	} else {
278
-		log.Printf("服务 %s 已关闭", service.serviceName)
279
-	}
280
-
281
-	// 执行关闭处理
282
-	if handler != nil {
283
-		handler.OnShutdown()
284
-	}
285
-
286
-	// 停止日志写入
287
-	logger.StopESWriter()
288
-	log.Printf("服务 %s 优雅关闭完成", service.serviceName)
289
-
290
-	// 等待一小段时间确保日志写入完成
291
-	time.Sleep(100 * time.Millisecond)
292
-	os.Exit(0)
293
-}
294
-
295
-// GetConfig 获取配置
296
-func (b *Bootstrapper) GetConfig() config.IConfig {
297
-	return b.Cfg
298
-}
299
-
300
-// GetWebService 获取指定服务的路由器
301
-func (b *Bootstrapper) GetRouter(yamlNode string) *http.ServeMux {
302
-	service := b.createService(yamlNode)
303
-	return service.Router
304
-}
305
-
306
-// GetRouterDefault 获取第一个服务的路由器(兼容性方法)
307
-func (b *Bootstrapper) GetRouterDefault() *http.ServeMux {
308
-	for _, service := range b.services {
309
-		return service.Router
310
-	}
311
-	// 如果没有服务,创建默认路由器(向后兼容)
312
-	return http.NewServeMux()
313
-}
314
-
315
-// // Handle 注册路由处理器到指定服务
316
-// func (b *Bootstrapper) Handle(serviceName, pattern string, handler http.Handler) bool {
317
-// 	if service, exists := b.services[serviceName]; exists {
318
-// 		service.Router.Handle(pattern, handler)
319
-// 		return true
3
+// import (
4
+// 	"context"
5
+// 	"fmt"
6
+// 	"log"
7
+// 	"net/http"
8
+// 	"os"
9
+// 	"os/signal"
10
+// 	"syscall"
11
+// 	"time"
12
+
13
+// 	"git.x2erp.com/qdy/go-base/client"
14
+// 	"git.x2erp.com/qdy/go-base/config"
15
+// 	"git.x2erp.com/qdy/go-base/consul"
16
+// 	"git.x2erp.com/qdy/go-base/logger"
17
+// )
18
+
19
+// // 定义接口
20
+// type ShutdownHandler interface {
21
+// 	OnShutdown()
22
+// }
23
+
24
+// // WebService Web服务实例
25
+// type WebService struct {
26
+// 	serviceName     string
27
+// 	HttpServer      *http.Server
28
+// 	Router          *http.ServeMux
29
+// 	quit            chan os.Signal
30
+// 	shutdownHandler ShutdownHandler
31
+// 	Port            int
32
+// 	Ip              string
33
+// }
34
+
35
+// // Bootstrapper 服务启动器
36
+// type Bootstrapper struct {
37
+// 	appName    string
38
+// 	appVersion string
39
+// 	Cfg        config.IConfig
40
+// 	services   map[string]*WebService // 存储多个服务实例
41
+// 	quit       chan os.Signal
42
+// }
43
+
44
+// // NewBootstrapper 创建启动器
45
+// func NewBootstrapper(name, version string) *Bootstrapper {
46
+// 	b := &Bootstrapper{
47
+// 		appName:    name,
48
+// 		appVersion: version,
49
+// 		quit:       make(chan os.Signal, 1),
50
+// 		services:   make(map[string]*WebService),
320 51
 // 	}
321
-// 	log.Printf("错误: 服务 %s 不存在", serviceName)
322
-// 	return false
52
+
53
+// 	b.init()
54
+
55
+// 	return b
56
+// }
57
+
58
+// // Init 初始化配置和日志
59
+// func (b *Bootstrapper) init() *Bootstrapper {
60
+// 	// 1. 初始化启动日志
61
+// 	if err := logger.InitBootLog(b.appName); err != nil {
62
+// 		log.Fatal("无法初始化启动日志: ", err)
63
+// 	}
64
+
65
+// 	// 2. 加载配置
66
+// 	log.Println("正在加载配置...")
67
+// 	cfg, err := config.GetConfig()
68
+// 	if err != nil {
69
+// 		log.Fatalf("加载配置失败: %v", err)
70
+// 	}
71
+// 	cfg.SetAppName(b.appName)
72
+// 	cfg.SetAppVersion(b.appVersion)
73
+// 	b.Cfg = cfg
74
+
75
+// 	// 3. 初始化运行时日志
76
+// 	logger.InitRuntimeLogger(b.appName, b.appVersion, b.Cfg.GetLog())
77
+// 	log.Println("配置和日志初始化完成")
78
+
79
+// 	return b
80
+// }
81
+
82
+// // CreateService 创建Web服务实例
83
+// func (b *Bootstrapper) createService() *WebService {
84
+
85
+// 	serviceCfg := b.Cfg.GetServiceConfig()
86
+
87
+// 	// 检查是否已存在同名服务
88
+// 	if _, exists := b.services[yamlNode]; exists {
89
+// 		logger.Debug("服务 %s 已存在,将返回现有实例", yamlNode)
90
+// 		return b.services[yamlNode]
91
+// 	}
92
+
93
+// 	io := client.GetServiceIP("")
94
+// 	// 创建新的服务实例
95
+// 	ws := &WebService{
96
+// 		serviceName: serviceCfg.ServiceName,
97
+// 		Router:      http.NewServeMux(),
98
+// 		quit:        make(chan os.Signal, 1),
99
+// 		Port:        serviceCfg.Port,
100
+// 		Ip:          io,
101
+// 	}
102
+
103
+// 	// 创建HTTP服务器
104
+// 	ws.HttpServer = &http.Server{
105
+// 		Addr:         fmt.Sprintf(":%d", serviceCfg.Port),
106
+// 		Handler:      ws.Router,
107
+// 		ReadTimeout:  15 * time.Second,
108
+// 		WriteTimeout: 15 * time.Second,
109
+// 		IdleTimeout:  60 * time.Second,
110
+// 	}
111
+
112
+// 	// 存储服务实例
113
+// 	b.services[yamlNode] = ws
114
+
115
+// 	logger.Debug("已创建服务实例: %s (端口: %d)", serviceCfg.ServiceName, serviceCfg.Port)
116
+
117
+// 	return ws
118
+// }
119
+
120
+// // GetAllServices 获取所有服务实例
121
+// func (b *Bootstrapper) GetAllServices() map[string]*WebService {
122
+// 	return b.services
123
+// }
124
+
125
+// // StartService 启动指定服务
126
+// func (b *Bootstrapper) StartService(yamlNode string) *Bootstrapper {
127
+
128
+// 	service := b.createService(yamlNode)
129
+
130
+// 	log.Printf("正在启动服务: %s ", service.serviceName)
131
+// 	log.Printf("模式: 独立运行 (net/http)")
132
+// 	log.Printf("服务端口: :%d", service.Port)
133
+
134
+// 	return b
135
+// }
136
+
137
+// // Run 运行所有服务
138
+// func (b *Bootstrapper) Run(shutdownHandler ShutdownHandler) {
139
+// 	if len(b.services) == 0 {
140
+// 		log.Fatal("没有要运行的服务,请先创建服务实例")
141
+// 	}
142
+
143
+// 	log.Printf("开始运行 %d 个服务...", len(b.services))
144
+
145
+// 	// 设置全局信号监听
146
+// 	signal.Notify(b.quit, syscall.SIGINT, syscall.SIGTERM)
147
+
148
+// 	// 启动所有服务
149
+// 	for serviceName, service := range b.services {
150
+// 		go func(name string, ws *WebService) {
151
+
152
+// 			consul.Register(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
153
+
154
+// 			log.Printf("启动服务 %s 在 %s", name, ws.HttpServer.Addr)
155
+// 			if err := ws.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
156
+// 				log.Fatalf("服务 %s 运行失败: %v", name, err)
157
+// 			}
158
+// 		}(serviceName, service)
159
+// 	}
160
+
161
+// 	// 等待中断信号
162
+// 	b.waitForShutdown(shutdownHandler)
163
+// }
164
+
165
+// // RunSingle 运行单个服务
166
+// func (b *Bootstrapper) RunSingle(yamlNode string, shutdownHandler ShutdownHandler) {
167
+// 	service := b.createService(yamlNode)
168
+
169
+// 	log.Printf("服务 %s 开始运行...", service.serviceName)
170
+
171
+// 	// 设置服务级别的信号监听
172
+// 	signal.Notify(service.quit, syscall.SIGINT, syscall.SIGTERM)
173
+
174
+// 	// 启动服务
175
+// 	go func() {
176
+// 		log.Printf("服务器启动在 %s", service.HttpServer.Addr)
177
+// 		if err := service.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
178
+// 			log.Fatalf("服务运行失败: %v", err)
179
+// 		}
180
+// 	}()
181
+
182
+// 	consul.Register(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
183
+
184
+// 	// 等待中断信号
185
+// 	b.waitForServiceShutdown(service, shutdownHandler)
323 186
 // }
324 187
 
325
-// SetShutdownHandler 为服务设置关闭处理器
326
-func (b *Bootstrapper) SetShutdownHandler(serviceName string, handler ShutdownHandler) bool {
327
-	if service, exists := b.services[serviceName]; exists {
328
-		service.shutdownHandler = handler
329
-		return true
330
-	}
331
-	return false
332
-}
188
+// // RunTLS 运行HTTPS服务
189
+// func (b *Bootstrapper) RunTLS(serviceName, certFile, keyFile string, shutdownHandler ShutdownHandler) {
190
+// 	service := b.createService(serviceName)
191
+
192
+// 	log.Printf("服务 %s 开始运行(HTTPS)...", service.serviceName)
193
+
194
+// 	// 设置服务级别的信号监听
195
+// 	signal.Notify(service.quit, syscall.SIGINT, syscall.SIGTERM)
196
+
197
+// 	// 启动HTTPS服务器
198
+// 	go func() {
199
+// 		log.Printf("HTTPS服务器启动在 %s", service.HttpServer.Addr)
200
+// 		if err := service.HttpServer.ListenAndServeTLS(certFile, keyFile); err != nil && err != http.ErrServerClosed {
201
+// 			log.Fatalf("服务运行失败: %v", err)
202
+// 		}
203
+// 	}()
204
+
205
+// 	// 等待中断信号
206
+// 	b.waitForServiceShutdown(service, shutdownHandler)
207
+// }
208
+
209
+// // waitForShutdown 等待关闭信号(关闭所有服务)
210
+// func (b *Bootstrapper) waitForShutdown(handler ShutdownHandler) {
211
+// 	log.Println("按 Ctrl+C 停止所有服务")
212
+
213
+// 	// 等待信号
214
+// 	<-b.quit
215
+// 	log.Println("接收到终止信号,正在优雅关闭所有服务...")
216
+
217
+// 	// 创建关闭上下文,给30秒完成当前请求
218
+// 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
219
+// 	defer cancel()
220
+
221
+// 	// 关闭所有服务
222
+// 	shutdownComplete := make(chan bool, len(b.services))
223
+
224
+// 	for serviceName, service := range b.services {
225
+// 		go func(name string, ws *WebService) {
226
+// 			log.Printf("正在关闭服务: %s", name)
227
+// 			//退出注册中心
228
+// 			consul.Deregister(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
229
+
230
+// 			if err := ws.HttpServer.Shutdown(ctx); err != nil {
231
+// 				log.Printf("服务 %s 关闭失败: %v", name, err)
232
+// 			} else {
233
+// 				log.Printf("服务 %s 已关闭", name)
234
+// 			}
235
+// 			shutdownComplete <- true
236
+// 		}(serviceName, service)
237
+// 	}
238
+
239
+// 	// 等待所有服务关闭完成
240
+// 	for i := 0; i < len(b.services); i++ {
241
+// 		<-shutdownComplete
242
+// 	}
243
+
244
+// 	// 执行关闭处理
245
+// 	if handler != nil {
246
+// 		handler.OnShutdown()
247
+// 	}
333 248
 
334
-// ========== WebService 的方法 ==========
249
+// 	// 停止日志写入
250
+// 	logger.StopESWriter()
251
+// 	log.Println("所有服务优雅关闭完成")
335 252
 
336
-// GetServiceName 获取服务名称
337
-// func (ws *WebService) GetServiceName() string {
338
-// 	return ws.serviceName
253
+// 	// 等待一小段时间确保日志写入完成
254
+// 	time.Sleep(100 * time.Millisecond)
255
+// 	os.Exit(0)
339 256
 // }
340 257
 
341
-// // GetServiceConfig 获取服务配置
342
-// func (ws *WebService) GetServiceConfig() *subconfigs.ServiceConfig {
343
-// 	return ws.serviceConfig
258
+// // waitForServiceShutdown 等待单个服务关闭
259
+// func (b *Bootstrapper) waitForServiceShutdown(service *WebService, handler ShutdownHandler) {
260
+
261
+// 	log.Printf("按 Ctrl+C 停止服务 %s", service.serviceName)
262
+
263
+// 	// 等待信号
264
+// 	<-service.quit
265
+// 	log.Printf("接收到终止信号,正在优雅关闭服务 %s...", service.serviceName)
266
+
267
+// 	//退出注册中心
268
+// 	consul.Deregister(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
269
+
270
+// 	// 创建关闭上下文,给30秒完成当前请求
271
+// 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
272
+// 	defer cancel()
273
+
274
+// 	// 停止接收新请求,完成当前请求
275
+// 	if err := service.HttpServer.Shutdown(ctx); err != nil {
276
+// 		log.Printf("服务 %s 关闭失败: %v", service.serviceName, err)
277
+// 	} else {
278
+// 		log.Printf("服务 %s 已关闭", service.serviceName)
279
+// 	}
280
+
281
+// 	// 执行关闭处理
282
+// 	if handler != nil {
283
+// 		handler.OnShutdown()
284
+// 	}
285
+
286
+// 	// 停止日志写入
287
+// 	logger.StopESWriter()
288
+// 	log.Printf("服务 %s 优雅关闭完成", service.serviceName)
289
+
290
+// 	// 等待一小段时间确保日志写入完成
291
+// 	time.Sleep(100 * time.Millisecond)
292
+// 	os.Exit(0)
344 293
 // }
345 294
 
346
-// GetRouter 获取服务的路由器
347
-// func (ws *WebService) GetRouter() *http.ServeMux {
348
-// 	return ws.Router
295
+// // GetConfig 获取配置
296
+// func (b *Bootstrapper) GetConfig() config.IConfig {
297
+// 	return b.Cfg
349 298
 // }
350 299
 
351
-// Handle 注册路由处理器
352
-// func (ws *WebService) Handle(pattern string, handler http.Handler) {
353
-// 	ws.Router.Handle(pattern, handler)
300
+// // GetWebService 获取指定服务的路由器
301
+// func (b *Bootstrapper) GetRouter(yamlNode string) *http.ServeMux {
302
+// 	service := b.createService(yamlNode)
303
+// 	return service.Router
354 304
 // }
355 305
 
356
-// SetShutdownHandler 设置关闭处理器
357
-func (ws *WebService) SetShutdownHandler(handler ShutdownHandler) {
358
-	ws.shutdownHandler = handler
359
-}
360
-
361
-// Run 运行单个服务
362
-func (ws *WebService) Run(shutdownHandler ShutdownHandler) {
363
-	log.Printf("服务 %s 开始运行...", ws.serviceName)
364
-
365
-	// 设置信号监听
366
-	signal.Notify(ws.quit, syscall.SIGINT, syscall.SIGTERM)
367
-
368
-	// 启动服务
369
-	go func() {
370
-		log.Printf("服务器启动在 %s", ws.HttpServer.Addr)
371
-		if err := ws.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
372
-			log.Fatalf("服务 %s 运行失败: %v", ws.serviceName, err)
373
-		}
374
-	}()
375
-
376
-	// 等待中断信号
377
-	log.Printf("按 Ctrl+C 停止服务 %s", ws.serviceName)
378
-	<-ws.quit
379
-
380
-	log.Printf("接收到终止信号,正在优雅关闭服务 %s...", ws.serviceName)
381
-
382
-	// 创建关闭上下文
383
-	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
384
-	defer cancel()
385
-
386
-	// 关闭服务
387
-	if err := ws.HttpServer.Shutdown(ctx); err != nil {
388
-		log.Printf("服务 %s 关闭失败: %v", ws.serviceName, err)
389
-	} else {
390
-		log.Printf("服务 %s 已关闭", ws.serviceName)
391
-	}
392
-
393
-	// 执行关闭处理
394
-	if shutdownHandler != nil {
395
-		shutdownHandler.OnShutdown()
396
-	} else if ws.shutdownHandler != nil {
397
-		ws.shutdownHandler.OnShutdown()
398
-	}
399
-
400
-	log.Printf("服务 %s 优雅关闭完成", ws.serviceName)
401
-	time.Sleep(100 * time.Millisecond)
402
-	os.Exit(0)
403
-}
306
+// // GetRouterDefault 获取第一个服务的路由器(兼容性方法)
307
+// func (b *Bootstrapper) GetRouterDefault() *http.ServeMux {
308
+// 	for _, service := range b.services {
309
+// 		return service.Router
310
+// 	}
311
+// 	// 如果没有服务,创建默认路由器(向后兼容)
312
+// 	return http.NewServeMux()
313
+// }
314
+
315
+// // // Handle 注册路由处理器到指定服务
316
+// // func (b *Bootstrapper) Handle(serviceName, pattern string, handler http.Handler) bool {
317
+// // 	if service, exists := b.services[serviceName]; exists {
318
+// // 		service.Router.Handle(pattern, handler)
319
+// // 		return true
320
+// // 	}
321
+// // 	log.Printf("错误: 服务 %s 不存在", serviceName)
322
+// // 	return false
323
+// // }
324
+
325
+// // SetShutdownHandler 为服务设置关闭处理器
326
+// func (b *Bootstrapper) SetShutdownHandler(serviceName string, handler ShutdownHandler) bool {
327
+// 	if service, exists := b.services[serviceName]; exists {
328
+// 		service.shutdownHandler = handler
329
+// 		return true
330
+// 	}
331
+// 	return false
332
+// }
333
+
334
+// // ========== WebService 的方法 ==========
335
+
336
+// // GetServiceName 获取服务名称
337
+// // func (ws *WebService) GetServiceName() string {
338
+// // 	return ws.serviceName
339
+// // }
340
+
341
+// // // GetServiceConfig 获取服务配置
342
+// // func (ws *WebService) GetServiceConfig() *subconfigs.ServiceConfig {
343
+// // 	return ws.serviceConfig
344
+// // }
345
+
346
+// // GetRouter 获取服务的路由器
347
+// // func (ws *WebService) GetRouter() *http.ServeMux {
348
+// // 	return ws.Router
349
+// // }
350
+
351
+// // Handle 注册路由处理器
352
+// // func (ws *WebService) Handle(pattern string, handler http.Handler) {
353
+// // 	ws.Router.Handle(pattern, handler)
354
+// // }
355
+
356
+// // SetShutdownHandler 设置关闭处理器
357
+// func (ws *WebService) SetShutdownHandler(handler ShutdownHandler) {
358
+// 	ws.shutdownHandler = handler
359
+// }
360
+
361
+// // Run 运行单个服务
362
+// func (ws *WebService) Run(shutdownHandler ShutdownHandler) {
363
+// 	log.Printf("服务 %s 开始运行...", ws.serviceName)
364
+
365
+// 	// 设置信号监听
366
+// 	signal.Notify(ws.quit, syscall.SIGINT, syscall.SIGTERM)
367
+
368
+// 	// 启动服务
369
+// 	go func() {
370
+// 		log.Printf("服务器启动在 %s", ws.HttpServer.Addr)
371
+// 		if err := ws.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
372
+// 			log.Fatalf("服务 %s 运行失败: %v", ws.serviceName, err)
373
+// 		}
374
+// 	}()
375
+
376
+// 	// 等待中断信号
377
+// 	log.Printf("按 Ctrl+C 停止服务 %s", ws.serviceName)
378
+// 	<-ws.quit
379
+
380
+// 	log.Printf("接收到终止信号,正在优雅关闭服务 %s...", ws.serviceName)
381
+
382
+// 	// 创建关闭上下文
383
+// 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
384
+// 	defer cancel()
385
+
386
+// 	// 关闭服务
387
+// 	if err := ws.HttpServer.Shutdown(ctx); err != nil {
388
+// 		log.Printf("服务 %s 关闭失败: %v", ws.serviceName, err)
389
+// 	} else {
390
+// 		log.Printf("服务 %s 已关闭", ws.serviceName)
391
+// 	}
392
+
393
+// 	// 执行关闭处理
394
+// 	if shutdownHandler != nil {
395
+// 		shutdownHandler.OnShutdown()
396
+// 	} else if ws.shutdownHandler != nil {
397
+// 		ws.shutdownHandler.OnShutdown()
398
+// 	}
399
+
400
+// 	log.Printf("服务 %s 优雅关闭完成", ws.serviceName)
401
+// 	time.Sleep(100 * time.Millisecond)
402
+// 	os.Exit(0)
403
+// }

+ 31
- 31
bootstraps/shutdown.go Dosyayı Görüntüle

@@ -1,39 +1,39 @@
1 1
 package bootstraps
2 2
 
3
-import (
4
-	"os"
5
-	"os/signal"
6
-	"syscall"
7
-	"time"
3
+// import (
4
+// 	"os"
5
+// 	"os/signal"
6
+// 	"syscall"
7
+// 	"time"
8 8
 
9
-	"git.x2erp.com/qdy/go-base/logger"
10
-	"git.x2erp.com/qdy/go-db/factory/database"
11
-)
9
+// 	"git.x2erp.com/qdy/go-base/logger"
10
+// 	"git.x2erp.com/qdy/go-db/factory/database"
11
+// )
12 12
 
13
-// setupGracefulShutdown 设置优雅关闭
14
-func SetupGracefulShutdown(dbFactory *database.DBFactory, cleanupFuncs ...func()) {
15
-	signalCh := make(chan os.Signal, 1)
16
-	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
13
+// // setupGracefulShutdown 设置优雅关闭
14
+// func SetupGracefulShutdown(dbFactory *database.DBFactory, cleanupFuncs ...func()) {
15
+// 	signalCh := make(chan os.Signal, 1)
16
+// 	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
17 17
 
18
-	go func() {
19
-		<-signalCh
20
-		logger.Info("\n接收到关闭信号,正在优雅关闭...")
18
+// 	go func() {
19
+// 		<-signalCh
20
+// 		logger.Info("\n接收到关闭信号,正在优雅关闭...")
21 21
 
22
-		// 关闭数据库连接
23
-		if dbFactory != nil {
24
-			if err := dbFactory.Close(); err != nil {
25
-				logger.Error("关闭数据库错误: %v", err)
26
-			}
27
-			logger.Info("数据库连接已关闭")
28
-		}
22
+// 		// 关闭数据库连接
23
+// 		if dbFactory != nil {
24
+// 			if err := dbFactory.Close(); err != nil {
25
+// 				logger.Error("关闭数据库错误: %v", err)
26
+// 			}
27
+// 			logger.Info("数据库连接已关闭")
28
+// 		}
29 29
 
30
-		// 执行其他清理函数
31
-		for _, cleanup := range cleanupFuncs {
32
-			cleanup()
33
-		}
30
+// 		// 执行其他清理函数
31
+// 		for _, cleanup := range cleanupFuncs {
32
+// 			cleanup()
33
+// 		}
34 34
 
35
-		// 等待日志写入完成
36
-		time.Sleep(100 * time.Millisecond)
37
-		os.Exit(0)
38
-	}()
39
-}
35
+// 		// 等待日志写入完成
36
+// 		time.Sleep(100 * time.Millisecond)
37
+// 		os.Exit(0)
38
+// 	}()
39
+// }

+ 82
- 150
config/config.go Dosyayı Görüntüle

@@ -4,20 +4,15 @@ import (
4 4
 	"sync"
5 5
 
6 6
 	"git.x2erp.com/qdy/go-base/config/subconfigs"
7
-	"git.x2erp.com/qdy/go-base/logger"
8 7
 )
9 8
 
10 9
 // IConfig 主配置接口(更新支持多数据库)
11 10
 type IConfig interface {
12 11
 	// 多数据库支持
13
-	GetDatabase() *subconfigs.DatabaseConfig                  // 获取默认数据库(向后兼容)
14
-	GetDatabases() *subconfigs.DatabasesConfig                // 获取所有数据库配置
15
-	GetDatabaseConfig(name string) *subconfigs.DatabaseConfig // 按名称获取数据库配置
12
+	GetDatabaseConfig() *subconfigs.DatabaseConfig // 获取默认数据库(向后兼容)
16 13
 
17
-	//多服务支持
18
-	GetService() *subconfigs.ServiceConfig                  //获取默认微服务配置
19
-	GetServices() *subconfigs.ServicesConfig                //获所有定义的微服务配置
20
-	GetServiceConfig(name string) *subconfigs.ServiceConfig //获取微服务配置
14
+	//服务支持
15
+	GetServiceConfig() *subconfigs.ServiceConfig //获取默认微服务配置
21 16
 
22 17
 	// 其他配置(保持不变)
23 18
 	GetRedisConfig() *subconfigs.RedisConfig
@@ -25,15 +20,14 @@ type IConfig interface {
25 20
 	GetRabbitMQConfig() *subconfigs.RabbitMQConfig
26 21
 
27 22
 	GetConsulConfig() *subconfigs.ConsulConfig
23
+	GetMongoDBConfig() *subconfigs.MongoDBConfig
28 24
 
29
-	GetHTTP() *subconfigs.HTTPConfig
30
-	GetMicro() *subconfigs.MicroConfig
31
-	GetLog() *subconfigs.LogConfig
32
-	GetInitError() error
25
+	GetHTTPConfig() *subconfigs.HTTPConfig
26
+	GetMicroConfig() *subconfigs.MicroConfig
27
+	GetLogConfig() *subconfigs.LogConfig
33 28
 
34 29
 	// 配置检查(更新)
35 30
 	IsDatabaseConfigured() bool
36
-	IsDatabaseConfiguredByName(name string) bool
37 31
 	IsDorisConfigured() bool
38 32
 	IsRedisConfigured() bool
39 33
 
@@ -49,60 +43,19 @@ type IConfig interface {
49 43
 
50 44
 // Config 主配置结构体 - 访问门面
51 45
 type Config struct {
52
-	initError error // 初始化错误
53
-}
54
-
55
-// ========== 数据库相关方法(更新) ==========
56
-
57
-// GetDatabases 获取所有数据库配置
58
-func (c *Config) GetDatabases() *subconfigs.DatabasesConfig {
59
-	if config := subconfigs.GetRegisteredConfig("databases"); config != nil {
60
-		if dbs, ok := config.(*subconfigs.DatabasesConfig); ok {
61
-			return dbs
62
-		}
63
-	}
64
-	return nil
65
-}
66
-
67
-// GetDatabase 获取默认数据库配置(向后兼容)
68
-func (c *Config) GetDatabase() *subconfigs.DatabaseConfig {
69
-	dbs := c.GetDatabases()
70
-	if dbs == nil {
71
-		logger.Errorf("获取默认数据库连接配置发生错误:配置为空!")
72
-		return nil
73
-	}
74
-	return dbs.GetDefaultDatabase()
46
+	loaded    bool            // 配置是否已加载
47
+	loadTime  string          // 配置加载时间(可选)
48
+	configMap map[string]bool // 已加载的配置类型映射
75 49
 }
76 50
 
77 51
 // GetDatabaseConfig 按名称获取数据库配置
78
-func (c *Config) GetDatabaseConfig(name string) *subconfigs.DatabaseConfig {
79
-	dbs := c.GetDatabases()
80
-	if dbs == nil {
81
-		return nil
82
-	}
83
-	return dbs.GetDatabase(name)
84
-}
85
-
86
-// IsDatabaseConfigured 检查默认数据库是否配置
87
-func (c *Config) IsDatabaseConfigured() bool {
88
-	dbs := c.GetDatabases()
89
-	if dbs == nil {
90
-		return false
52
+func (c *Config) GetDatabaseConfig() *subconfigs.DatabaseConfig {
53
+	if config := subconfigs.GetRegisteredConfig("database"); config != nil {
54
+		return config.(*subconfigs.DatabaseConfig)
91 55
 	}
92
-	return dbs.IsConfigured()
93
-}
94
-
95
-// IsDatabaseConfiguredByName 检查指定名称的数据库是否配置
96
-func (c *Config) IsDatabaseConfiguredByName(name string) bool {
97
-	dbs := c.GetDatabases()
98
-	if dbs == nil {
99
-		return false
100
-	}
101
-	return dbs.IsConfigured()
56
+	return nil
102 57
 }
103 58
 
104
-// ========== 其他配置方法(保持不变) ==========
105
-
106 59
 func (c *Config) GetRedisConfig() *subconfigs.RedisConfig {
107 60
 	if config := subconfigs.GetRegisteredConfig("redis"); config != nil {
108 61
 		return config.(*subconfigs.RedisConfig)
@@ -117,6 +70,13 @@ func (c *Config) GetConsulConfig() *subconfigs.ConsulConfig {
117 70
 	return nil
118 71
 }
119 72
 
73
+func (c *Config) GetMongoDBConfig() *subconfigs.MongoDBConfig {
74
+	if config := subconfigs.GetRegisteredConfig("mongodb"); config != nil {
75
+		return config.(*subconfigs.MongoDBConfig)
76
+	}
77
+	return nil
78
+}
79
+
120 80
 func (c *Config) GetDorisConfig() *subconfigs.DorisConfig {
121 81
 	if config := subconfigs.GetRegisteredConfig("doris"); config != nil {
122 82
 		return config.(*subconfigs.DorisConfig)
@@ -131,60 +91,37 @@ func (c *Config) GetRabbitMQConfig() *subconfigs.RabbitMQConfig {
131 91
 	return nil
132 92
 }
133 93
 
134
-// ========== 微服务相关方法(更新) ==========
135
-
136
-// GetServices 获取所有微服务配置
137
-func (c *Config) GetServices() *subconfigs.ServicesConfig {
138
-	if config := subconfigs.GetRegisteredConfig("services"); config != nil {
139
-		if dbs, ok := config.(*subconfigs.ServicesConfig); ok {
140
-			return dbs
141
-		}
94
+func (c *Config) GetServiceConfig() *subconfigs.ServiceConfig {
95
+	if config := subconfigs.GetRegisteredConfig("service"); config != nil {
96
+		return config.(*subconfigs.ServiceConfig)
142 97
 	}
143 98
 	return nil
144 99
 }
145 100
 
146
-// GetService 获取默认微服务配置(向后兼容)
147
-func (c *Config) GetService() *subconfigs.ServiceConfig {
148
-	dbs := c.GetServices()
149
-	if dbs == nil {
150
-		logger.Errorf("获取默认微服务配置发生错误:配置为空!")
151
-		return nil
152
-	}
153
-	return dbs.GetDefaultService()
154
-}
155
-
156
-// GetServiceConfig 按名称获取微服务配置
157
-func (c *Config) GetServiceConfig(name string) *subconfigs.ServiceConfig {
158
-	dbs := c.GetServices()
159
-	if dbs == nil {
160
-		return nil
161
-	}
162
-	return dbs.GetService(name)
163
-}
164
-
165
-func (c *Config) GetHTTP() *subconfigs.HTTPConfig {
101
+func (c *Config) GetHTTPConfig() *subconfigs.HTTPConfig {
166 102
 	if config := subconfigs.GetRegisteredConfig("http"); config != nil {
167 103
 		return config.(*subconfigs.HTTPConfig)
168 104
 	}
169 105
 	return nil
170 106
 }
171 107
 
172
-func (c *Config) GetMicro() *subconfigs.MicroConfig {
108
+func (c *Config) GetMicroConfig() *subconfigs.MicroConfig {
173 109
 	if config := subconfigs.GetRegisteredConfig("micro"); config != nil {
174 110
 		return config.(*subconfigs.MicroConfig)
175 111
 	}
176 112
 	return nil
177 113
 }
178 114
 
179
-func (c *Config) GetLog() *subconfigs.LogConfig {
115
+func (c *Config) GetLogConfig() *subconfigs.LogConfig {
180 116
 	if config := subconfigs.GetRegisteredConfig("log"); config != nil {
181 117
 		return config.(*subconfigs.LogConfig)
182 118
 	}
183 119
 	return nil
184 120
 }
185 121
 
186
-func (c *Config) GetInitError() error {
187
-	return c.initError
122
+func (c *Config) IsDatabaseConfigured() bool {
123
+	db := c.GetDatabaseConfig()
124
+	return db != nil && db.IsConfigured()
188 125
 }
189 126
 
190 127
 // 实现 IConfig 接口的其他方法
@@ -201,57 +138,39 @@ func (c *Config) IsRedisConfigured() bool {
201 138
 // 设置方法
202 139
 func (c *Config) SetAppEnv(name string) {
203 140
 	if c.GetAppEnv() == "" {
204
-		c.GetServices().AppEnv = name
141
+		c.GetServiceConfig().AppEnv = name
205 142
 	}
206 143
 }
207 144
 
208 145
 func (c *Config) SetAppName(name string) {
209 146
 	if c.GetAppName() == "" {
210
-		c.GetServices().AppName = name
147
+		c.GetServiceConfig().AppName = name
211 148
 	}
212 149
 }
213 150
 func (c *Config) SetAppVersion(name string) {
214 151
 	if c.GetAppVersion() == "" {
215
-		c.GetServices().AppVersion = name
152
+		c.GetServiceConfig().AppVersion = name
216 153
 	}
217 154
 }
218 155
 
219 156
 // GetAppVersion 获取服务版本
220 157
 func (c *Config) GetAppVersion() string {
221
-	return c.GetServices().AppVersion
158
+	return c.GetServiceConfig().AppVersion
222 159
 }
223 160
 
224 161
 // GetAppEnv 获取环境
225 162
 func (c *Config) GetAppEnv() string {
226
-	return c.GetServices().AppEnv
163
+	return c.GetServiceConfig().AppEnv
227 164
 }
228 165
 
229 166
 // GetAppName 获取当前应用名称
230 167
 func (c *Config) GetAppName() string {
231
-	return c.GetServices().AppName
168
+	return c.GetServiceConfig().AppName
232 169
 }
233 170
 
234 171
 // GetAppAuthToken 得到当前配置文件里的token
235 172
 func (c *Config) GetAppAuthToken() string {
236
-	return c.GetServices().AppAuthToken
237
-}
238
-
239
-// ========== 包级便捷函数(更新) ==========
240
-
241
-// GetDatabases 包级便捷函数 - 获取所有数据库配置
242
-func GetDatabases() *subconfigs.DatabasesConfig {
243
-	if cfgInstance == nil {
244
-		return nil
245
-	}
246
-	return cfgInstance.GetDatabases()
247
-}
248
-
249
-// GetDatabase 包级便捷函数 - 获取默认数据库配置(向后兼容)
250
-func GetDatabase() *subconfigs.DatabaseConfig {
251
-	if cfgInstance == nil {
252
-		return &subconfigs.DatabaseConfig{}
253
-	}
254
-	return cfgInstance.GetDatabase()
173
+	return c.GetServiceConfig().AppAuthToken
255 174
 }
256 175
 
257 176
 // GetDatabaseConfig 包级便捷函数 - 按名称获取数据库配置
@@ -259,11 +178,11 @@ func GetDatabaseConfig(name string) *subconfigs.DatabaseConfig {
259 178
 	if cfgInstance == nil {
260 179
 		return nil
261 180
 	}
262
-	return cfgInstance.GetDatabaseConfig(name)
181
+	return cfgInstance.GetDatabaseConfig()
263 182
 }
264 183
 
265 184
 // GetRedis 包级便捷函数 - 获取Redis配置
266
-func GetRedis() *subconfigs.RedisConfig {
185
+func GetRedisConfig() *subconfigs.RedisConfig {
267 186
 	if cfgInstance == nil {
268 187
 		return &subconfigs.RedisConfig{}
269 188
 	}
@@ -271,7 +190,7 @@ func GetRedis() *subconfigs.RedisConfig {
271 190
 }
272 191
 
273 192
 // GetRedis 包级便捷函数 - 获取Redis配置
274
-func GetConsul() *subconfigs.ConsulConfig {
193
+func GetConsulConfig() *subconfigs.ConsulConfig {
275 194
 	if cfgInstance == nil {
276 195
 		return &subconfigs.ConsulConfig{}
277 196
 	}
@@ -279,66 +198,79 @@ func GetConsul() *subconfigs.ConsulConfig {
279 198
 }
280 199
 
281 200
 // GetHTTP 包级便捷函数 - 获取HTTP配置
282
-func GetHTTP() *subconfigs.HTTPConfig {
201
+func GetHTTPConfig() *subconfigs.HTTPConfig {
283 202
 	if cfgInstance == nil {
284 203
 		return &subconfigs.HTTPConfig{}
285 204
 	}
286
-	return cfgInstance.GetHTTP()
205
+	return cfgInstance.GetHTTPConfig()
287 206
 }
288 207
 
289
-// GetLog 包级便捷函数 - 获取日志配置
290
-func GetLog() *subconfigs.LogConfig {
208
+// GetMongoDB 包级便捷函数 - 获取MongoDB配置
209
+func GetMongoDBConfig() *subconfigs.MongoDBConfig {
291 210
 	if cfgInstance == nil {
292
-		return &subconfigs.LogConfig{}
211
+		return &subconfigs.MongoDBConfig{}
293 212
 	}
294
-	return cfgInstance.GetLog()
213
+	return cfgInstance.GetMongoDBConfig()
295 214
 }
296 215
 
297
-func GetMicro() *subconfigs.MicroConfig {
216
+// GetLog 包级便捷函数 - 获取日志配置
217
+func GetLogConfig() *subconfigs.LogConfig {
298 218
 	if cfgInstance == nil {
299
-		return &subconfigs.MicroConfig{}
219
+		return &subconfigs.LogConfig{}
300 220
 	}
301
-	return cfgInstance.GetMicro()
221
+	return cfgInstance.GetLogConfig()
302 222
 }
303 223
 
304
-func GetService() *subconfigs.ServiceConfig {
224
+func GetMicroConfig() *subconfigs.MicroConfig {
305 225
 	if cfgInstance == nil {
306
-		return &subconfigs.ServiceConfig{}
226
+		return &subconfigs.MicroConfig{}
307 227
 	}
308
-	return cfgInstance.GetService()
228
+	return cfgInstance.GetMicroConfig()
309 229
 }
310 230
 
311
-// GetServiceConfig 包级便捷函数 - 按名称获取数微服务配置
312
-func GetServiceConfig(name string) *subconfigs.ServiceConfig {
231
+func GetServiceConfig() *subconfigs.ServiceConfig {
313 232
 	if cfgInstance == nil {
314
-		return nil
233
+		return &subconfigs.ServiceConfig{}
315 234
 	}
316
-	return cfgInstance.GetServiceConfig(name)
235
+	return cfgInstance.GetServiceConfig()
317 236
 }
318 237
 
319
-// ========== 单例管理 ==========
320
-
321 238
 var (
322 239
 	cfgInstance *Config
323 240
 	once        sync.Once
324 241
 )
325 242
 
326 243
 // GetConfig 获取主配置(单例模式)
327
-func GetConfig() (IConfig, error) {
244
+func GetConfig() IConfig {
328 245
 	once.Do(func() {
329
-		cfgInstance = &Config{}
330
-		cfgInstance.initError = LoadConfig() // 加载配置到注册表
246
+		cfgInstance = &Config{
247
+			loaded:    false,
248
+			configMap: make(map[string]bool),
249
+		}
250
+		LoadConfig() // 加载配置到注册表
251
+		cfgInstance.loaded = true
252
+		// 可以在这里记录配置加载成功的日志
331 253
 	})
332
-	return cfgInstance, cfgInstance.initError
254
+	return cfgInstance
333 255
 }
334 256
 
335
-// GetInitError 包级函数 - 兼容现有代码调用
336
-func GetInitError() error {
337
-	return cfgInstance.GetInitError()
257
+// IsConfigLoaded 检查配置是否已加载
258
+func (c *Config) IsConfigLoaded() bool {
259
+	return c.loaded
338 260
 }
339 261
 
340
-// GetConfigWithError 新方法 - 同时获取配置和错误
341
-func GetConfigWithError() (IConfig, error) {
342
-	cfg, err := GetConfig()
343
-	return cfg, err
262
+// MarkConfigLoaded 标记配置已加载
263
+func (c *Config) MarkConfigLoaded(configType string) {
264
+	if c.configMap == nil {
265
+		c.configMap = make(map[string]bool)
266
+	}
267
+	c.configMap[configType] = true
268
+}
269
+
270
+// IsConfigTypeLoaded 检查特定类型的配置是否已加载
271
+func (c *Config) IsConfigTypeLoaded(configType string) bool {
272
+	if c.configMap == nil {
273
+		return false
274
+	}
275
+	return c.configMap[configType]
344 276
 }

+ 9
- 9
config/loader.go Dosyayı Görüntüle

@@ -11,32 +11,34 @@ import (
11 11
 )
12 12
 
13 13
 // LoadConfig 从文件加载配置到注册表(保持原有接口不变)
14
-func LoadConfig() error {
14
+func LoadConfig() {
15 15
 	// 1. 查找配置文件
16 16
 	configFile, err := findConfigFile()
17 17
 	if err != nil {
18
-		return err
18
+		log.Fatalf("查找配置文件错误:%v", err)
19
+
19 20
 	}
20 21
 
21 22
 	// 2. 读取并解析文件
22 23
 	data, err := os.ReadFile(configFile)
23 24
 	if err != nil {
24
-		return fmt.Errorf("read config file error: %v", err)
25
+		log.Fatalf("read config file error: %v", err)
25 26
 	}
26 27
 
27 28
 	var rawConfig map[string]interface{}
28 29
 	err = yaml.Unmarshal(data, &rawConfig)
29 30
 	if err != nil {
30
-		return fmt.Errorf("parse yaml error: %v", err)
31
+		log.Fatalf("parse yaml error: %v", err)
32
+
31 33
 	}
32 34
 
33 35
 	// 3. 从map加载配置
34
-	return LoadConfigFromMap(rawConfig)
36
+	LoadConfigFromMap(rawConfig)
35 37
 }
36 38
 
37 39
 // LoadConfigFromMap 从map[string]interface{}加载配置到注册表
38 40
 // 新增方法,供外部调用(比如从数据库加载后使用)
39
-func LoadConfigFromMap(rawConfig map[string]interface{}) error {
41
+func LoadConfigFromMap(rawConfig map[string]interface{}) {
40 42
 	// 1. 设置所有注册配置的默认值
41 43
 	for _, config := range subconfigs.GetAllConfigs() {
42 44
 		config.SetDefaults()
@@ -48,12 +50,10 @@ func LoadConfigFromMap(rawConfig map[string]interface{}) error {
48 50
 			// 转换为 map[string]interface{}
49 51
 			strMap := convertMap(configData)
50 52
 			if err := config.Load(strMap); err != nil {
51
-				return fmt.Errorf("load config %s error: %v", name, err)
53
+				log.Fatalf("load config %s error: %v", name, err)
52 54
 			}
53 55
 		}
54 56
 	}
55
-
56
-	return nil
57 57
 }
58 58
 
59 59
 // convertMap 转换map类型(内部函数保持不变)

+ 1
- 1
config/subconfigs/consul_config.go Dosyayı Görüntüle

@@ -15,7 +15,7 @@ func NewConsulConfig() *ConsulConfig {
15 15
 }
16 16
 
17 17
 func (c *ConsulConfig) SetDefaults() {
18
-	c.Address = "localhost:8500"
18
+	//c.Address = "localhost:8500"
19 19
 	c.Scheme = "http"
20 20
 }
21 21
 

+ 2
- 177
config/subconfigs/database_config.go Dosyayı Görüntüle

@@ -5,11 +5,6 @@ import (
5 5
 	"log"
6 6
 )
7 7
 
8
-type DatabasesConfig struct {
9
-	BaseConfig
10
-	Databases map[string]*DatabaseConfig `yaml:"databases"`
11
-}
12
-
13 8
 // DatabaseConfig 数据库配置
14 9
 type DatabaseConfig struct {
15 10
 	BaseConfig
@@ -24,61 +19,6 @@ type DatabaseConfig struct {
24 19
 	ConnMaxLifetime int    `yaml:"conn_max_lifetime"`
25 20
 }
26 21
 
27
-// ========== DatabasesConfig 实现 ConfigLoader 接口 ==========
28
-
29
-// SetDefaults 设置默认值 - 实现 ConfigLoader 接口
30
-func (c *DatabasesConfig) SetDefaults() {
31
-	//因为是多集合,外层调这里赋默认值,这个时候对象还没有建立。赋默认值的地方移到其他地方去
32
-	// if c.Databases == nil {
33
-	// 	c.Databases = make(map[string]*DatabaseConfig)
34
-	// 	log.Println("⚠️  数据库配置为空,已初始化空的数据库配置")
35
-	// 	return
36
-	// }
37
-
38
-	// // 为每个数据库配置设置默认值
39
-	// for _, db := range c.Databases {
40
-	// 	if db != nil {
41
-	// 		db.SetDefaults()
42
-	// 	}
43
-	// }
44
-}
45
-
46
-func (c *DatabasesConfig) Load(data map[string]interface{}) error {
47
-	// 初始化
48
-	c.Databases = make(map[string]*DatabaseConfig)
49
-
50
-	// 遍历所有数据库配置
51
-	for dbName, dbData := range data {
52
-		dbDataMap, ok := dbData.(map[interface{}]interface{})
53
-		if !ok {
54
-			return fmt.Errorf("database '%s' config is not a map", dbName)
55
-		}
56
-
57
-		// 转换为 map[string]interface{}
58
-		stringMap := make(map[string]interface{})
59
-		for k, v := range dbDataMap {
60
-			if key, ok := k.(string); ok {
61
-				stringMap[key] = v
62
-			}
63
-		}
64
-
65
-		dbConfig := &DatabaseConfig{}
66
-		dbConfig.SetDefaults() // 先设置默认值
67
-		// 加载单个数据库配置
68
-		if err := dbConfig.Load(stringMap); err != nil {
69
-			return fmt.Errorf("failed to load database '%s' config: %v", dbName, err)
70
-		}
71
-
72
-		c.Databases[dbName] = dbConfig
73
-	}
74
-
75
-	// 设置默认值和验证
76
-	c.SetDefaults()
77
-	return c.Validate()
78
-}
79
-
80
-// ========== DatabaseConfig 实现 ConfigLoader 接口 ==========
81
-
82 22
 // SetDefaults 设置默认值 - 实现 ConfigLoader 接口
83 23
 func (c *DatabaseConfig) SetDefaults() {
84 24
 	if c.Type == "" {
@@ -100,12 +40,10 @@ func (c *DatabaseConfig) SetDefaults() {
100 40
 
101 41
 // Load 从yaml数据加载 - 实现 ConfigLoader 接口
102 42
 func (c *DatabaseConfig) Load(data map[string]interface{}) error {
103
-	// 虽然可能不会被直接调用,但为了接口完整性还是要实现
43
+
104 44
 	return c.LoadFromYAML(data, c)
105 45
 }
106 46
 
107
-// ========== 业务方法 ==========
108
-
109 47
 // Validate 验证配置(数据库配置)
110 48
 func (c *DatabaseConfig) Validate() error {
111 49
 	if c.Type == "" {
@@ -123,37 +61,6 @@ func (c *DatabaseConfig) Validate() error {
123 61
 	return nil
124 62
 }
125 63
 
126
-// Validate 验证配置(多数据库配置)
127
-func (c *DatabasesConfig) Validate() error {
128
-	if c.Databases == nil {
129
-		log.Println("❌ 错误: 未找到任何数据库配置,请检查配置文件中的 'databases' 配置")
130
-		return fmt.Errorf("no databases configurations found")
131
-	}
132
-
133
-	// 必须要有默认数据库
134
-	if _, exists := c.Databases["default"]; !exists {
135
-		availableDBs := c.GetAllDatabaseNames()
136
-		log.Printf("❌ 错误: 默认数据库未找到。可用的数据库: %v。请在配置文件中添加 'default' 数据库", availableDBs)
137
-		return fmt.Errorf("default database not found")
138
-	}
139
-
140
-	// 验证每个数据库配置
141
-	for name, db := range c.Databases {
142
-		if db == nil {
143
-			log.Printf("❌ 错误: 数据库 '%s' 配置为空", name)
144
-			return fmt.Errorf("database '%s' configuration is nil", name)
145
-		}
146
-
147
-		if err := db.Validate(); err != nil {
148
-			log.Printf("❌ 错误: 数据库 '%s' 验证失败: %v", name, err)
149
-			return fmt.Errorf("database '%s' validation failed: %v", name, err)
150
-		}
151
-	}
152
-
153
-	log.Printf("✅ 数据库配置验证通过,找到 %d 个数据库配置", len(c.Databases))
154
-	return nil
155
-}
156
-
157 64
 // IsConfigured 判断是否已配置(数据库配置)
158 65
 func (c *DatabaseConfig) IsConfigured() bool {
159 66
 	if c.Host == "" {
@@ -175,89 +82,7 @@ func (c *DatabaseConfig) IsConfigured() bool {
175 82
 	return true
176 83
 }
177 84
 
178
-// IsConfigured 判断是否已配置(多数据库配置)
179
-func (c *DatabasesConfig) IsConfigured() bool {
180
-	defaultDB := c.GetDefaultDatabase()
181
-	if defaultDB == nil {
182
-		log.Println("❌ 错误: 默认数据库不存在")
183
-		return false
184
-	}
185
-
186
-	if !defaultDB.IsConfigured() {
187
-		log.Println("❌ 错误: 默认数据库配置不完整")
188
-		return false
189
-	}
190
-
191
-	return true
192
-}
193
-
194
-// GetDefaultDatabase 获取默认数据库(必须存在)
195
-func (c *DatabasesConfig) GetDefaultDatabase() *DatabaseConfig {
196
-	if c.Databases == nil {
197
-		log.Println("❌ 错误: 尝试获取默认数据库时,数据库配置为空")
198
-		return nil
199
-	}
200
-
201
-	if db, exists := c.Databases["default"]; exists {
202
-		return db
203
-	}
204
-
205
-	// 如果没有名为default的,尝试返回第一个(但会记录警告)
206
-	for name, db := range c.Databases {
207
-		log.Printf("⚠️  警告: 未找到名为 'default' 的数据库,使用第一个数据库 '%s' 作为默认", name)
208
-		return db
209
-	}
210
-
211
-	log.Println("❌ 错误: 数据库中没有任何配置")
212
-	return nil
213
-}
214
-
215
-// GetDatabase 按名称获取数据库(为空时记录错误)
216
-func (c *DatabasesConfig) GetDatabase(name string) *DatabaseConfig {
217
-	if c.Databases == nil {
218
-		log.Printf("❌ 错误: 尝试获取数据库 '%s' 时,数据库配置为空", name)
219
-		return nil
220
-	}
221
-
222
-	db := c.Databases[name]
223
-	if db == nil {
224
-		availableDBs := c.GetAllDatabaseNames()
225
-		log.Printf("❌ 错误: 数据库 '%s' 不存在。可用的数据库: %v", name, availableDBs)
226
-	}
227
-
228
-	return db
229
-}
230
-
231
-// GetAllDatabaseNames 获取所有数据库名称
232
-func (c *DatabasesConfig) GetAllDatabaseNames() []string {
233
-	if c.Databases == nil {
234
-		log.Println("⚠️  警告: 尝试获取数据库名称时,数据库配置为空")
235
-		return []string{}
236
-	}
237
-
238
-	names := make([]string, 0, len(c.Databases))
239
-	for name := range c.Databases {
240
-		names = append(names, name)
241
-	}
242
-	return names
243
-}
244
-
245
-// GetDatabaseNamesWithoutDefault 获取除default外的所有数据库名称
246
-func (c *DatabasesConfig) GetDatabaseNamesWithoutDefault() []string {
247
-	if c.Databases == nil {
248
-		return []string{}
249
-	}
250
-
251
-	names := make([]string, 0, len(c.Databases)-1)
252
-	for name := range c.Databases {
253
-		if name != "default" {
254
-			names = append(names, name)
255
-		}
256
-	}
257
-	return names
258
-}
259
-
260 85
 // 自动注册
261 86
 func init() {
262
-	Register("databases", &DatabasesConfig{})
87
+	Register("database", &DatabaseConfig{})
263 88
 }

+ 68
- 0
config/subconfigs/mongodb_config.go Dosyayı Görüntüle

@@ -0,0 +1,68 @@
1
+package subconfigs
2
+
3
+import (
4
+	"fmt"
5
+	"time"
6
+)
7
+
8
+// MongoDBConfig MongoDB客户端配置
9
+type MongoDBConfig struct {
10
+	BaseConfig
11
+	URI         string        `yaml:"uri"`         // MongoDB连接URI,如:"mongodb://localhost:27017"
12
+	Database    string        `yaml:"database"`    // 默认数据库名
13
+	Username    string        `yaml:"username"`    // 用户名(可选)
14
+	Password    string        `yaml:"password"`    // 密码(可选)
15
+	AuthSource  string        `yaml:"authSource"`  // 认证数据库,默认:"admin"
16
+	MaxPoolSize uint64        `yaml:"maxPoolSize"` // 最大连接池大小
17
+	MinPoolSize uint64        `yaml:"minPoolSize"` // 最小连接池大小
18
+	SSL         bool          `yaml:"ssl"`         // 是否使用SSL连接
19
+	Timeout     time.Duration `yaml:"timeout"`     // 连接超时时间(毫秒)
20
+}
21
+
22
+// NewMongoDBConfig 创建MongoDB配置实例
23
+func NewMongoDBConfig() *MongoDBConfig {
24
+	return &MongoDBConfig{}
25
+}
26
+
27
+// SetDefaults 设置默认值
28
+func (c *MongoDBConfig) SetDefaults() {
29
+	c.Username = ""
30
+	c.Password = ""
31
+	c.MaxPoolSize = 100
32
+	c.MinPoolSize = 10
33
+	c.SSL = false
34
+	c.Timeout = 30
35
+}
36
+
37
+// Load 从YAML数据加载配置
38
+func (c *MongoDBConfig) Load(data map[string]interface{}) error {
39
+	return c.LoadFromYAML(data, c)
40
+}
41
+
42
+// Validate 验证配置
43
+func (c *MongoDBConfig) Validate() error {
44
+	if c.URI == "" {
45
+		return fmt.Errorf("mongodb URI must be configured")
46
+	}
47
+	if c.Database == "" {
48
+		return fmt.Errorf("mongodb database name must be configured")
49
+	}
50
+	if c.MaxPoolSize < c.MinPoolSize {
51
+		return fmt.Errorf("maxPoolSize must be greater than or equal to minPoolSize")
52
+	}
53
+	if c.Timeout <= 0 {
54
+		return fmt.Errorf("timeout must be a positive integer")
55
+	}
56
+
57
+	return nil
58
+}
59
+
60
+// IsConfigured 检查是否已配置
61
+func (c *MongoDBConfig) IsConfigured() bool {
62
+	return c.URI != "" && c.Database != ""
63
+}
64
+
65
+// 自动注册
66
+func init() {
67
+	Register("mongodb", &MongoDBConfig{})
68
+}

config/subconfigs/register.go → config/subconfigs/register_config.go Dosyayı Görüntüle


+ 9
- 166
config/subconfigs/service_config.go Dosyayı Görüntüle

@@ -6,18 +6,14 @@ import (
6 6
 	"log"
7 7
 )
8 8
 
9
-type ServicesConfig struct {
10
-	BaseConfig
11
-	AppName      string                    `yaml:"app_name"`       //当前应用名称
12
-	AppVersion   string                    `yaml:"app_version"`    //当前应用版本
13
-	AppEnv       string                    `yaml:"app_env"`        //环境参数 dev test prod
14
-	AppAuthToken string                    `yaml:"app_auth_token"` //使用静态认证的时候使用的token
15
-	Services     map[string]*ServiceConfig `yaml:"services"`       //多个服务配置项
16
-}
17
-
18
-// DatabaseConfig 数据库配置
9
+// ServiceConfig 数据库配置
19 10
 type ServiceConfig struct {
20 11
 	BaseConfig
12
+	AppName      string `yaml:"app_name"`       //当前应用名称
13
+	AppVersion   string `yaml:"app_version"`    //当前应用版本
14
+	AppEnv       string `yaml:"app_env"`        //环境参数 dev test prod
15
+	AppAuthToken string `yaml:"app_auth_token"` //使用静态认证的时候使用的token
16
+
21 17
 	Port         int    `yaml:"port"`
22 18
 	ServiceName  string `yaml:"service_name"`
23 19
 	InstanceName string `yaml:"instance_name"`
@@ -27,51 +23,11 @@ type ServiceConfig struct {
27 23
 }
28 24
 
29 25
 // SetDefaults 设置默认值 - 实现 ConfigLoader 接口
30
-func (c *ServicesConfig) SetDefaults() {
26
+func (c *ServiceConfig) SetDefaults() {
27
+
31 28
 	if c.AppEnv == "" {
32 29
 		c.AppEnv = "dev"
33 30
 	}
34
-	//因为是多集合,外层调这里赋默认值,这个时候对象还没有建立。赋默认值的地方移到其他地方去
35
-}
36
-
37
-func (c *ServicesConfig) Load(data map[string]interface{}) error {
38
-	// 初始化
39
-	c.Services = make(map[string]*ServiceConfig)
40
-
41
-	// 遍历所有配置
42
-	for dbName, dbData := range data {
43
-		dbDataMap, ok := dbData.(map[interface{}]interface{})
44
-		if !ok {
45
-			return fmt.Errorf("service '%s' config is not a map", dbName)
46
-		}
47
-
48
-		// 转换为 map[string]interface{}
49
-		stringMap := make(map[string]interface{})
50
-		for k, v := range dbDataMap {
51
-			if key, ok := k.(string); ok {
52
-				stringMap[key] = v
53
-			}
54
-		}
55
-
56
-		// 创建 ServiceConfig 对象并设置默认值
57
-		dbConfig := &ServiceConfig{}
58
-		dbConfig.SetDefaults() // 先设置默认值
59
-
60
-		// 加载单个服务配置
61
-		if err := dbConfig.Load(stringMap); err != nil {
62
-			return fmt.Errorf("failed to load servuce '%s' config: %v", dbName, err)
63
-		}
64
-
65
-		c.Services[dbName] = dbConfig
66
-	}
67
-
68
-	// 设置默认值和验证
69
-	//c.SetDefaults()
70
-	return c.Validate()
71
-}
72
-
73
-// SetDefaults 设置默认值 - 实现 ConfigLoader 接口
74
-func (c *ServiceConfig) SetDefaults() {
75 31
 
76 32
 	if c.Port == 0 {
77 33
 		c.Port = 8080
@@ -105,37 +61,6 @@ func (c *ServiceConfig) Validate() error {
105 61
 	return nil
106 62
 }
107 63
 
108
-// Validate 验证配置(多数据库配置)
109
-func (c *ServicesConfig) Validate() error {
110
-	if c.Services == nil {
111
-		log.Println("❌ 错误: 未找到任何微服务配置,请检查配置文件中的 'services' 配置")
112
-		return fmt.Errorf("no services configurations found")
113
-	}
114
-
115
-	// 必须要有默认数据库
116
-	if _, exists := c.Services["default"]; !exists {
117
-		availableDBs := c.GetAllServiceNames()
118
-		log.Printf("❌ 错误: 默认微服务配置未找到。可用的微服务配置: %v。请在配置文件中添加 'default' 微服务", availableDBs)
119
-		return fmt.Errorf("default service not found")
120
-	}
121
-
122
-	// 验证每个数据库配置
123
-	for name, db := range c.Services {
124
-		if db == nil {
125
-			log.Printf("❌ 错误: 微服务 '%s' 配置为空", name)
126
-			return fmt.Errorf("service '%s' configuration is nil", name)
127
-		}
128
-
129
-		if err := db.Validate(); err != nil {
130
-			log.Printf("❌ 错误: 微服务 '%s' 验证失败: %v", name, err)
131
-			return fmt.Errorf("service '%s' validation failed: %v", name, err)
132
-		}
133
-	}
134
-
135
-	log.Printf("✅ 微服务配置验证通过,找到 %d 个微服务配置", len(c.Services))
136
-	return nil
137
-}
138
-
139 64
 // IsConfigured 判断是否已配置(数据库配置)
140 65
 func (c *ServiceConfig) IsConfigured() bool {
141 66
 
@@ -147,89 +72,7 @@ func (c *ServiceConfig) IsConfigured() bool {
147 72
 	return true
148 73
 }
149 74
 
150
-// IsConfigured 判断是否已配置(多数据库配置)
151
-func (c *ServicesConfig) IsConfigured() bool {
152
-	defaultDB := c.GetDefaultService()
153
-	if defaultDB == nil {
154
-		log.Println("❌ 错误: 默认微服务不存在")
155
-		return false
156
-	}
157
-
158
-	if !defaultDB.IsConfigured() {
159
-		log.Println("❌ 错误: 默认微服务配置不完整")
160
-		return false
161
-	}
162
-
163
-	return true
164
-}
165
-
166
-// GetDefaultService 获取默认微服务(必须存在)
167
-func (c *ServicesConfig) GetDefaultService() *ServiceConfig {
168
-	if c.Services == nil {
169
-		log.Println("❌ 错误: 尝试获取默认微服务时,微服务配置为空")
170
-		return nil
171
-	}
172
-
173
-	if db, exists := c.Services["default"]; exists {
174
-		return db
175
-	}
176
-
177
-	// 如果没有名为default的,尝试返回第一个(但会记录警告)
178
-	for name, db := range c.Services {
179
-		log.Printf("⚠️  警告: 未找到名为 'default' 的微服务,使用第一个微服务 '%s' 作为默认", name)
180
-		return db
181
-	}
182
-
183
-	log.Println("❌ 错误: 服务模块配置中没有任何配置")
184
-	return nil
185
-}
186
-
187
-// GetService 按名称获取微服务(为空时记录错误)
188
-func (c *ServicesConfig) GetService(name string) *ServiceConfig {
189
-	if c.Services == nil {
190
-		log.Printf("❌ 错误: 尝试获取微服务 '%s' 时,微服务配置为空", name)
191
-		return nil
192
-	}
193
-
194
-	db := c.Services[name]
195
-	if db == nil {
196
-		availableDBs := c.GetAllServiceNames()
197
-		log.Printf("❌ 错误: 微服务 '%s' 不存在。可用的微服务: %v", name, availableDBs)
198
-	}
199
-
200
-	return db
201
-}
202
-
203
-// GetAllServiceNames 获取所有数据库名称
204
-func (c *ServicesConfig) GetAllServiceNames() []string {
205
-	if c.Services == nil {
206
-		log.Println("⚠️  警告: 尝试获取微服务配置节点名称时,微服务配置为空")
207
-		return []string{}
208
-	}
209
-
210
-	names := make([]string, 0, len(c.Services))
211
-	for name := range c.Services {
212
-		names = append(names, name)
213
-	}
214
-	return names
215
-}
216
-
217
-// GetServiceNamesWithoutDefault 获取除default外的所有微服务配置节点名称
218
-func (c *ServicesConfig) GetServiceNamesWithoutDefault() []string {
219
-	if c.Services == nil {
220
-		return []string{}
221
-	}
222
-
223
-	names := make([]string, 0, len(c.Services)-1)
224
-	for name := range c.Services {
225
-		if name != "default" {
226
-			names = append(names, name)
227
-		}
228
-	}
229
-	return names
230
-}
231
-
232 75
 // 自动注册
233 76
 func init() {
234
-	Register("services", &ServicesConfig{})
77
+	Register("service", &ServiceConfig{})
235 78
 }

+ 66
- 21
consul/register_consul.go Dosyayı Görüntüle

@@ -7,12 +7,33 @@ import (
7 7
 	"time"
8 8
 
9 9
 	"git.x2erp.com/qdy/go-base/client"
10
+	"git.x2erp.com/qdy/go-base/config"
10 11
 	"git.x2erp.com/qdy/go-base/config/subconfigs"
12
+
11 13
 	"github.com/hashicorp/consul/api"
12 14
 )
13 15
 
16
+type ConsulFactory struct {
17
+	config config.IConfig
18
+	ip     string
19
+}
20
+
14 21
 // Register 注册服务到Consul
15
-func Register(serviceName, configHostname string, port int, consulConfig *subconfigs.ConsulConfig) error {
22
+func Register(cfg config.IConfig) *ConsulFactory {
23
+
24
+	serviceName := cfg.GetServiceConfig().ServiceName
25
+	port := cfg.GetServiceConfig().Port
26
+	consulConfig := cfg.GetConsulConfig()
27
+	configHostname := client.GetServiceIP("")
28
+
29
+	if consulConfig == nil || !consulConfig.IsConfigured() {
30
+		log.Println("未配置consul注册发现中心,微服务按单体服务运行.")
31
+		return &ConsulFactory{
32
+			config: cfg,
33
+			ip:     configHostname,
34
+		}
35
+	}
36
+
16 37
 	// 1. 获取IP
17 38
 	ip := client.GetServiceIP(configHostname)
18 39
 	log.Printf("注册服务 %s -> %s:%d 到 %s", serviceName, ip, port, consulConfig.Address)
@@ -36,13 +57,13 @@ func Register(serviceName, configHostname string, port int, consulConfig *subcon
36 57
 	// 3. 创建客户端
37 58
 	client, err := api.NewClient(apiConfig)
38 59
 	if err != nil {
39
-		return fmt.Errorf("创建Consul客户端失败: %v", err)
60
+		log.Fatalf("创建Consul客户端失败: %v", err)
40 61
 	}
41 62
 
42 63
 	// 4. 测试连接
43 64
 	_, err = client.Agent().Self()
44 65
 	if err != nil {
45
-		return fmt.Errorf("无法连接到Consul服务器 %s: %v", apiConfig.Address, err)
66
+		log.Fatalf("无法连接到Consul服务器 %s: %v", apiConfig.Address, err)
46 67
 	}
47 68
 	log.Printf("✅ 成功连接到Consul服务器: %s", apiConfig.Address)
48 69
 
@@ -69,25 +90,32 @@ func Register(serviceName, configHostname string, port int, consulConfig *subcon
69 90
 
70 91
 	err = client.Agent().ServiceRegister(registration)
71 92
 	if err != nil {
72
-		return fmt.Errorf("consul注册失败: %v", err)
93
+		log.Fatalf("consul注册失败: %v", err)
73 94
 	}
74 95
 
75 96
 	// 打印详细注册信息
76
-	log.Printf("✅ 服务已注册到Consul服务器: %s", consulConfig.Address)
77
-	log.Printf("📋 注册详情:")
78
-	log.Printf("   服务名称: %s", serviceName)
79
-	log.Printf("   服务地址: %s:%d", ip, port)
80
-	log.Printf("   服务ID: %s", registration.ID)
81
-	log.Printf("   健康检查: %s", registration.Check.HTTP)
82
-	log.Printf("   检查间隔: %s", registration.Check.Interval)
83
-	log.Printf("   检查超时: %s", registration.Check.Timeout)
84
-	log.Printf("   失败注销: %s", registration.Check.DeregisterCriticalServiceAfter)
85
-
86
-	return nil
97
+	//log.Printf("✅ 服务已注册到Consul服务器: %s", consulConfig.Address)
98
+	log.Printf("📋注册详情:")
99
+	log.Printf("-服务名称: %s", serviceName)
100
+	log.Printf("-服务地址: %s:%d", ip, port)
101
+	log.Printf("-服务ID: %s", registration.ID)
102
+	log.Printf("-健康检查: %s", registration.Check.HTTP)
103
+	log.Printf("-检查间隔: %s", registration.Check.Interval)
104
+	log.Printf("-检查超时: %s", registration.Check.Timeout)
105
+	log.Printf("-失败注销: %s", registration.Check.DeregisterCriticalServiceAfter)
106
+
107
+	return &ConsulFactory{
108
+		config: cfg,
109
+		ip:     configHostname,
110
+	}
87 111
 }
88 112
 
89 113
 // CheckRegistration 检查服务是否已注册
90 114
 func CheckRegistration(serviceName, configHostname string, port int, consulConfig *subconfigs.ConsulConfig) error {
115
+	if consulConfig == nil || !consulConfig.IsConfigured() {
116
+		log.Println("未配置consul注册发现中心,微服务按单体服务运行.")
117
+		return nil
118
+	}
91 119
 	ip := client.GetServiceIP(configHostname)
92 120
 	serviceID := fmt.Sprintf("%s-%s-%d", serviceName, ip, port)
93 121
 
@@ -128,9 +156,23 @@ func CheckRegistration(serviceName, configHostname string, port int, consulConfi
128 156
 	return fmt.Errorf("服务未注册: %s", serviceID)
129 157
 }
130 158
 
131
-// Deregister 注销服务
132
-func Deregister(serviceName, ip string, port int, consulConfig *subconfigs.ConsulConfig) error {
133
-	serviceID := fmt.Sprintf("%s-%s-%d", serviceName, ip, port)
159
+func (c *ConsulFactory) GetName() string {
160
+	return "ConsulFactory"
161
+}
162
+
163
+// Close 注销服务
164
+func (c *ConsulFactory) Close() {
165
+
166
+	serviceName := c.config.GetServiceConfig().ServiceName
167
+	port := c.config.GetServiceConfig().Port
168
+	consulConfig := c.config.GetConsulConfig()
169
+
170
+	if consulConfig == nil || !consulConfig.IsConfigured() {
171
+		log.Println("未配置consul注册发现中心,服务不用到注册中心进行注销.")
172
+
173
+	}
174
+
175
+	serviceID := fmt.Sprintf("%s-%s-%d", serviceName, c.ip, port)
134 176
 
135 177
 	// 创建客户端
136 178
 	apiConfig := api.DefaultConfig()
@@ -139,15 +181,18 @@ func Deregister(serviceName, ip string, port int, consulConfig *subconfigs.Consu
139 181
 	}
140 182
 	client, err := api.NewClient(apiConfig)
141 183
 	if err != nil {
142
-		return fmt.Errorf("创建consul客户端失败: %v", err)
184
+		log.Printf("创建consul客户端失败: %v", err)
185
+		return
143 186
 	}
144 187
 
145 188
 	// 注销服务
146 189
 	err = client.Agent().ServiceDeregister(serviceID)
147 190
 	if err != nil {
148
-		return fmt.Errorf("从consul注销服务失败 (ID: %s): %v", serviceID, err)
191
+
192
+		log.Printf("从consul注销服务失败 (ID: %s): %v", serviceID, err)
193
+		return
149 194
 	}
150 195
 
151 196
 	log.Printf("✅ 已从consul注销服务: %s", serviceID)
152
-	return nil
197
+	return
153 198
 }

+ 103
- 0
container/container_factory.go Dosyayı Görüntüle

@@ -0,0 +1,103 @@
1
+// container_factory.go
2
+package container
3
+
4
+import (
5
+	"log"
6
+	"sync"
7
+
8
+	"git.x2erp.com/qdy/go-base/config"
9
+)
10
+
11
+type Resource interface {
12
+	GetName() string
13
+	Close()
14
+}
15
+
16
+type CreateFunc[T Resource] func(cfg config.IConfig) T
17
+
18
+type ContainerFactory struct {
19
+	config    config.IConfig
20
+	resources map[string]Resource // 用map按名称存储
21
+	order     []string            // 保持添加顺序
22
+	mu        sync.RWMutex
23
+}
24
+
25
+func NewContainer(cfg config.IConfig) *ContainerFactory {
26
+	return &ContainerFactory{
27
+		config:    cfg,
28
+		resources: make(map[string]Resource),
29
+		order:     make([]string, 0),
30
+	}
31
+}
32
+
33
+// 泛型方法:如果不存在则创建并注册
34
+func Create[T Resource](c *ContainerFactory, createFunc CreateFunc[T]) T {
35
+	//c.mu.Lock()
36
+	//defer c.mu.Unlock()
37
+
38
+	// 先创建对象获取名称
39
+	resource := createFunc(c.config)
40
+	return Reg(c, resource)
41
+	// name := resource.GetName()
42
+
43
+	// log.Printf("创建 %s 对象", name)
44
+
45
+	// // 如果已存在,返回已注册的对象
46
+	// if existing, ok := c.resources[name]; ok {
47
+	// 	log.Printf("对象 %s 已经存在.", name)
48
+	// 	return existing.(T) // 安全,因为同名的类型肯定相同
49
+	// }
50
+
51
+	// log.Printf("缓存 %s 对象", name)
52
+
53
+	// // 添加到order(保持顺序)
54
+	// c.order = append(c.order, name)
55
+
56
+	// // 存储到map
57
+	// c.resources[name] = resource
58
+	// return resource
59
+}
60
+
61
+// / Reg 直接注册已创建的对象
62
+func Reg[T Resource](c *ContainerFactory, resource T) T {
63
+	c.mu.Lock()
64
+	defer c.mu.Unlock()
65
+
66
+	name := resource.GetName()
67
+	log.Printf("直接注册 %s 对象", name)
68
+
69
+	// 如果已存在,返回已注册的对象(或报错)
70
+	if existing, ok := c.resources[name]; ok {
71
+		log.Printf("对象 %s 已经存在,跳过注册", name)
72
+		// 可以选择返回已有的对象或什么都不做
73
+		return existing.(T) // 安全,因为同名的类型肯定相同
74
+	}
75
+
76
+	log.Printf("缓存 %s 对象", name)
77
+
78
+	// 添加到order(保持顺序)
79
+	c.order = append(c.order, name)
80
+
81
+	// 存储到map
82
+	c.resources[name] = resource
83
+	log.Printf("已注册 %s 对象", name)
84
+	return resource
85
+}
86
+
87
+// 按添加顺序关闭(先进先出,最先添加的最先关闭)
88
+func (c *ContainerFactory) CloseAll() {
89
+	c.mu.Lock()
90
+	defer c.mu.Unlock()
91
+
92
+	// 按添加顺序关闭
93
+	for _, name := range c.order {
94
+		if res, ok := c.resources[name]; ok {
95
+			res.Close()
96
+			log.Printf("关闭 %s 对象", name)
97
+		}
98
+	}
99
+
100
+	// 清空容器
101
+	c.resources = make(map[string]Resource)
102
+	c.order = make([]string, 0)
103
+}

+ 1
- 0
go.mod Dosyayı Görüntüle

@@ -55,6 +55,7 @@ require (
55 55
 	github.com/go-git/go-git/v5 v5.16.4 // indirect
56 56
 	github.com/golang/protobuf v1.5.4 // indirect
57 57
 	github.com/google/uuid v1.6.0 // indirect
58
+	github.com/iancoleman/strcase v0.3.0
58 59
 	github.com/imdario/mergo v0.3.16 // indirect
59 60
 	github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
60 61
 	github.com/kevinburke/ssh_config v1.4.0 // indirect

+ 2
- 0
go.sum Dosyayı Görüntüle

@@ -105,6 +105,8 @@ github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC
105 105
 github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
106 106
 github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM=
107 107
 github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
108
+github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
109
+github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
108 110
 github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
109 111
 github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
110 112
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=

+ 13
- 6
logger/boot_logger.go Dosyayı Görüntüle

@@ -10,22 +10,25 @@ import (
10 10
 	"time"
11 11
 )
12 12
 
13
+type BootLoggerFactory struct {
14
+}
15
+
13 16
 var (
14 17
 	bootLogFile *os.File
15 18
 	bootLogger  *log.Logger
16 19
 )
17 20
 
18 21
 // InitBootLogger 初始化启动日志(只在启动阶段使用)
19
-func InitBootLog(serviceName string) error {
22
+func InitBootLog() *BootLoggerFactory {
20 23
 
21 24
 	if logToFile := os.Getenv("LOG_TO_FILE"); logToFile == "false" {
22
-		return nil
25
+		return &BootLoggerFactory{}
23 26
 	}
24 27
 
25 28
 	// 1. 确保日志目录存在
26 29
 	logDir := "logs"
27 30
 	if err := os.MkdirAll(logDir, 0755); err != nil {
28
-		return fmt.Errorf("创建日志目录失败: %v", err)
31
+		log.Fatalf("创建日志目录失败: %v", err)
29 32
 	}
30 33
 
31 34
 	// 2. 创建启动日志文件
@@ -35,7 +38,7 @@ func InitBootLog(serviceName string) error {
35 38
 
36 39
 	file, err := os.Create(filePath)
37 40
 	if err != nil {
38
-		return fmt.Errorf("创建启动日志文件失败: %v", err)
41
+		log.Fatalf("创建启动日志文件失败: %v", err)
39 42
 	}
40 43
 
41 44
 	bootLogFile = file
@@ -54,7 +57,7 @@ func InitBootLog(serviceName string) error {
54 57
 	BootLog("启动时间: %s", time.Now().Format("2006-01-02 15:04:05"))
55 58
 	BootLog("启动日志文件: %s", filePath)
56 59
 
57
-	return nil
60
+	return &BootLoggerFactory{}
58 61
 }
59 62
 
60 63
 // BootLog 启动阶段专用日志函数
@@ -68,8 +71,12 @@ func BootLog(format string, v ...interface{}) {
68 71
 	}
69 72
 }
70 73
 
74
+func (f *BootLoggerFactory) GetName() string {
75
+	return "BootLoggerFactory"
76
+}
77
+
71 78
 // CloseBootLogger 关闭启动日志,切换到运行日志
72
-func CloseBootLogger() {
79
+func (f *BootLoggerFactory) Close() {
73 80
 	if bootLogger != nil {
74 81
 		BootLog("=== 启动阶段结束,切换到运行时日志 ===")
75 82
 	}

+ 42
- 4
logger/runtime_logger.go Dosyayı Görüntüle

@@ -9,6 +9,7 @@ import (
9 9
 	"sync"
10 10
 	"time"
11 11
 
12
+	"git.x2erp.com/qdy/go-base/config"
12 13
 	"git.x2erp.com/qdy/go-base/config/subconfigs"
13 14
 	"git.x2erp.com/qdy/go-base/ctx"
14 15
 	"git.x2erp.com/qdy/go-base/logger/http"
@@ -18,6 +19,9 @@ import (
18 19
 	"gopkg.in/natefinch/lumberjack.v2"
19 20
 )
20 21
 
22
+type RunTimeLoggerFactory struct {
23
+}
24
+
21 25
 var (
22 26
 	runtimeLogger  *zap.Logger
23 27
 	runtimeSugared *zap.SugaredLogger
@@ -35,8 +39,14 @@ var (
35 39
 // }
36 40
 
37 41
 // InitRuntimeLogger 初始化
38
-func InitRuntimeLogger(svcName, svcVersion string, logConfig *subconfigs.LogConfig) {
42
+func InitRuntimeLogger(cfg config.IConfig) *RunTimeLoggerFactory {
43
+
44
+	svcName := cfg.GetAppName()
45
+	svcVersion := cfg.GetAppVersion()
46
+	logConfig := cfg.GetLogConfig()
47
+
39 48
 	initOnce.Do(func() {
49
+
40 50
 		if logConfig == nil {
41 51
 			log.Fatal("错误: 日志配置不能为空")
42 52
 		}
@@ -54,6 +64,7 @@ func InitRuntimeLogger(svcName, svcVersion string, logConfig *subconfigs.LogConf
54 64
 		log.Printf("日志级别: %s", logConfig.Level)
55 65
 
56 66
 	})
67
+	return &RunTimeLoggerFactory{}
57 68
 }
58 69
 
59 70
 func createRuntimeLogger(svcName, svcVersion string, cfg *subconfigs.LogConfig) error {
@@ -115,7 +126,7 @@ func createRuntimeLogger(svcName, svcVersion string, cfg *subconfigs.LogConfig)
115 126
 				level,
116 127
 			)
117 128
 			cores = append(cores, consoleCore)
118
-			log.Printf("[RUNTIME-LOGGER] 初始化控制台日志输出(文本格式)")
129
+			log.Printf("[RUNTIME-LOGGER] 初始化控制台日志输出(文本格式)%s", svcVersion)
119 130
 
120 131
 		case "file":
121 132
 			// 文件输出(JSON格式)
@@ -155,7 +166,7 @@ func createRuntimeLogger(svcName, svcVersion string, cfg *subconfigs.LogConfig)
155 166
 			err := http.InitESWriter(
156 167
 				svcName,
157 168
 				cfg.ESPath,
158
-				cfg.ESUsername, // 假设LogConfig已有这些字段
169
+				cfg.ESUsername,
159 170
 				cfg.ESPassword,
160 171
 				containsConsole,
161 172
 			)
@@ -192,7 +203,7 @@ func createRuntimeLogger(svcName, svcVersion string, cfg *subconfigs.LogConfig)
192 203
 	// 7. 创建logger
193 204
 	runtimeLogger = zap.New(core,
194 205
 		zap.AddCaller(),
195
-		zap.AddCallerSkip(2),
206
+		zap.AddCallerSkip(1),
196 207
 		zap.AddStacktrace(zap.ErrorLevel),
197 208
 		//zap.Fields(
198 209
 		//	zap.String("service", svcName),
@@ -329,3 +340,30 @@ func IsDebug() bool {
329 340
 	}
330 341
 	return runtimeLogger.Core().Enabled(zapcore.DebugLevel)
331 342
 }
343
+
344
+func (f *RunTimeLoggerFactory) GetName() string {
345
+	return "RunTimeLoggerFactory"
346
+}
347
+
348
+// RunTimeLoggerFactory 关闭启动日志,切换到运行日志
349
+func (f *RunTimeLoggerFactory) Close() {
350
+
351
+	// 1. 同步日志缓冲区
352
+	if runtimeLogger != nil {
353
+		_ = runtimeLogger.Sync() // 忽略错误,因为sync可能失败
354
+	}
355
+
356
+	// 2. 关闭ES写入器(如果有)
357
+	StopESWriter()
358
+
359
+	// 3. 清理资源
360
+	// 注意:zap.Logger 不需要显式关闭,Sync() 已足够
361
+
362
+	// 5. 使用标准库日志记录关闭信息
363
+	if serviceName != "" {
364
+		log.Printf("[RUNTIME-LOGGER] 服务 %s 日志系统已关闭", serviceName)
365
+	} else {
366
+		log.Printf("[RUNTIME-LOGGER] 日志系统已关闭")
367
+	}
368
+
369
+}

+ 2
- 2
middleware/auth_middleware.go Dosyayı Görüntüle

@@ -57,8 +57,8 @@ func JWTAuthMiddleware(next http.Handler) http.Handler {
57 57
 		//保存上下文
58 58
 		// 创建LoggerContext(从token解析用户信息)
59 59
 		requestContext := &ctx.RequestContext{
60
-			ServiceName:  appConfig.GetService().ServiceName,
61
-			InstanceName: appConfig.GetService().InstanceName,
60
+			ServiceName:  appConfig.GetServiceConfig().ServiceName,
61
+			InstanceName: appConfig.GetServiceConfig().InstanceName,
62 62
 			TraceID:      "trace_id-123", // 生成追踪ID
63 63
 			TenantID:     "tenant-123",   // 从token解析
64 64
 			UserID:       "user-456",     // 从token解析

+ 71
- 0
models/bson_model.go Dosyayı Görüntüle

@@ -0,0 +1,71 @@
1
+package models
2
+
3
+import (
4
+	"time"
5
+
6
+	"git.x2erp.com/qdy/go-base/ctx"
7
+	"go.mongodb.org/mongo-driver/bson/primitive"
8
+)
9
+
10
+// IDType 泛型类型约束
11
+type IDType interface {
12
+	string | primitive.ObjectID
13
+}
14
+
15
+// 泛型内部模型
16
+type bsonModel[T IDType] struct {
17
+	ID        T         `bson:"_id,omitempty" json:"id,omitempty"`
18
+	TenantId  string    `bson:"tenant_id,omitempty"`
19
+	CreatedBy string    `bson:"created_by,omitempty" json:"created_by,omitempty"`
20
+	CreatedAt time.Time `bson:"created_at" json:"created_at"`
21
+	UpdatedBy string    `bson:"updated_by,omitempty" json:"updated_by,omitempty"`
22
+	UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
23
+}
24
+
25
+// 保持原有的外部类型
26
+type BsonStringModel = bsonModel[string]
27
+type BsonObjectModel = bsonModel[primitive.ObjectID]
28
+
29
+// 创建新的 String 模型(自动生成ID)
30
+func NewStringIDModel(ctx ctx.RequestContext) BsonStringModel {
31
+	return BsonStringModel{
32
+		ID:        primitive.NewObjectID().Hex(),
33
+		TenantId:  ctx.TenantID,
34
+		CreatedAt: time.Now(),
35
+		CreatedBy: ctx.UserID,
36
+		UpdatedAt: time.Now(),
37
+		UpdatedBy: ctx.UserID,
38
+	}
39
+}
40
+
41
+// 创建新的 String 模型(自定义ID)
42
+func NewStringIDModelWithID(ctx ctx.RequestContext, id string) BsonStringModel {
43
+	return BsonStringModel{
44
+		ID:        id,
45
+		TenantId:  ctx.TenantID,
46
+		CreatedAt: time.Now(),
47
+		CreatedBy: ctx.UserID,
48
+		UpdatedAt: time.Now(),
49
+		UpdatedBy: ctx.UserID,
50
+	}
51
+}
52
+
53
+// 创建新的 ObjectID 模型(自动生成ID)
54
+func NewObjectIDModel(ctx ctx.RequestContext) BsonObjectModel {
55
+	return BsonObjectModel{
56
+		ID:        primitive.NewObjectID(),
57
+		TenantId:  ctx.TenantID,
58
+		CreatedAt: time.Now(),
59
+		CreatedBy: ctx.UserID,
60
+		UpdatedAt: time.Now(),
61
+		UpdatedBy: ctx.UserID,
62
+	}
63
+}
64
+
65
+// 用于更新操作的模型(只设置更新信息)
66
+func ModelForUpdate(ctx ctx.RequestContext) BsonStringModel {
67
+	return BsonStringModel{
68
+		UpdatedAt: time.Now(),
69
+		UpdatedBy: ctx.UserID,
70
+	}
71
+}

+ 3
- 9
test.go Dosyayı Görüntüle

@@ -8,17 +8,11 @@ import (
8 8
 
9 9
 func main() {
10 10
 	// 获取配置实例
11
-	cfg, err := config.GetConfig()
12
-
13
-	// 检查初始化是否有错误
14
-	if err != nil {
15
-		fmt.Printf("配置加载失败: %v\n", err)
16
-		return
17
-	}
11
+	cfg := config.GetConfig()
18 12
 
19 13
 	// 使用配置
20 14
 	if cfg.IsDatabaseConfigured() {
21
-		dbConfig := cfg.GetDatabase()
15
+		dbConfig := cfg.GetDatabaseConfig()
22 16
 		fmt.Printf("Host: %s\n", dbConfig.Host)
23 17
 		fmt.Printf("Port: %d\n", dbConfig.Port)
24 18
 		fmt.Printf("Database: %s\n", dbConfig.Database)
@@ -27,7 +21,7 @@ func main() {
27 21
 	//authConfig := cfg.GetAuth()
28 22
 	//fmt.Printf("token: %s\n", authConfig.Token)
29 23
 
30
-	serviceConfig := cfg.GetService()
24
+	serviceConfig := cfg.GetServiceConfig()
31 25
 	fmt.Printf("ReadTimeout: %d秒\n", serviceConfig.ReadTimeout)
32 26
 	fmt.Printf("WriteTimeout: %d秒\n", serviceConfig.WriteTimeout)
33 27
 	fmt.Printf("IdleTimeout: %d秒\n", serviceConfig.IdleTimeout)

+ 2
- 2
types/types.go Dosyayı Görüntüle

@@ -74,8 +74,8 @@ type BytesMessageRequest struct {
74 74
 
75 75
 // QueueInfoRequest 获取队列信息的请求
76 76
 type QueueInfoRequest struct {
77
-	ChannelName string `json:"channel_name"`
78
-	QueueName   string `json:"queue_name"`
77
+	ChannelName string `json:"channel_name,omitempty"`
78
+	QueueName   string `json:"queue_name,omitempty"`
79 79
 }
80 80
 
81 81
 // RabbitMQResult RabbitMQ操作结果

+ 90
- 0
utils/modle_util.go Dosyayı Görüntüle

@@ -0,0 +1,90 @@
1
+package utils
2
+
3
+import (
4
+	"reflect"
5
+	"strings"
6
+
7
+	"github.com/iancoleman/strcase"
8
+)
9
+
10
+// GetStructName 获取结构体名称
11
+func GetStructName(v interface{}) string {
12
+	if v == nil {
13
+		return ""
14
+	}
15
+
16
+	t := reflect.TypeOf(v)
17
+
18
+	// 处理指针
19
+	for t.Kind() == reflect.Ptr {
20
+		t = t.Elem()
21
+	}
22
+
23
+	// 返回结构体名称
24
+	return t.Name()
25
+}
26
+
27
+// GetSnakeName 获取结构体的蛇形命名(snake_case)
28
+func GetSnakeName(v interface{}) string {
29
+	structName := GetStructName(v)
30
+	return strcase.ToSnake(structName)
31
+}
32
+
33
+// GetCamelName 获取结构体的驼峰命名(camelCase)
34
+func GetCamelName(v interface{}) string {
35
+	structName := GetStructName(v)
36
+	return strcase.ToLowerCamel(structName)
37
+}
38
+
39
+// GetKebabName 获取结构体的烤肉串命名(kebab-case)
40
+func GetKebabName(v interface{}) string {
41
+	structName := GetStructName(v)
42
+	return strcase.ToKebab(structName)
43
+}
44
+
45
+// ToSnake 驼峰转蛇形
46
+func ToSnake(s string) string {
47
+	return strcase.ToSnake(s)
48
+}
49
+
50
+// ToCamel 蛇形转驼峰
51
+func ToCamel(s string) string {
52
+	return strcase.ToLowerCamel(s)
53
+}
54
+
55
+// ToLowerCamel 下划线转小驼峰
56
+func ToLowerCamel(s string) string {
57
+	return strcase.ToLowerCamel(s)
58
+}
59
+
60
+// ToKebab 转烤肉串命名
61
+func ToKebab(s string) string {
62
+	return strcase.ToKebab(s)
63
+}
64
+
65
+// GetCollectionName 获取MongoDB集合名称
66
+// 可以自定义规则,例如去除特定后缀
67
+func GetCollectionName(v interface{}) string {
68
+	structName := GetStructName(v)
69
+
70
+	// 移除常见后缀
71
+	suffixes := []string{"Model", "Entity", "Record", "Document"}
72
+	for _, suffix := range suffixes {
73
+		if strings.HasSuffix(structName, suffix) {
74
+			structName = strings.TrimSuffix(structName, suffix)
75
+			break
76
+		}
77
+	}
78
+
79
+	// 转换为复数形式(简单规则)
80
+	if !strings.HasSuffix(structName, "s") {
81
+		// 简单的复数化规则
82
+		if strings.HasSuffix(structName, "y") {
83
+			structName = strings.TrimSuffix(structName, "y") + "ies"
84
+		} else {
85
+			structName = structName + "s"
86
+		}
87
+	}
88
+
89
+	return strcase.ToSnake(structName)
90
+}

webx/health_handle.go → webx/health/health_handle.go Dosyayı Görüntüle

@@ -1,11 +1,13 @@
1
-// webx/health_util.go
2
-package webx
1
+// webx/health_handle.go
2
+package health
3 3
 
4 4
 import (
5
+	"log"
5 6
 	"time"
6 7
 
7 8
 	"git.x2erp.com/qdy/go-base/config"
8 9
 	"git.x2erp.com/qdy/go-base/logger"
10
+	"git.x2erp.com/qdy/go-base/webx/router"
9 11
 )
10 12
 
11 13
 // HealthResponse 健康检查响应
@@ -20,22 +22,22 @@ type HealthResponse struct {
20 22
 }
21 23
 
22 24
 // RegisterDefaultHealthCheck 注册默认健康检查路由(带详细日志)
23
-func RegisterDefaultHealthCheck(ws *WebService, serviceName string) {
25
+func RegisterDefaultHealthCheck(ws *router.RouterService, serviceName string) {
24 26
 	if serviceName == "" {
25
-		cfg, _ := config.GetConfig()
27
+		cfg := config.GetConfig()
26 28
 		serviceName = cfg.GetAppName()
27 29
 		if serviceName == "" {
28 30
 			serviceName = "unknown-service"
29 31
 		}
30 32
 	}
31 33
 
32
-	logger.Debug("注册健康检查路由,服务名: %s", serviceName)
34
+	log.Printf("注册健康检查路由,服务名: %s", serviceName)
33 35
 
34 36
 	// 健康检查(带详细日志)
35 37
 	ws.GET("/health", func() (HealthResponse, error) {
36
-		logger.Debug("健康检查被调用: /health")
38
+		log.Printf("健康检查被调用: /health")
37 39
 
38
-		cfg, _ := config.GetConfig()
40
+		cfg := config.GetConfig()
39 41
 		response := HealthResponse{
40 42
 			Status:    "ok",
41 43
 			Service:   serviceName,
@@ -44,13 +46,13 @@ func RegisterDefaultHealthCheck(ws *WebService, serviceName string) {
44 46
 			Timestamp: time.Now().Format(time.RFC3339),
45 47
 		}
46 48
 
47
-		logger.Debug("健康检查响应: %+v", response)
49
+		log.Printf("健康检查响应: %+v", response)
48 50
 		return response, nil
49 51
 	}).Desc("健康检查").Register()
50 52
 
51 53
 	// 就绪检查
52 54
 	ws.GET("/health/ready", func() (HealthResponse, error) {
53
-		logger.Debug("就绪检查被调用: /health/ready")
55
+		log.Printf("就绪检查被调用: /health/ready")
54 56
 
55 57
 		return HealthResponse{
56 58
 			Status:    "ready",
@@ -61,7 +63,7 @@ func RegisterDefaultHealthCheck(ws *WebService, serviceName string) {
61 63
 
62 64
 	// 存活检查
63 65
 	ws.GET("/health/live", func() (HealthResponse, error) {
64
-		logger.Debug("存活检查被调用: /health/live")
66
+		log.Printf("存活检查被调用: /health/live")
65 67
 
66 68
 		return HealthResponse{
67 69
 			Status:    "alive",
@@ -72,9 +74,9 @@ func RegisterDefaultHealthCheck(ws *WebService, serviceName string) {
72 74
 
73 75
 	// 服务信息
74 76
 	ws.GET("/health/info", func() (map[string]interface{}, error) {
75
-		logger.Debug("服务信息被调用: /health/info")
77
+		log.Printf("服务信息被调用: /health/info")
76 78
 
77
-		cfg, _ := config.GetConfig()
79
+		cfg := config.GetConfig()
78 80
 		response := map[string]interface{}{
79 81
 			"service":     serviceName,
80 82
 			"version":     cfg.GetAppVersion(),
@@ -97,25 +99,24 @@ func RegisterDefaultHealthCheck(ws *WebService, serviceName string) {
97 99
 		return response, nil
98 100
 	}).Desc("服务信息").Register()
99 101
 
100
-	logger.Debug("健康检查路由注册完成,路径: /health, /health/ready, /health/live, /health/info")
101 102
 }
102 103
 
103 104
 // RegisterConsulHealthCheck 注册Consul兼容的健康检查
104
-func RegisterConsulHealthCheck(ws *WebService) {
105
-	logger.Debug("注册Consul兼容健康检查路由")
105
+func RegisterConsulHealthCheck(ws *router.RouterService) {
106
+	log.Printf("注册Consul兼容健康检查路由")
106 107
 
107 108
 	// Consul需要的健康检查端点(返回text/plain)
108 109
 	ws.GET("/health", func() ([]byte, error) {
109
-		logger.Info("Consul健康检查被调用: /health")
110
-		logger.Info("返回 'OK' 给Consul")
110
+		//log.Printf("Consul健康检查被调用: /health")
111
+		//log.Printf("返回 'OK' 给Consul")
111 112
 		return []byte("OK"), nil
112 113
 	}).Desc("Consul健康检查").Register()
113 114
 
114 115
 	// Consul详细状态检查
115 116
 	ws.GET("/health/consul", func() (map[string]interface{}, error) {
116
-		logger.Debug("Consul状态检查被调用: /health/consul")
117
+		//log.Printf("Consul状态检查被调用: /health/consul")
117 118
 
118
-		cfg, _ := config.GetConfig()
119
+		cfg := config.GetConfig()
119 120
 		response := map[string]interface{}{
120 121
 			"status":  "passing",
121 122
 			"service": cfg.GetAppName(),
@@ -127,14 +128,14 @@ func RegisterConsulHealthCheck(ws *WebService) {
127 128
 			},
128 129
 		}
129 130
 
130
-		logger.Debug("Consul健康状态响应: %+v", response)
131
+		//log.Printf("Consul健康状态响应: %+v", response)
131 132
 		return response, nil
132 133
 	}).Desc("Consul健康状态").Register()
133 134
 }
134 135
 
135 136
 // RegisterAllHealthChecks 注册所有健康检查(推荐使用)
136
-func RegisterAllHealthChecks(ws *WebService, serviceName string) {
137
-	logger.Debug("开始注册所有健康检查路由...")
137
+func RegisterAllHealthChecks(ws *router.RouterService, serviceName string) {
138
+	log.Printf("开始注册所有健康检查路由...")
138 139
 
139 140
 	// 注册默认健康检查
140 141
 	RegisterDefaultHealthCheck(ws, serviceName)
@@ -152,5 +153,5 @@ func RegisterAllHealthChecks(ws *WebService, serviceName string) {
152 153
 		}, nil
153 154
 	}).Desc("简单Ping检查").Register()
154 155
 
155
-	logger.Debug("所有健康检查路由注册完成")
156
+	log.Printf("所有健康检查路由注册完成")
156 157
 }

webx/web_service.go → webx/router/router_service.go Dosyayı Görüntüle

@@ -1,4 +1,4 @@
1
-package webx
1
+package router
2 2
 
3 3
 import (
4 4
 	"encoding/json"
@@ -11,14 +11,14 @@ import (
11 11
 )
12 12
 
13 13
 // WebService 路由服务
14
-type WebService struct {
14
+type RouterService struct {
15 15
 	router      *http.ServeMux
16 16
 	middlewares []func(http.Handler) http.Handler
17 17
 }
18 18
 
19 19
 // NewWebService 创建WebService
20
-func NewWebService(router *http.ServeMux) *WebService {
21
-	ws := &WebService{
20
+func NewWebService(router *http.ServeMux) *RouterService {
21
+	ws := &RouterService{
22 22
 		router: router,
23 23
 	}
24 24
 
@@ -26,33 +26,33 @@ func NewWebService(router *http.ServeMux) *WebService {
26 26
 }
27 27
 
28 28
 // Use 添加全局中间件
29
-func (ws *WebService) Use(middleware func(http.Handler) http.Handler) *WebService {
29
+func (ws *RouterService) Use(middleware func(http.Handler) http.Handler) *RouterService {
30 30
 	ws.middlewares = append(ws.middlewares, middleware)
31 31
 	return ws
32 32
 }
33 33
 
34 34
 // GET 注册GET请求
35
-func (ws *WebService) GET(path string, handler interface{}) *RouteBuilder {
35
+func (ws *RouterService) GET(path string, handler interface{}) *RouteBuilder {
36 36
 	return ws.handle("GET", path, handler)
37 37
 }
38 38
 
39 39
 // POST 注册POST请求
40
-func (ws *WebService) POST(path string, handler interface{}) *RouteBuilder {
40
+func (ws *RouterService) POST(path string, handler interface{}) *RouteBuilder {
41 41
 	return ws.handle("POST", path, handler)
42 42
 }
43 43
 
44 44
 // PUT 注册PUT请求
45
-func (ws *WebService) PUT(path string, handler interface{}) *RouteBuilder {
45
+func (ws *RouterService) PUT(path string, handler interface{}) *RouteBuilder {
46 46
 	return ws.handle("PUT", path, handler)
47 47
 }
48 48
 
49 49
 // DELETE 注册DELETE请求
50
-func (ws *WebService) DELETE(path string, handler interface{}) *RouteBuilder {
50
+func (ws *RouterService) DELETE(path string, handler interface{}) *RouteBuilder {
51 51
 	return ws.handle("DELETE", path, handler)
52 52
 }
53 53
 
54 54
 // handle 统一处理方法
55
-func (ws *WebService) handle(method, path string, handler interface{}) *RouteBuilder {
55
+func (ws *RouterService) handle(method, path string, handler interface{}) *RouteBuilder {
56 56
 	// 解析路径参数名
57 57
 	paramNames := extractPathParams(path)
58 58
 
@@ -79,67 +79,9 @@ func (ws *WebService) handle(method, path string, handler interface{}) *RouteBui
79 79
 	}
80 80
 }
81 81
 
82
-// // 上下文中间件
83
-// func (ws *WebService) contextMiddleware() func(http.Handler) http.Handler {
84
-// 	return func(next http.Handler) http.Handler {
85
-// 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
86
-// 			// 自动创建 RequestContext
87
-// 			reqCtx := ws.createRequestContext(r)
88
-
89
-// 			// 保存到请求中
90
-// 			r = ctx.SaveContext(r, *reqCtx)
91
-// 			next.ServeHTTP(w, r)
92
-// 		})
93
-// 	}
94
-// }
95
-
96
-// // 创建 RequestContext
97
-// func (ws *WebService) createRequestContext(r *http.Request) *ctx.RequestContext {
98
-// 	return &ctx.RequestContext{
99
-// 		TraceID:      generateTraceID(),
100
-// 		ServiceName:  getServiceName(r),
101
-// 		InstanceName: getInstanceName(),
102
-// 		TenantID:     r.Header.Get("X-Tenant-ID"),
103
-// 		UserID:       extractUserID(r),
104
-// 	}
105
-// }
106
-
107
-// // 辅助函数
108
-// func generateTraceID() string {
109
-// 	return "trace-" + strconv.FormatInt(time.Now().UnixNano(), 36)
110
-// }
111
-
112
-// func getServiceName(r *http.Request) string {
113
-// 	if serviceName := r.Header.Get("X-Service-Name"); serviceName != "" {
114
-// 		return serviceName
115
-// 	}
116
-// 	return "unknown-service"
117
-// }
118
-
119
-// func getInstanceName() string {
120
-// 	// 获取主机名
121
-// 	hostname, _ := os.Hostname()
122
-// 	if hostname != "" {
123
-// 		return hostname
124
-// 	}
125
-// 	return "instance-1"
126
-// }
127
-
128
-// func extractUserID(r *http.Request) string {
129
-// 	if auth := r.Header.Get("Authorization"); auth != "" {
130
-// 		// 简单示例:从 Authorization 头提取
131
-// 		if strings.HasPrefix(auth, "Bearer ") {
132
-// 			// 这里可以解析 JWT token 获取用户ID
133
-// 			// 暂时返回示例值
134
-// 			return "user-from-token"
135
-// 		}
136
-// 	}
137
-// 	return ""
138
-// }
139
-
140 82
 // RouteBuilder 路由构建器
141 83
 type RouteBuilder struct {
142
-	ws          *WebService
84
+	ws          *RouterService
143 85
 	method      string
144 86
 	path        string
145 87
 	handlerFunc reflect.Value
@@ -190,7 +132,7 @@ func (rb *RouteBuilder) Register() {
190 132
 
191 133
 // handlerAdapter 处理器适配器
192 134
 type handlerAdapter struct {
193
-	ws          *WebService
135
+	ws          *RouterService
194 136
 	method      string
195 137
 	pathPattern string
196 138
 	paramNames  []string
@@ -293,132 +235,6 @@ func (ha *handlerAdapter) buildArgs(w http.ResponseWriter, r *http.Request, path
293 235
 	return args
294 236
 }
295 237
 
296
-// func (ha *handlerAdapter) buildArgs(w http.ResponseWriter, r *http.Request, pathParams map[string]string) []reflect.Value {
297
-// 	handlerType := ha.handlerFunc.Type()
298
-// 	numIn := handlerType.NumIn()
299
-// 	args := make([]reflect.Value, numIn)
300
-
301
-// 	// 收集所有 string 类型的参数索引
302
-// 	var stringParamIndices []int
303
-// 	for i := 0; i < numIn; i++ {
304
-// 		paramType := handlerType.In(i)
305
-// 		if paramType.Kind() == reflect.String &&
306
-// 			paramType != reflect.TypeOf((*ctx.RequestContext)(nil)) {
307
-// 			stringParamIndices = append(stringParamIndices, i)
308
-// 		}
309
-// 	}
310
-
311
-// 	// 处理每个参数
312
-// 	stringParamIndex := 0
313
-// 	for i := 0; i < numIn; i++ {
314
-// 		paramType := handlerType.In(i)
315
-// 		paramName := getParamName(i, handlerType, ha.paramNames)
316
-
317
-// 		// 1. 检查是否是特殊类型
318
-// 		if arg := ha.bindSpecialType(paramType, w, r); arg.IsValid() {
319
-// 			args[i] = arg
320
-// 			continue
321
-// 		}
322
-
323
-// 		// 2. 检查是否是 *ctx.RequestContext 类型
324
-// 		if paramType == reflect.TypeOf((*ctx.RequestContext)(nil)) {
325
-// 			reqCtx := ctx.GetContext(r)
326
-// 			args[i] = reflect.ValueOf(reqCtx)
327
-// 			continue
328
-// 		}
329
-
330
-// 		// 3. 处理路径参数
331
-// 		matched := false
332
-
333
-// 		// 如果有对应的路径参数名,直接匹配
334
-// 		if value, ok := pathParams[paramName]; ok && paramType.Kind() == reflect.String {
335
-// 			args[i] = convertToType(value, paramType)
336
-// 			matched = true
337
-// 		}
338
-
339
-// 		// 如果是 string 类型但没有匹配到名称,按顺序分配路径参数
340
-// 		if !matched && paramType.Kind() == reflect.String {
341
-// 			// 使用 stringParamIndices 中的位置来匹配 pathParamNames
342
-// 			if stringParamIndex < len(ha.paramNames) && stringParamIndex < len(stringParamIndices) {
343
-// 				paramName := ha.paramNames[stringParamIndex]
344
-// 				if value, ok := pathParams[paramName]; ok {
345
-// 					args[i] = convertToType(value, paramType)
346
-// 					matched = true
347
-// 					stringParamIndex++
348
-// 				}
349
-// 			}
350
-// 		}
351
-
352
-// 		if matched {
353
-// 			continue
354
-// 		}
355
-
356
-// 		// 4. 其他绑定逻辑...
357
-// 		// 查询参数、JSON body 等
358
-// 	}
359
-
360
-// 	return args
361
-// }
362
-
363
-// // buildArgs 构建函数参数
364
-// func (ha *handlerAdapter) buildArgs(w http.ResponseWriter, r *http.Request, pathParams map[string]string) []reflect.Value {
365
-// 	handlerType := ha.handlerFunc.Type()
366
-// 	numIn := handlerType.NumIn()
367
-// 	args := make([]reflect.Value, numIn)
368
-
369
-// 	for i := 0; i < numIn; i++ {
370
-// 		paramType := handlerType.In(i)
371
-// 		paramName := getParamName(i, handlerType, ha.paramNames)
372
-
373
-// 		// 1. 检查是否是特殊类型
374
-// 		if arg := ha.bindSpecialType(paramType, w, r); arg.IsValid() {
375
-// 			args[i] = arg
376
-// 			continue
377
-// 		}
378
-
379
-// 		// 2. 检查是否是 *ctx.RequestContext 类型
380
-// 		if paramType == reflect.TypeOf((*ctx.RequestContext)(nil)) {
381
-// 			reqCtx := ctx.GetContext(r)
382
-// 			if logger.IsDebug() {
383
-// 				logger.DebugC(reqCtx, "requestContext: %+v", reqCtx)
384
-// 			}
385
-// 			args[i] = reflect.ValueOf(reqCtx)
386
-// 			continue
387
-// 		}
388
-
389
-// 		// 3. 尝试从路径参数获取
390
-// 		if value, ok := pathParams[paramName]; ok {
391
-// 			if arg := convertToType(value, paramType); arg.IsValid() {
392
-// 				args[i] = arg
393
-// 				continue
394
-// 			}
395
-// 		}
396
-
397
-// 		// 4. 尝试从查询参数获取
398
-// 		if queryValue := r.URL.Query().Get(paramName); queryValue != "" {
399
-// 			if arg := convertToType(queryValue, paramType); arg.IsValid() {
400
-// 				args[i] = arg
401
-// 				continue
402
-// 			}
403
-// 		}
404
-
405
-// 		// 5. 尝试从JSON body获取
406
-// 		if (r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH") &&
407
-// 			(paramType.Kind() == reflect.Struct ||
408
-// 				(paramType.Kind() == reflect.Ptr && paramType.Elem().Kind() == reflect.Struct)) {
409
-// 			if arg := ha.parseBody(r, paramType); arg.IsValid() {
410
-// 				args[i] = arg
411
-// 				continue
412
-// 			}
413
-// 		}
414
-
415
-// 		// 6. 返回零值
416
-// 		args[i] = reflect.Zero(paramType)
417
-// 	}
418
-
419
-// 	return args
420
-// }
421
-
422 238
 // bindSpecialType 绑定特殊类型
423 239
 func (ha *handlerAdapter) bindSpecialType(paramType reflect.Type, w http.ResponseWriter, r *http.Request) reflect.Value {
424 240
 	switch paramType {

+ 325
- 0
webx/webx_factory.go Dosyayı Görüntüle

@@ -0,0 +1,325 @@
1
+package webx
2
+
3
+import (
4
+	"context"
5
+	"fmt"
6
+	"log"
7
+	"net/http"
8
+	"os"
9
+	"os/signal"
10
+	"sync"
11
+	"syscall"
12
+	"time"
13
+
14
+	"git.x2erp.com/qdy/go-base/client"
15
+	"git.x2erp.com/qdy/go-base/config/subconfigs"
16
+	"git.x2erp.com/qdy/go-base/container"
17
+	"git.x2erp.com/qdy/go-base/logger"
18
+)
19
+
20
+// WebService Web服务实例
21
+type WebService struct {
22
+	serviceName string
23
+	httpServer  *http.Server
24
+	router      *http.ServeMux
25
+	//RouterService *router.RouterService // 暴露RouterService
26
+	quit   chan os.Signal
27
+	config *subconfigs.ServiceConfig
28
+	ip     string
29
+	port   int
30
+}
31
+
32
+// WebServiceFactory Web服务工厂(全局单例模式)
33
+type WebServiceFactory struct {
34
+	mu         sync.RWMutex
35
+	webService *WebService
36
+}
37
+
38
+var (
39
+	instanceWebService     *WebServiceFactory
40
+	instanceWebServiceOnce sync.Once
41
+)
42
+
43
+// GetWebServiceFactory 获取Web服务工厂单例
44
+func GetWebServiceFactory() *WebServiceFactory {
45
+	instanceWebServiceOnce.Do(func() {
46
+		log.Printf("Creating WebServiceFactory...")
47
+
48
+		instanceWebService = &WebServiceFactory{}
49
+
50
+		log.Printf("WebServiceFactory is successfully created.")
51
+	})
52
+
53
+	return instanceWebService
54
+}
55
+
56
+// CreateService 创建Web服务实例
57
+func (f *WebServiceFactory) CreateService(config *subconfigs.ServiceConfig) (*WebService, error) {
58
+	f.mu.Lock()
59
+	defer f.mu.Unlock()
60
+
61
+	// 检查是否已存在服务
62
+	if f.webService != nil {
63
+		log.Printf("服务已存在,返回现有实例: %s", f.webService.serviceName)
64
+		return f.webService, nil
65
+	}
66
+
67
+	// 验证配置
68
+	if config == nil {
69
+		return nil, fmt.Errorf("服务配置不能为空")
70
+	}
71
+
72
+	// 设置默认值
73
+	if config.Port == 0 {
74
+		config.Port = 8080
75
+	}
76
+	if config.ServiceName == "" {
77
+		config.ServiceName = "default-service"
78
+	}
79
+	if config.ReadTimeout == 0 {
80
+		config.ReadTimeout = 15
81
+	}
82
+	if config.WriteTimeout == 0 {
83
+		config.WriteTimeout = 15
84
+	}
85
+	if config.IdleTimeout == 0 {
86
+		config.IdleTimeout = 60
87
+	}
88
+
89
+	// 获取IP
90
+	ip := client.GetServiceIP("")
91
+
92
+	// 创建服务实例
93
+	service := &WebService{
94
+		serviceName: config.ServiceName,
95
+		router:      http.NewServeMux(),
96
+		quit:        make(chan os.Signal, 1),
97
+		config:      config,
98
+		ip:          ip,
99
+		port:        config.Port,
100
+	}
101
+
102
+	// 创建HTTP服务器
103
+	service.httpServer = &http.Server{
104
+		Addr:         fmt.Sprintf(":%d", config.Port),
105
+		Handler:      service.router,
106
+		ReadTimeout:  time.Duration(config.ReadTimeout) * time.Second,
107
+		WriteTimeout: time.Duration(config.WriteTimeout) * time.Second,
108
+		IdleTimeout:  time.Duration(config.IdleTimeout) * time.Second,
109
+	}
110
+
111
+	// 保存实例
112
+	f.webService = service
113
+
114
+	log.Printf("已创建服务实例: %s (端口: %d)", config.ServiceName, config.Port)
115
+	return service, nil
116
+}
117
+
118
+// IsCreated 检查服务是否已创建
119
+func (f *WebServiceFactory) IsCreated() bool {
120
+	f.mu.RLock()
121
+	defer f.mu.RUnlock()
122
+	return f.webService != nil
123
+}
124
+
125
+// ========== WebService 实例方法 ==========
126
+
127
+// GetRouter 获取路由器
128
+func (s *WebService) GetRouter() *http.ServeMux {
129
+	return s.router
130
+}
131
+
132
+// GetServer 获取HTTP服务器
133
+func (s *WebService) GetServer() *http.Server {
134
+	return s.httpServer
135
+}
136
+
137
+// GetServiceName 获取服务名称
138
+func (s *WebService) GetServiceName() string {
139
+	return s.serviceName
140
+}
141
+
142
+// GetIP 获取服务IP
143
+func (s *WebService) GetIP() string {
144
+	return s.ip
145
+}
146
+
147
+// GetPort 获取服务端口
148
+func (s *WebService) GetPort() int {
149
+	return s.port
150
+}
151
+
152
+// GetConfig 获取服务配置
153
+func (s *WebService) GetConfig() *subconfigs.ServiceConfig {
154
+	return s.config
155
+}
156
+
157
+// RegisterRoute 注册路由
158
+func (s *WebService) RegisterRoute(pattern string, handler http.Handler) {
159
+	s.router.Handle(pattern, handler)
160
+}
161
+
162
+// RegisterRouteFunc 注册路由处理函数
163
+func (s *WebService) RegisterRouteFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
164
+	s.router.HandleFunc(pattern, handler)
165
+}
166
+
167
+// Run 运行所有服务
168
+func (s *WebService) Run() {
169
+	// 设置全局信号监听
170
+	signal.Notify(s.quit, syscall.SIGINT, syscall.SIGTERM)
171
+
172
+	log.Printf("启动服务 %s 在 %s", s.serviceName, s.httpServer.Addr)
173
+
174
+	// 在goroutine中启动服务,避免阻塞
175
+	go func() {
176
+		if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
177
+			log.Fatalf("服务 %s 运行失败: %v", s.serviceName, err)
178
+		}
179
+	}()
180
+
181
+	// 等待中断信号,传递指针
182
+	//s.waitForServiceShutdown(containerFactory)
183
+}
184
+
185
+// RunTLS 运行HTTPS服务
186
+func (s *WebService) RunTLS(serviceName, certFile, keyFile string) {
187
+
188
+	log.Printf("服务 %s 开始运行(HTTPS)...", s.serviceName)
189
+
190
+	// 设置服务级别的信号监听
191
+	signal.Notify(s.quit, syscall.SIGINT, syscall.SIGTERM)
192
+
193
+	// 启动HTTPS服务器
194
+	go func() {
195
+		log.Printf("HTTPS服务器启动在 %s", s.httpServer.Addr)
196
+		if err := s.httpServer.ListenAndServeTLS(certFile, keyFile); err != nil && err != http.ErrServerClosed {
197
+			log.Fatalf("服务运行失败: %v", err)
198
+		}
199
+	}()
200
+
201
+	// 等待中断信号
202
+	//s.waitForServiceShutdown(containerFactory)
203
+}
204
+
205
+// waitForServiceShutdown 等待单个服务关闭
206
+func (s *WebService) WaitForServiceShutdown(containerFactory *container.ContainerFactory) {
207
+
208
+	log.Printf("按 Ctrl+C 停止服务 %s", s.serviceName)
209
+
210
+	// 等待信号
211
+	<-s.quit
212
+	log.Printf("接收到终止信号,正在优雅关闭服务 %s...", s.serviceName)
213
+
214
+	//退出注册中心
215
+	//consul.Deregister(s.serviceName, s.Ip, s.Port, b.Cfg.GetConsulConfig())
216
+
217
+	// 创建关闭上下文,给30秒完成当前请求
218
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
219
+	defer cancel()
220
+
221
+	// 停止接收新请求,完成当前请求
222
+	if err := s.httpServer.Shutdown(ctx); err != nil {
223
+		log.Printf("服务 %s 关闭失败: %v", s.serviceName, err)
224
+	} else {
225
+		log.Printf("服务 %s 已关闭", s.serviceName)
226
+	}
227
+
228
+	// 执行关闭处理
229
+	if containerFactory != nil {
230
+		containerFactory.CloseAll()
231
+	}
232
+
233
+	// 停止日志写入
234
+	logger.StopESWriter()
235
+	log.Printf("服务 %s 优雅关闭完成", s.serviceName)
236
+
237
+	// 等待一小段时间确保日志写入完成
238
+	time.Sleep(100 * time.Millisecond)
239
+	os.Exit(0)
240
+}
241
+
242
+// AddMiddleware 添加中间件
243
+func (s *WebService) AddMiddleware(middleware func(http.Handler) http.Handler) {
244
+	s.httpServer.Handler = middleware(s.httpServer.Handler)
245
+}
246
+
247
+// EnableCORS 启用CORS支持
248
+func (s *WebService) EnableCORS() {
249
+	s.AddMiddleware(func(next http.Handler) http.Handler {
250
+		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
251
+			w.Header().Set("Access-Control-Allow-Origin", "*")
252
+			w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
253
+			w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
254
+
255
+			if r.Method == "OPTIONS" {
256
+				w.WriteHeader(http.StatusOK)
257
+				return
258
+			}
259
+
260
+			next.ServeHTTP(w, r)
261
+		})
262
+	})
263
+}
264
+
265
+// EnableRequestLogging 启用请求日志记录
266
+func (s *WebService) EnableRequestLogging() {
267
+	s.AddMiddleware(func(next http.Handler) http.Handler {
268
+		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
269
+			start := time.Now()
270
+
271
+			// 使用包装器记录响应状态码
272
+			rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
273
+
274
+			next.ServeHTTP(rw, r)
275
+
276
+			// 记录日志
277
+			duration := time.Since(start)
278
+			log.Printf("%s %s %d %v", r.Method, r.URL.Path, rw.statusCode, duration)
279
+			logger.Info("%s %s %d %v", r.Method, r.URL.Path, rw.statusCode, duration)
280
+		})
281
+	})
282
+}
283
+
284
+// 辅助类型,用于记录响应状态码
285
+type responseWriter struct {
286
+	http.ResponseWriter
287
+	statusCode int
288
+}
289
+
290
+func (rw *responseWriter) WriteHeader(code int) {
291
+	rw.statusCode = code
292
+	rw.ResponseWriter.WriteHeader(code)
293
+}
294
+
295
+// HealthCheck 添加健康检查端点
296
+func (s *WebService) HealthCheck(pattern string) {
297
+	s.RegisterRouteFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
298
+		w.WriteHeader(http.StatusOK)
299
+		w.Write([]byte("OK"))
300
+	})
301
+}
302
+
303
+// Metrics 添加指标端点
304
+func (s *WebService) Metrics(pattern string) {
305
+	s.RegisterRouteFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
306
+		w.Header().Set("Content-Type", "text/plain")
307
+		w.WriteHeader(http.StatusOK)
308
+		// 这里可以添加应用的指标数据
309
+		w.Write([]byte("# HELP go_info Information about the Go environment.\n"))
310
+		w.Write([]byte("# TYPE go_info gauge\n"))
311
+		w.Write([]byte("go_info{version=\"1.19\"} 1\n"))
312
+	})
313
+}
314
+
315
+// StaticFile 添加静态文件服务
316
+func (s *WebService) StaticFile(pattern, filepath string) {
317
+	s.RegisterRouteFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
318
+		http.ServeFile(w, r, filepath)
319
+	})
320
+}
321
+
322
+// StaticDirectory 添加静态目录服务
323
+func (s *WebService) StaticDirectory(pattern, directory string) {
324
+	s.RegisterRoute(pattern, http.StripPrefix(pattern, http.FileServer(http.Dir(directory))))
325
+}

Loading…
İptal
Kaydet