227 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package router ...
 | |
| //
 | |
| // Description : router ...
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 2025-02-07 18:19
 | |
| package router
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"strings"
 | |
| 
 | |
| 	"git.zhangdeman.cn/zhangdeman/graceful"
 | |
| 
 | |
| 	"git.zhangdeman.cn/zhangdeman/gin/define"
 | |
| 
 | |
| 	apiDoc "git.zhangdeman.cn/zhangdeman/api-doc"
 | |
| 	"git.zhangdeman.cn/zhangdeman/consts"
 | |
| 	"git.zhangdeman.cn/zhangdeman/gin/middleware"
 | |
| 	"git.zhangdeman.cn/zhangdeman/gin/middleware/request_cors"
 | |
| 	"github.com/gin-contrib/pprof"
 | |
| 
 | |
| 	apiDocDefine "git.zhangdeman.cn/zhangdeman/api-doc/define"
 | |
| 	apiDocEnum "git.zhangdeman.cn/zhangdeman/api-doc/enums"
 | |
| 	"github.com/gin-gonic/gin"
 | |
| )
 | |
| 
 | |
| func newServerOption(port int, optionList ...SetServerOptionFunc) *serverOption {
 | |
| 	option := &serverOption{
 | |
| 		swaggerUiTheme:       apiDocEnum.SwaggerUIThemeRedocFree.String(),
 | |
| 		swaggerBaseUri:       "/doc/swagger",
 | |
| 		globalMiddlewareList: nil,
 | |
| 		disableSwaggerDoc:    false,
 | |
| 		serverInfo: &apiDocDefine.Info{
 | |
| 			Description:    "这是一个微服务,提供一些必要的的数据接口功能",
 | |
| 			Title:          "微服务接口文档",
 | |
| 			TermsOfService: "",
 | |
| 			Contact: &apiDocDefine.Contact{
 | |
| 				Name:  "开发人员",
 | |
| 				Url:   "",
 | |
| 				Email: "developer@example.com",
 | |
| 			},
 | |
| 			License: &apiDocDefine.License{
 | |
| 				Name: consts.LicenseApache20,
 | |
| 				Url:  consts.LicenseUrlTable[consts.LicenseApache20],
 | |
| 			},
 | |
| 			Version: "0.0.1",
 | |
| 		},
 | |
| 		serverList: []*apiDocDefine.ServerItem{
 | |
| 			{
 | |
| 				Url:         fmt.Sprintf("http://127.0.0.1:%d", port),
 | |
| 				Description: "测试服务器",
 | |
| 				Variables:   nil,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 	for _, opt := range optionList {
 | |
| 		if nil == opt {
 | |
| 			continue
 | |
| 		}
 | |
| 		opt(option)
 | |
| 	}
 | |
| 	return option
 | |
| }
 | |
| 
 | |
| // NewServer server实例
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 18:20 2025/2/7
 | |
| func NewServer(port int, optionList ...SetServerOptionFunc) *server {
 | |
| 	if port < 80 {
 | |
| 		panic("port should be greater than 80")
 | |
| 	}
 | |
| 	option := newServerOption(port, optionList...)
 | |
| 	globalMiddlewareList := make([]gin.HandlerFunc, 0)
 | |
| 	if nil != option.initContextData {
 | |
| 		globalMiddlewareList = append(globalMiddlewareList, option.initContextData) // 初始化一些全局的变量
 | |
| 	}
 | |
| 	if !option.disableInitRequest { // 启用了初始化请求
 | |
| 		globalMiddlewareList = append(globalMiddlewareList, middleware.InitRequest()) // 初始化请求
 | |
| 	}
 | |
| 	// CustomContext 必须在第一个, 并且进行初始化
 | |
| 	globalMiddlewareList = append(
 | |
| 		globalMiddlewareList,
 | |
| 		func(ctx *gin.Context) {
 | |
| 			// 初始化上下文以及基础信息
 | |
| 			_ = define.NewContext(ctx)
 | |
| 		},
 | |
| 	)
 | |
| 	if nil != option.loggerCfg {
 | |
| 		// 请求日志记录中间件
 | |
| 		globalMiddlewareList = append(globalMiddlewareList, middleware.LogRequest(option.loggerCfg))
 | |
| 	}
 | |
| 	if option.enableCors {
 | |
| 		// 跨域中间件
 | |
| 		globalMiddlewareList = append(globalMiddlewareList, request_cors.New(request_cors.Config{
 | |
| 			AllowAllOrigins:        true,
 | |
| 			AllowOrigins:           nil,
 | |
| 			AllowOriginFunc:        nil,
 | |
| 			AllowMethods:           []string{"*"},
 | |
| 			AllowHeaders:           []string{"*"},
 | |
| 			AllowCredentials:       true,
 | |
| 			ExposeHeaders:          nil,
 | |
| 			MaxAge:                 0,
 | |
| 			AllowWildcard:          true,
 | |
| 			AllowBrowserExtensions: true,
 | |
| 			AllowWebSockets:        true,
 | |
| 			AllowFiles:             true,
 | |
| 		}))
 | |
| 	}
 | |
| 	if len(option.globalMiddlewareList) > 0 {
 | |
| 		// 自定义全局中间件追加
 | |
| 		globalMiddlewareList = append(globalMiddlewareList, option.globalMiddlewareList...)
 | |
| 	}
 | |
| 	r := gin.Default()
 | |
| 
 | |
| 	// 注册全局中间件
 | |
| 	r.Use(globalMiddlewareList...)
 | |
| 
 | |
| 	// 启用pprof, 注册相关路由
 | |
| 	if option.enablePprof {
 | |
| 		pprof.Register(r)
 | |
| 	}
 | |
| 	return &server{
 | |
| 		router:     r,
 | |
| 		uiInstance: apiDoc.NewSwaggerUI(option.serverInfo, option.serverList, apiDocEnum.SwaggerUITheme(option.swaggerUiTheme)),
 | |
| 		port:       port,
 | |
| 		option:     option,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type server struct {
 | |
| 	router     *gin.Engine
 | |
| 	port       int
 | |
| 	uiInstance *apiDoc.SwaggerUI
 | |
| 	option     *serverOption
 | |
| }
 | |
| 
 | |
| // Start 启动服务
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 18:31 2025/2/7
 | |
| func (s *server) Start() {
 | |
| 	// 注册文档
 | |
| 	s.uiInstance.RegisterHandler(s.router, s.option.swaggerBaseUri)
 | |
| 	gracefulServer := graceful.NewServer(fmt.Sprintf(":%d", s.port), s.Router())
 | |
| 	if err := gracefulServer.ListenAndServe(); err != nil {
 | |
| 		if strings.Contains(err.Error(), "use of closed network connection") {
 | |
| 			fmt.Println("接收到退出指令, 服务平滑关闭")
 | |
| 			return
 | |
| 		}
 | |
| 		panic("服务启动监听失败" + err.Error())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Router 对外访问路由实例, 不建议直接用
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 17:35 2025/2/18
 | |
| func (s *server) Router() *gin.Engine {
 | |
| 	return s.router
 | |
| }
 | |
| 
 | |
| // Handler404 注册404的处理方法
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 16:01 2025/2/22
 | |
| func (s *server) Handler404(f gin.HandlerFunc) {
 | |
| 	s.router.NoRoute(f)
 | |
| }
 | |
| 
 | |
| // SetCustomRouter 自定义路由处理
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 16:09 2025/2/22
 | |
| func (s *server) SetCustomRouter(f func(r *gin.Engine)) {
 | |
| 	if nil == f {
 | |
| 		return
 | |
| 	}
 | |
| 	f(s.router)
 | |
| }
 | |
| 
 | |
| // Group 注册接口路由
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 19:35 2025/1/27
 | |
| func (s *server) Group(routerPrefix string, middlewareList []gin.HandlerFunc, cList ...any) {
 | |
| 	g := s.router.Group(routerPrefix)
 | |
| 	g.Use(middlewareList...)
 | |
| 	cParser := controller{}
 | |
| 	for _, c := range cList {
 | |
| 		urlTable := cParser.Parse(c)
 | |
| 		for _, itemUriCfg := range urlTable {
 | |
| 			_ = s.uiInstance.DocInstance().AddApiFromInAndOut(routerPrefix, itemUriCfg.FormDataType, itemUriCfg.ResultDataType)
 | |
| 			method := strings.ToUpper(itemUriCfg.RequestMethod)
 | |
| 			switch method {
 | |
| 			case http.MethodGet:
 | |
| 				g.GET(itemUriCfg.Path, RequestHandler(itemUriCfg))
 | |
| 			case http.MethodHead:
 | |
| 				g.HEAD(itemUriCfg.Path, RequestHandler(itemUriCfg))
 | |
| 			case http.MethodPost:
 | |
| 				g.POST(itemUriCfg.Path, RequestHandler(itemUriCfg))
 | |
| 			case http.MethodPut:
 | |
| 				g.PUT(itemUriCfg.Path, RequestHandler(itemUriCfg))
 | |
| 			case http.MethodPatch:
 | |
| 				g.PATCH(itemUriCfg.Path, RequestHandler(itemUriCfg))
 | |
| 			case http.MethodDelete:
 | |
| 				g.DELETE(itemUriCfg.Path, RequestHandler(itemUriCfg))
 | |
| 			case http.MethodOptions:
 | |
| 				g.OPTIONS(itemUriCfg.Path, RequestHandler(itemUriCfg))
 | |
| 			case http.MethodTrace:
 | |
| 				panic(`method Trace is not supported`)
 | |
| 			default:
 | |
| 				panic("method " + itemUriCfg.RequestMethod + " is not support")
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |