代码拉取完成,页面将自动刷新
package ginutil
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"gitee.com/tomatomeatman/golang-repository/bricks/model/emity"
"gitee.com/tomatomeatman/golang-repository/bricks/model/fileback"
Log "github.com/cihub/seelog"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"gopkg.in/ini.v1"
)
type Context = *gin.Context
var SetMode = gin.SetMode
var Default = gin.Default
const DebugMode = gin.DebugMode
const ReleaseMode = gin.ReleaseMode
const TestMode = gin.TestMode
// 请求类型枚举
type RequestType string
const (
GET RequestType = "GET"
POST RequestType = "POST"
DELETE RequestType = "DELETE"
PUT RequestType = "PUT"
OPTIONS RequestType = "OPTIONS"
WEBSOCKET RequestType = "WEBSOCKET"
)
// 枚举转字符串
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"
case WEBSOCKET:
return "WEBSOCKET"
default:
return "NA"
}
}
var (
regeditWaitGroup sync.WaitGroup //同步原语,要保证所有的Url注册都已经完成
writeLock sync.Mutex //保存锁
httpHandleFunc = make(map[string]HttpHandleInfo) //http控制层接口信息集合
websocketFunc = make(map[string]HttpHandleInfo) //websocket控制层接口信息集合
appGinServer *http.Server
aopBefore = make(map[string][]func(ctx Context, params ...interface{}) *emity.MsgEmity) //前置拦截器
aopAround = make(map[string][]func(ctx Context, params ...interface{}) *emity.MsgEmity) //环绕拦截器
aopAfter = make(map[string][]func(ctx Context, params ...interface{}) *emity.MsgEmity) //后置拦截器
)
// http控制层接口信息
type HttpHandleInfo struct {
Url string
Type RequestType
Fun func(ctx Context) interface{}
}
// 设置跨域
func SetCors(r *gin.Engine) {
r.Use(Cors())
}
func GetGin(ginMode, webRoot, Port string, InterceptorFunc func(ctx Context) bool) *http.Server {
HttpHandleInfos := 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()
SetCors(r) //设置跨域
SetStatic(r, "."+webRoot) //设置静态目录
r.GET("/shutdown", Shutdown) //关机接口
r.POST("/shutdown", Shutdown) //关机接口
r.GET("/websocket", WebsocketServe) //websocket接口
for _, val := range HttpHandleInfos {
switch val.Type {
case GET:
r.GET(val.Url, GetHandleFunc(val.Url, GET, InterceptorFunc, HttpHandleInfos))
case POST:
r.POST(val.Url, GetHandleFunc(val.Url, POST, InterceptorFunc, HttpHandleInfos))
case DELETE:
r.DELETE(val.Url, GetHandleFunc(val.Url, DELETE, InterceptorFunc, HttpHandleInfos))
case PUT:
r.PUT(val.Url, GetHandleFunc(val.Url, PUT, InterceptorFunc, HttpHandleInfos))
case OPTIONS:
r.OPTIONS(val.Url, GetHandleFunc(val.Url, OPTIONS, InterceptorFunc, HttpHandleInfos))
// case WEBSOCKET:
// r.GET(val.Url, GetHandleWebsocketFunc(val.Url, WEBSOCKET, InterceptorFunc, HttpHandleInfos))
default:
r.GET(val.Url, func(ctx Context) {
ctx.JSONP(http.StatusBadRequest, emity.Err(1001, "请求方式错误,不支持此方式"))
})
}
}
httpHandleFunc = make(map[string]HttpHandleInfo) //清理
appGinServer = &http.Server{
Addr: ":" + Port,
Handler: r,
}
return appGinServer
}
// 跨域函数
func 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 SetStatic(r *gin.Engine, webroot string) {
_ = mime.AddExtensionType(".js", "application/javascript") // 特殊处理JS文件的Content-Type
r.Use(static.Serve("/", static.LocalFile(webroot, true))) // 前端项目静态资源
}
// 注册web接口
func RegisterController(url string, iTypes interface{}, handler func(ctx Context) interface{}) {
RegisterControllers(url, iTypes, handler)
}
// 注册web接口
func ControllerRegister(url string, handler func(ctx Context) interface{}, iTypes ...RequestType) {
if len(iTypes) < 1 {
registerController(url, POST, handler)
return
}
for _, rt := range iTypes {
registerController(url, rt, handler)
}
}
// 注册web接口
func RegisterControllers(url string, iTypes interface{}, handler func(ctx Context) interface{}) {
switch t := iTypes.(type) {
case RequestType:
registerController(url, t, handler)
case []RequestType:
if len(iTypes.([]RequestType)) < 1 {
registerController(url, POST, handler)
return
}
for _, v := range iTypes.([]RequestType) {
registerController(url, v, handler)
}
default:
registerController(url, POST, handler)
}
}
// 注册web接口
func registerController(url string, iType RequestType, handler func(ctx Context) interface{}) {
regeditWaitGroup.Add(1) // 注册前增加计数器
defer regeditWaitGroup.Done() // 注册结束时减少计数器
writeLock.Lock() //加锁
defer writeLock.Unlock() //解锁
temp := url + iType.String()
_, ok := httpHandleFunc[temp]
if ok {
Log.Error("链接重复:" + url)
return
}
if iType == WEBSOCKET {
websocketFunc[url] = HttpHandleInfo{
Url: url,
Type: iType,
Fun: handler,
}
return
}
httpHandleFunc[temp] = HttpHandleInfo{
Url: url,
Type: iType,
Fun: handler,
}
}
/**
* 根据url取函数
* @param url
* @param iType
* @param ctx
* @return
*/
func CallFuncByUrl(url string, iType RequestType, ctx Context) interface{} {
temp := url + iType.String()
fun, ok := httpHandleFunc[temp]
if !ok {
return nil
}
return fun.Fun(ctx)
}
// 取注册的web接口
func GetController() map[string]HttpHandleInfo {
regeditWaitGroup.Wait() // 等待所有注册完成
return httpHandleFunc
}
/**
* 取注册的web接口
*/
func GetHandleFunc(urlKey string, iType RequestType, InterceptorFunc func(ctx Context) bool,
controllerMap map[string]HttpHandleInfo) func(ctx Context) {
result := func(ctx Context) {
if nil != InterceptorFunc {
if !InterceptorFunc(ctx) {
return
}
}
urlStr := ctx.Request.URL.Path
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
}
// 执行前置函数
meBefore := CallBeforeFunc(urlStr, ctx)
if !meBefore.Gsuccess {
ctx.JSONP(http.StatusOK, meBefore)
return
}
// 执行本体函数
obj := httpHandleInfo.Fun(ctx)
if obj == nil { //如果返回值是nil,则直接返回(需要函数内自己处理)
return
}
// 执行后置函数
meAfter := CallAfterFunc(urlStr, ctx, obj)
if !meAfter.Gsuccess {
ctx.JSONP(http.StatusOK, meAfter)
return
}
// 执行返回处理
switch obj := obj.(type) {
case *emity.MsgEmity, emity.MsgEmity:
ctx.JSONP(http.StatusOK, obj)
case *fileback.FileBack:
fm := obj
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 fileback.FileBack:
fm := obj
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
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
}
/**
* 取注册的Websocket接口
*/
func GetHandleWebsocketFunc(urlKey string, iType RequestType, InterceptorFunc func(ctx Context) bool,
controllerMap map[string]HttpHandleInfo) func(ctx Context) {
result := func(ctx Context) {
if nil != InterceptorFunc {
if !InterceptorFunc(ctx) {
return
}
}
var upgrader = websocket.Upgrader{
// 这个是校验请求来源
// 在这里我们不做校验,直接return true
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// 将普通的http GET请求升级为websocket请求
client, err := upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "将普通的http GET请求升级为websocket请求失败"})
return
}
defer client.Close()
urlAndType := urlKey + iType.String() //url和请求方式组合
httpHandleInfo, ok := controllerMap[urlAndType] //给个默认
if !ok {
return
}
for {
_, value, err := client.ReadMessage()
if err != nil {
return
}
// 将信息存放到请求参数中
r := ctx.Request
r.ParseForm() //警告:必须先 解析所有请求数据
form := r.Form
if form == nil {
form = make(url.Values)
r.Form = form
}
form.Set("msg", string(value))
// 执行本体函数
obj := httpHandleInfo.Fun(ctx)
if obj == nil { //如果返回值是nil,则直接返回(需要函数内自己处理)
msg := emity.ErrString(1001, "执行失败,执行结果为nil")
err = client.WriteMessage(websocket.TextMessage, []byte(msg))
if err != nil {
Log.Error("Websocket发送信息到前端异常:", err)
return
}
return
}
// 发送执行结果
msg, _ := json.Marshal(obj)
err = client.WriteMessage(websocket.TextMessage, msg)
if err != nil {
Log.Error("Websocket发送信息到前端异常:", err)
return
}
}
}
return result
}
// 关闭服务
func Shutdown(ctx Context) {
key := getParamString(ctx, "sInsideKey", "")
if key == "" {
ctx.JSONP(http.StatusOK, emity.Err(100001, "关闭密钥参数sInsideKey缺失"))
return
}
appKey := readConfigKey("App", "InsideKey", "12345")
if appKey != key {
ctx.JSONP(http.StatusOK, emity.Err(100001, "关闭密钥参数错误"))
return
}
Log.Debug("关闭服务...")
if err := appGinServer.Shutdown(ctx); err != nil {
Log.Debug("服务强制关闭发生异常:", err)
ctx.JSONP(http.StatusOK, emity.Err(100003, "服务强制关闭发生异常"))
return
}
fmt.Println("服务关闭")
ctx.JSONP(http.StatusOK, emity.Success(9999, "服务强制关闭成功"))
}
/**
* 取参数
* ctx GinHttp上下文对象
* name 参数名称
* def 默认值
*/
func getParamString(ctx Context, name, def 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(¶ms)
temp, ok := params[name]
if ok {
return fmt.Sprint(temp)
}
//-- 取GET方法的参数 --//
query := ctx.Request.URL.Query() // 获取请求的参数
v := query[name]
if len(v) > 0 && strings.TrimSpace(v[0]) != "" {
return v[0]
}
return def
}
/**
* 读取配置文件
* section 配置文件section
* key 配置文件key
* def 默认值
*/
func 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)
}
/**
* 注册Aop-函数执行前调用函数
* @param urlStr 被监听函数
* @param doFunc 被调用函数
* @return
*/
func RegisterBefore(urlStr string, doFunc func(ctx Context, params ...interface{}) *emity.MsgEmity) {
urlStr = strings.TrimSpace(urlStr)
if urlStr == "" {
return
}
regeditWaitGroup.Add(1) // 注册前增加计数器
defer regeditWaitGroup.Done() // 注册结束时减少计数器
writeLock.Lock() //加锁
defer writeLock.Unlock() //解锁
funcArray, ok := aopBefore[urlStr]
if ok {
funcArray = append(funcArray, doFunc)
aopBefore[urlStr] = funcArray
return
}
funcArray = []func(ctx Context, params ...interface{}) *emity.MsgEmity{doFunc}
aopBefore[urlStr] = funcArray
}
/**
* 注册Aop-控制函数执行后调用函数
* @param urlStr 被监听控制Url地址(注册web接口时的url地址)
* @param doFunc 被调用函数
* @return
*/
func RegisterAfter(urlStr string, doFunc func(ctx Context, params ...interface{}) *emity.MsgEmity) {
urlStr = strings.TrimSpace(urlStr)
if urlStr == "" {
return
}
regeditWaitGroup.Add(1) // 注册前增加计数器
defer regeditWaitGroup.Done() // 注册结束时减少计数器
writeLock.Lock() //加锁
defer writeLock.Unlock() //解锁
funcArray, ok := aopAfter[urlStr]
if ok {
funcArray = append(funcArray, doFunc)
aopAfter[urlStr] = funcArray
return
}
funcArray = []func(ctx Context, params ...interface{}) *emity.MsgEmity{doFunc}
aopAfter[urlStr] = funcArray
}
/**
* 注册Aop-控制函数执行中调用函数
* @param urlStr 被监听控制Url地址(注册web接口时的url地址)
* @param doFunc 被调用函数
* @return
*/
func RegisterAround(urlStr string, doFunc func(ctx Context, params ...interface{}) *emity.MsgEmity) {
urlStr = strings.TrimSpace(urlStr)
if urlStr == "" {
return
}
regeditWaitGroup.Add(1) // 注册前增加计数器
defer regeditWaitGroup.Done() // 注册结束时减少计数器
writeLock.Lock() //加锁
defer writeLock.Unlock() //解锁
funcArray, ok := aopAround[urlStr]
if ok {
funcArray = append(funcArray, doFunc)
aopAround[urlStr] = funcArray
return
}
funcArray = []func(ctx Context, params ...interface{}) *emity.MsgEmity{doFunc}
aopAround[urlStr] = funcArray
}
/**
* 调用Aop-控制函数执行前调用函数
* @param urlStr 被监听控制Url地址(注册web接口时的url地址)
* @param doFunc 被调用函数
* @return
*/
func CallBeforeFunc(urlStr string, ctx Context, params ...interface{}) *emity.MsgEmity {
return callFunc(aopBefore, urlStr, ctx, params)
}
/**
* 调用Aop-函数执行后调用函数
* @param urlStr 被监听控制Url地址(注册web接口时的url地址)
* @param doFunc 被调用函数
* @return
*/
func CallAfterFunc(urlStr string, ctx Context, params ...interface{}) *emity.MsgEmity {
return callFunc(aopAfter, urlStr, ctx, params)
}
/**
* 调用Aop-函数执行中调用函数
* @param urlStr 被监听控制Url地址(注册web接口时的url地址)
* @param doFunc 被调用函数
* @return
*/
func CallAroundFunc(urlStr string, ctx Context, params ...interface{}) *emity.MsgEmity {
return callFunc(aopAround, urlStr, ctx, params)
}
/**
* 调用Aop-函数执行中调用函数
* @param aopInfo aop信息
* @param urlStr 被监听控制Url地址(注册web接口时的url地址)
* @param doFunc 被调用函数
* @return
*/
func callFunc(aopInfo map[string][]func(ctx Context, params ...interface{}) *emity.MsgEmity,
urlStr string, ctx Context, params []interface{}) *emity.MsgEmity {
if urlStr == "" {
return emity.Success(1000, "函数名为空,不处理")
}
funcArray, ok := aopInfo[urlStr]
if !ok {
return emity.Success(1001, "没有函数,不处理")
}
if len(funcArray) < 1 {
return emity.Success(1002, "没有调用函数,结束AOP处理")
}
for _, fun := range funcArray {
me := fun(ctx, params...)
if !me.Gsuccess {
return me
}
}
return emity.Success(1003, "调用函数没有错误,结束AOP处理")
}
/**
* websocket服务
* @param context
*/
func WebsocketServe(context Context) {
var upgrader = websocket.Upgrader{
// 这个是校验请求来源
// 在这里我们不做校验,直接return true
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// 将普通的http GET请求升级为websocket请求
client, err := upgrader.Upgrade(context.Writer, context.Request, nil)
if err != nil {
context.JSON(http.StatusInternalServerError, gin.H{"error": "Upgrade failed"})
return
}
defer client.Close()
for {
_, jsonStr, err := client.ReadMessage()
if err != nil {
return
}
m := make(map[string]interface{})
err = json.Unmarshal([]byte(jsonStr), &m)
if err != nil {
Log.Error("Json字符串转换异常: %+v\n", err)
me := map[string]interface{}{
"requestSign": "未知",
"success": false,
"msg": "请求失败,请求参数格式可能存在问题,必须是json字符串格式:{'controllerurl':'控制层url','参数1':'参数1值','参数2':参数2值}",
"data": 1001,
}
result, _ := json.Marshal(me)
err = client.WriteMessage(websocket.TextMessage, result)
if err != nil {
Log.Error("Websocket发送信息到前端异常:", err)
return
}
return
}
sign := m["requestSign"]
urlstr, ok := m["controllerurl"]
if !ok {
me := map[string]interface{}{
"requestSign": sign,
"success": false,
"msg": "请求失败,controllerurl参数缺失",
"data": 1002,
}
result, _ := json.Marshal(me)
err = client.WriteMessage(websocket.TextMessage, result)
if err != nil {
Log.Error("Websocket发送信息到前端异常:", err)
return
}
return
}
httpHandleInfo, ok := websocketFunc[urlstr.(string)] //给个默认
if !ok {
me := map[string]interface{}{
"requestSign": sign,
"success": false,
"msg": "没有符合的请求接口",
"data": 1003,
}
result, _ := json.Marshal(me)
err = client.WriteMessage(websocket.TextMessage, result)
if err != nil {
Log.Error("Websocket发送信息到前端异常:", err)
return
}
return
}
// 将信息存放到请求参数中
r := context.Request
r.ParseForm() //警告:必须先 解析所有请求数据
form := r.Form
if form == nil {
form = make(url.Values)
r.Form = form
}
for k, v := range m {
if k == "controllerurl" {
continue
}
if k == "requestSign" {
continue
}
form.Set(k, fmt.Sprintf("%v", v))
}
// 执行本体函数
obj := httpHandleInfo.Fun(context)
if obj == nil { //如果返回值是nil,则直接返回(需要函数内自己处理)
me := map[string]interface{}{
"requestSign": sign,
"success": false,
"msg": "执行失败,执行结果为nil",
"data": 1004,
}
result, _ := json.Marshal(me)
err = client.WriteMessage(websocket.TextMessage, result)
if err != nil {
Log.Error("Websocket发送信息到前端异常:", err)
return
}
return
}
// 发送执行结果
temp := obj.(*emity.MsgEmity)
me := map[string]interface{}{
"requestSign": sign,
"success": temp.Gsuccess,
"msg": temp.Gmsg,
"data": temp.Gdata,
}
result, _ := json.Marshal(me)
err = client.WriteMessage(websocket.TextMessage, result)
if err != nil {
Log.Error("Websocket发送信息到前端异常:", err)
return
}
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。