Ai
1 Star 0 Fork 0

tomatomeatman/GolangRepository

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
GinUtil.go 9.88 KB
一键复制 编辑 原始数据 按行查看 历史
laowei 提交于 2024-07-15 16:06 +08:00 . 1
package gin
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"gitee.com/tomatomeatman/golang-repository/bricks2/model/emity"
Log "github.com/cihub/seelog"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"gopkg.in/ini.v1"
)
type GinUtil struct{}
// 请求类型枚举
type RequestType string
const (
GET RequestType = "GET"
POST RequestType = "POST"
DELETE RequestType = "DELETE"
PUT RequestType = "PUT"
OPTIONS RequestType = "OPTIONS"
)
// 枚举转字符串
func (rt RequestType) String() string {
switch rt {
case GET:
return "GET"
case POST:
return "POST"
case DELETE:
return "DELETE"
case PUT:
return "PUT"
case OPTIONS:
return "OPTIONS"
default:
return "NA"
}
}
var (
guiUtil_UrlRegeditWg sync.WaitGroup //同步原语,要保证所有的Url注册都已经完成
guiUtil_CheckWrite sync.Mutex //保存锁
httpHandleFunc = make(map[string]HttpHandleInfo) //http控制层接口信息集合
appGinServer *http.Server
)
// http控制层接口信息
type HttpHandleInfo struct {
Url string
Type RequestType
Fun func(ctx *gin.Context) interface{}
}
// 设置跨域
func (gu GinUtil) SetCors(r *gin.Engine) {
r.Use(gu.Cors())
}
func (gu GinUtil) GetGin(ginMode, webRoot, Port string, InterceptorFunc func(ctx *gin.Context) bool) *http.Server {
ginUtil := GinUtil{}
HttpHandleInfos := ginUtil.GetController()
switch strings.ToUpper(ginMode) { //gin运行模式
case "RELEASE":
gin.SetMode(gin.ReleaseMode)
case "TEST":
gin.SetMode(gin.TestMode)
case "DEBUG":
gin.SetMode(gin.DebugMode)
default:
gin.SetMode(gin.ReleaseMode)
}
r := gin.Default()
ginUtil.SetCors(r) //设置跨域
ginUtil.SetStatic(r, "."+webRoot) //设置静态目录
r.GET("/shutdown", gu.Shutdown)
r.POST("/shutdown", gu.Shutdown)
for _, val := range HttpHandleInfos {
switch val.Type {
case GET:
r.GET(val.Url, ginUtil.GetHandleFunc(val.Url, GET, InterceptorFunc, HttpHandleInfos))
case POST:
r.POST(val.Url, ginUtil.GetHandleFunc(val.Url, POST, InterceptorFunc, HttpHandleInfos))
case DELETE:
r.DELETE(val.Url, ginUtil.GetHandleFunc(val.Url, DELETE, InterceptorFunc, HttpHandleInfos))
case PUT:
r.PUT(val.Url, ginUtil.GetHandleFunc(val.Url, PUT, InterceptorFunc, HttpHandleInfos))
case OPTIONS:
r.OPTIONS(val.Url, ginUtil.GetHandleFunc(val.Url, OPTIONS, InterceptorFunc, HttpHandleInfos))
default:
r.GET(val.Url, func(ctx *gin.Context) {
ctx.JSONP(http.StatusBadRequest, emity.MsgEmity{}.Err(1001, "请求方式错误,不支持此方式"))
})
}
}
httpHandleFunc = make(map[string]HttpHandleInfo) //清理
appGinServer := &http.Server{
Addr: ":" + Port,
Handler: r,
}
return appGinServer
}
// 跨域函数
func (gu GinUtil) Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin")
if origin != "" {
c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
//c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
//c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
c.Header("Access-Control-Allow-Headers", "*")
c.Header("Access-Control-Expose-Headers", "*")
c.Header("Access-Control-Allow-Credentials", "true")
}
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
c.Next()
}
}
// 设置静态路径
func (gu GinUtil) SetStatic(r *gin.Engine, webroot string) {
_ = mime.AddExtensionType(".js", "application/javascript") // 特殊处理JS文件的Content-Type
r.Use(static.Serve("/", static.LocalFile(webroot, true))) // 前端项目静态资源
}
// 注册web接口
func (gu GinUtil) RegisterController(url string, iTypes interface{}, handler func(ctx *gin.Context) interface{}) {
gu.RegisterControllers(url, iTypes, handler)
}
// 注册web接口
func (gu GinUtil) ControllerRegister(url string, handler func(ctx *gin.Context) interface{}, iTypes ...RequestType) {
if len(iTypes) < 1 {
gu.registerController(url, POST, handler)
return
}
for _, rt := range iTypes {
gu.registerController(url, rt, handler)
}
}
// 注册web接口
func (gu GinUtil) RegisterControllers(url string, iTypes interface{}, handler func(ctx *gin.Context) interface{}) {
switch t := iTypes.(type) {
case RequestType:
gu.registerController(url, t, handler)
case []RequestType:
if len(iTypes.([]RequestType)) < 1 {
gu.registerController(url, POST, handler)
return
}
for _, v := range iTypes.([]RequestType) {
gu.registerController(url, v, handler)
}
default:
gu.registerController(url, POST, handler)
}
}
// 注册web接口
func (gu GinUtil) registerController(url string, iType RequestType, handler func(ctx *gin.Context) interface{}) {
guiUtil_UrlRegeditWg.Add(1) // 注册前增加计数器
defer guiUtil_UrlRegeditWg.Done() // 注册结束时减少计数器
guiUtil_CheckWrite.Lock() //加锁
defer guiUtil_CheckWrite.Unlock() //解锁
temp := url + iType.String()
_, ok := httpHandleFunc[temp]
if ok {
Log.Error("链接重复:" + url)
return
}
httpHandleFunc[temp] = HttpHandleInfo{
Url: url,
Type: iType,
Fun: handler,
}
}
// 取注册的web接口
func (gu GinUtil) GetController() map[string]HttpHandleInfo {
guiUtil_UrlRegeditWg.Wait() // 等待所有注册完成
return httpHandleFunc
}
/**
* 取注册的web接口
*/
func (gu GinUtil) GetHandleFunc(urlKey string, iType RequestType, InterceptorFunc func(ctx *gin.Context) bool,
controllerMap map[string]HttpHandleInfo) func(ctx *gin.Context) {
result := func(ctx *gin.Context) {
urlStr := ctx.Request.URL.Path
if nil != InterceptorFunc {
if !InterceptorFunc(ctx) {
return
}
}
var urlAndType string
if strings.HasPrefix(urlStr, "/proxy/") { //路径中存在转发请求
urlAndType = "/proxy/*proxy" + iType.String()
} else {
urlAndType = urlKey + iType.String() //url和请求方式组合
}
httpHandleInfo, ok := controllerMap[urlAndType] //给个默认
if !ok {
return
}
// for runKey := range controllerMap {
// if runKey != urlStr {
// continue
// }
// httpHandleInfo = controllerMap[urlAndType]
// vb = true
// break
// }
// if !vb {
// return
// }
obj := httpHandleInfo.Fun(ctx)
switch obj.(type) {
case *emity.MsgEmity, emity.MsgEmity:
ctx.JSONP(http.StatusOK, obj)
case *emity.FileEmity:
fm := obj.(*emity.FileEmity)
if !fm.Gsuccess {
ctx.JSONP(http.StatusOK, obj)
break
}
if fm.Gdisposition != "" {
ctx.Header("Content-Disposition", fm.Gdisposition)
}
ctx.Header("Content-Type", fm.Gtype)
ctx.Header("Content-Length", fm.GsLength)
ctx.Writer.Write(fm.Gdata.([]byte))
case emity.FileEmity:
fm := obj.(emity.FileEmity)
if !fm.Gsuccess {
ctx.JSONP(http.StatusOK, obj)
break
}
if fm.Gdisposition != "" {
ctx.Header("Content-Disposition", fm.Gdisposition)
}
ctx.Header("Content-Type", fm.Gtype)
ctx.Header("Content-Length", fm.GsLength)
ctx.Writer.Write(fm.Gdata.([]byte))
case []byte:
by := obj.([]byte)
ctx.Header("Content-Type", "application/octet-stream")
ctx.Header("Content-Length", strconv.Itoa(len(by)))
ctx.Writer.Write(by)
default:
ctx.Writer.Write([]byte(fmt.Sprintf("%v", obj)))
}
}
return result
}
// 关闭服务
func (gu GinUtil) Shutdown(ctx *gin.Context) {
key := gu.getParam(ctx, "sInsideKey")
if key == "" {
ctx.JSONP(http.StatusOK, emity.MsgEmity{}.Err(100001, "关闭密钥参数sInsideKey缺失"))
return
}
appKey := gu.readConfigKey("App", "InsideKey", "12345")
if appKey != key {
ctx.JSONP(http.StatusOK, emity.MsgEmity{}.Err(100001, "关闭密钥参数错误"))
return
}
Log.Debug("关闭服务...")
if err := appGinServer.Shutdown(ctx); err != nil {
Log.Debug("服务强制关闭发生异常:", err)
ctx.JSONP(http.StatusOK, emity.MsgEmity{}.Err(100003, "服务强制关闭发生异常"))
return
}
fmt.Println("服务关闭")
ctx.JSONP(http.StatusOK, emity.MsgEmity{}.Success(9999, "服务强制关闭成功"))
}
/**
* 取参数
* ctx GinHttp上下文对象
* name 参数名称
* def 默认值
*/
func (gu GinUtil) getParam(ctx *gin.Context, name string) string {
ctx.Request.ParseForm() //警告:必须先 解析所有请求数据
//-- 取POST方法的参数 --//
params := make(map[string]interface{})
br, _ := io.ReadAll(ctx.Request.Body)
ctx.Request.Body.Close()
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(br))
json.NewDecoder(bytes.NewBuffer(br)).Decode(&params)
temp, ok := params[name]
if ok {
return fmt.Sprint(temp)
}
//-- 取GET方法的参数 --//
query := ctx.Request.URL.Query() // 获取请求的参数
v := query[name]
if nil != v && len(v) > 0 && strings.TrimSpace(v[0]) != "" {
return v[0]
}
return ""
}
/**
* 读取配置文件
* section 配置文件section
* key 配置文件key
* def 默认值
*/
func (gu GinUtil) readConfigKey(section, key, def string) string {
root := ""
exePath, err := os.Executable()
if err != nil {
root = "."
}
root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))
configFilePath := strings.Replace(root+"/config/app.ini", "\\", "/", -1)
_, err = os.Stat(configFilePath) //os.Stat获取文件信息
if err != nil {
if !os.IsExist(err) {
Log.Error("配置文件不存在", err)
return def
}
}
// 加载配置文件
conf, err := ini.Load(configFilePath)
if err != nil {
Log.Error("读取配置文件失败:", err)
return def
}
// 获取配置文件中的 section 和 key
appSection := conf.Section(section)
result, err := appSection.GetKey(key)
if err != nil {
Log.Error("读取配置项失败:", err)
return def
}
return fmt.Sprintf("%v", result)
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/tomatomeatman/golang-repository.git
git@gitee.com:tomatomeatman/golang-repository.git
tomatomeatman
golang-repository
GolangRepository
58c3962bcc30

搜索帮助