233 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Package router ...
 | 
						|
//
 | 
						|
// Description : router ...
 | 
						|
//
 | 
						|
// Author : go_developer@163.com<白茶清欢>
 | 
						|
//
 | 
						|
// Date : 2025-02-07 18:19
 | 
						|
package router
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"net/http"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
 | 
						|
	"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,
 | 
						|
		lock:        &sync.RWMutex{},
 | 
						|
		commonParam: map[string]GetCommonParam{},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type server struct {
 | 
						|
	router      *gin.Engine
 | 
						|
	port        int
 | 
						|
	uiInstance  *apiDoc.SwaggerUI
 | 
						|
	option      *serverOption
 | 
						|
	commonParam map[string]GetCommonParam // 结构体字段名, 注意, 不是TAG
 | 
						|
	lock        *sync.RWMutex
 | 
						|
}
 | 
						|
 | 
						|
// 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)
 | 
						|
			handleFunc := s.RequestHandler(itemUriCfg)
 | 
						|
			switch method {
 | 
						|
			case http.MethodGet:
 | 
						|
				g.GET(itemUriCfg.Path, handleFunc)
 | 
						|
			case http.MethodHead:
 | 
						|
				g.HEAD(itemUriCfg.Path, handleFunc)
 | 
						|
			case http.MethodPost:
 | 
						|
				g.POST(itemUriCfg.Path, handleFunc)
 | 
						|
			case http.MethodPut:
 | 
						|
				g.PUT(itemUriCfg.Path, handleFunc)
 | 
						|
			case http.MethodPatch:
 | 
						|
				g.PATCH(itemUriCfg.Path, handleFunc)
 | 
						|
			case http.MethodDelete:
 | 
						|
				g.DELETE(itemUriCfg.Path, handleFunc)
 | 
						|
			case http.MethodOptions:
 | 
						|
				g.OPTIONS(itemUriCfg.Path, handleFunc)
 | 
						|
			case http.MethodTrace:
 | 
						|
				panic(`method Trace is not supported`)
 | 
						|
			default:
 | 
						|
				panic("method " + itemUriCfg.RequestMethod + " is not support")
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |