{"id":13794295,"url":"https://github.com/xiaobopang/go_init","last_synced_at":"2025-09-08T10:32:41.787Z","repository":{"id":41086422,"uuid":"159330874","full_name":"xiaobopang/go_init","owner":"xiaobopang","description":"一个用go组织项目结构，主要包括 gin, goredis, gorm, websocket, rabbitmq等。👉","archived":false,"fork":false,"pushed_at":"2019-05-31T02:14:49.000Z","size":11965,"stargazers_count":234,"open_issues_count":0,"forks_count":45,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-02-14T19:33:17.044Z","etag":null,"topics":["gin","goredis","gorm","iris","json","rabbitmq","websocket"],"latest_commit_sha":null,"homepage":"https://dzjo.cn","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xiaobopang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-11-27T12:18:31.000Z","updated_at":"2024-02-07T14:51:27.000Z","dependencies_parsed_at":"2022-08-29T13:31:46.125Z","dependency_job_id":null,"html_url":"https://github.com/xiaobopang/go_init","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiaobopang%2Fgo_init","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiaobopang%2Fgo_init/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiaobopang%2Fgo_init/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiaobopang%2Fgo_init/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xiaobopang","download_url":"https://codeload.github.com/xiaobopang/go_init/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232302271,"owners_count":18502114,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gin","goredis","gorm","iris","json","rabbitmq","websocket"],"created_at":"2024-08-03T23:00:38.313Z","updated_at":"2025-01-03T06:47:01.472Z","avatar_url":"https://github.com/xiaobopang.png","language":"Go","readme":"## Introduce\n\n    这是一个基于gin搭建的一个包含gorm, goredis,rabbitmq,websocket等操作相关操作的项目结构。\n\n    主要提供一些库和组件的实现案例，以及项目开发部署，发布，执行等流程。纯属个人兴趣，学习整理过程，\n    \n    如有发现不合理的地方希望大家可以提出建议和指正。\n\n    通过执行 go get -u github.com/xiaobopang/go_init 来下载安装该项目，使用 govendor sync来拉取依赖到vendor目录，\n\n    注意vendor所在的目录一定要在第一个GOPAHT下。\n\n    通过 go build -o go_init main.go 来生成执行文件,其他平台编译方式见文档底部。\n    \n    压缩go build的二进制文件,可使用 go build -ldflags \"-s -w\" -o go_init main.go\n\n    这里的 -ldflags 参数最终会在 go tool link 的时候传给它， go tool link -h 解释如下\n    \n        ...\n        -s    disable symbol table\n        -w    disable DWARF generation\n\n    这样处理可以删除掉调试符号,从而显著减小了文件大小（平均20%）,也可以相对的隐藏一些源码信息。\n    \n    如果你觉得这样压缩之后文件还是比较大，那么我们还可以再加一个UPX壳，这样编译过后的二进制文件\n    \n    还可以压缩到原文件大小的五分之一。具体操作如下：\n\n[UPX安装](https://github.com/upx/upx) 👈点击\n\n        1、go build -ldflags \"-s -w\" -o go_init main.go\n\n        2、upx go_init\n\n        结果如下：\n![执行结果](./1.png)\n\n    启动服务：./run.sh start\n\n    停止服务：./run.sh stop\n\n    注意：有可能出现没有执行权限的情况，执行 sudo chmod +x run.sh来解决\n\n    1. Mysql\n\n    2. Redis\n\n    3. Websocket\n\n    4. RabbitMQ\n\n    5. ElasticSearch\n\n### Router 示例\n\n```\n        package router\n\n        /*\n        * @Script: routers.go\n        * @Author: pangxiaobo\n        * @Email: 10846295@qq.com\n        * @Create At: 2018-11-27 18:19:27\n        * @Last Modified By: pangxiaobo\n        * @Last Modified At: 2018-12-12 14:25:18\n        * @Description: This is description.\n        */\n\n        import (\n                \"net/http\"\n\n                \"github.com/gin-gonic/gin\"\n                \"github.com/xiaobopang/go_init/controller\"\n                \"github.com/xiaobopang/go_init/middleware\"\n        )\n\n        var indexCtl = new(controller.IndexController)\n        var testCtl = new(controller.TestController)\n        var wsCtl = new(controller.WsController)\n        var mqCtl = new(controller.MqController)\n\n        func SetupRouter() *gin.Engine {\n                router := gin.Default()\n                router.Use(gin.Recovery())\n                //router.Use(gin.Logger())\n\n                router.GET(\"/\", indexCtl.Welcome)\n                router.NoRoute(indexCtl.Handle404)\n\n                // 简单的路由组: v1\n                v1 := router.Group(\"/v1\")\n                {\n                        v1.GET(\"/redis\", testCtl.RedisTest) //redis 测试\n\n                        v1.POST(\"/exchange\", func(c *gin.Context) {\n                                mqCtl.ExchangeHandler(c.Writer, c.Request)\n                        })\n                        v1.POST(\"/queue/bind\", func(c *gin.Context) {\n                                mqCtl.QueueBindHandler(c.Writer, c.Request)\n                        })\n                        v1.GET(\"/queue\", func(c *gin.Context) {\n                                mqCtl.QueueHandler(c.Writer, c.Request)\n                        }) //consume queue\n                        v1.POST(\"/queue\", func(c *gin.Context) {\n                                mqCtl.QueueHandler(c.Writer, c.Request)\n                        }) //declare queue\n                        v1.DELETE(\"/queue\", func(c *gin.Context) {\n                                mqCtl.QueueHandler(c.Writer, c.Request)\n                        }) //delete queue\n                        v1.POST(\"/publish\", func(c *gin.Context) {\n                                mqCtl.PublishHandler(c.Writer, c.Request)\n                        })\n                        v1.GET(\"/ws\", func(c *gin.Context) {\n                                wsCtl.WsHandler(c.Writer, c.Request)\n                        })\n\n                        v1.GET(\"/get_token\", testCtl.GetToken)\n                }\n\n                router.GET(\"/redirect\", func(c *gin.Context) {\n                        c.Redirect(http.StatusMovedPermanently, \"https://www.unclepang.com/\")\n                })\n\n                v2 := router.Group(\"/v2\")\n                v2.Use(middleware.CORS(middleware.CORSOptions{}))\n                {\n                        v2.GET(\"/user\", testCtl.GetUser)\n                        v2.GET(\"/es\", testCtl.ES)\n                        v2.POST(\"/user\", testCtl.AddUser)\n                        v2.DELETE(\"/user\", testCtl.DelUser)\n                        v2.PATCH(\"/user\", testCtl.UptUser)\n                }\n\n                return router\n        }\n\n\n```\n\n### Request and Response 示例\n\n```\n        package controller\n\n        /*\n        * @Script: test.go\n        * @Author: pangxiaobo\n        * @Email: 10846295@qq.com\n        * @Create At: 2018-11-06 14:50:15\n        * @Last Modified By: pangxiaobo\n        * @Last Modified At: 2018-12-12 14:25:46\n        * @Description: This is description.\n        */\n\n        import (\n                \"encoding/json\"\n                \"fmt\"\n                \"strconv\"\n                \"time\"\n\n                \"github.com/elastic/go-elasticsearch\"\n                \"github.com/gin-gonic/gin\"\n                \"github.com/xiaobopang/go_init/helper\"\n                \"github.com/xiaobopang/go_init/lib\"\n                \"github.com/xiaobopang/go_init/model\"\n        )\n\n        type TestController struct{}\n\n        func (t *TestController) GetNick(c *gin.Context) {\n                nickname := c.DefaultQuery(\"nick\", \"guest\")\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      map[string]string{\"nickname\": nickname},\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n        }\n\n        //获取用户\n        func (t *TestController) GetUser(c *gin.Context) {\n\n                id, _ := strconv.Atoi(c.Query(\"id\"))\n                fmt.Println(id)\n\n                res, _ := model.GetUserById(id)\n\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      res,\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n        }\n\n        //获取用户\n        func (t *TestController) UserList(c *gin.Context) {\n                keyword := c.Query(\"keyword\")\n                pageNo := c.GetInt(\"page_number\")\n                pageSize := c.GetInt(\"page_size\")\n\n                res := model.UsersList(pageNo, pageSize, \"username = ?\", keyword)\n\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      res,\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n        }\n\n        //新增用户\n        func (t *TestController) AddUser(c *gin.Context) {\n\n                name := c.PostForm(\"name\")\n                password := helper.Md5(c.PostForm(\"password\"))\n                age, _ := strconv.Atoi(c.DefaultPostForm(\"age\", \"20\"))\n                gender, _ := strconv.Atoi(c.DefaultPostForm(\"gender\", \"1\"))\n                email := c.PostForm(\"email\")\n\n                res := model.AddUser(name, password, age, gender, email)\n\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      res,\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n        }\n\n        //删除用户 (硬删除)\n        func (t *TestController) DelUser(c *gin.Context) {\n\n                id, _ := strconv.Atoi(c.Query(\"id\"))\n                fmt.Println(id)\n\n                res := model.DelUser(id)\n\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      res,\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n        }\n\n        //更新\n        func (t *TestController) UptUser(c *gin.Context) {\n\n                id, _ := strconv.Atoi(c.PostForm(\"id\"))\n                data := make(map[string]interface{})\n\n                data[\"username\"] = c.PostForm(\"name\")\n                data[\"password\"] = helper.Md5(c.PostForm(\"password\"))\n                data[\"age\"], _ = strconv.Atoi(c.DefaultPostForm(\"age\", \"20\"))\n                data[\"gender\"], _ = strconv.Atoi(c.DefaultPostForm(\"gender\", \"1\"))\n                data[\"email\"] = c.PostForm(\"email\")\n                data[\"updated_at\"] = time.Now().Unix()\n\n                res := model.UptUser(id, data)\n\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      res,\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n        }\n\n        //Redis 测试\n        func (t *TestController) RedisTest(c *gin.Context) {\n                redisKey := c.Query(\"redisKey\")\n\n                userInfo, err := lib.GetKey(redisKey)\n                if err != nil {\n                        data := make(map[string]interface{})\n                        data[\"username\"] = \"jack\"\n                        data[\"age\"] = 22\n                        data[\"gender\"] = \"man\"\n                        data[\"email\"] = \"test@test.com\"\n                        data[\"updated_at\"] = time.Now().Unix()\n                        userInfo, err := json.Marshal(data)\n                        lib.SetKey(redisKey, userInfo, 3600)\n                        if err != nil {\n                                fmt.Println(err)\n                        }\n                }\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      userInfo,\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n        }\n\n        func (t *TestController) GetToken(c *gin.Context) {\n                token, err := lib.GenerateToken(1, \"pang@pang.com\")\n                if err != nil {\n                        fmt.Println(\"err: \", err)\n                }\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      token,\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n\n        }\n\n        // es 测试\n        func (t *TestController) ES(c *gin.Context) {\n                cfg := elasticsearch.Config{\n                        Addresses: []string{\n                                \"http://127.0.0.1:9201\",\n                        },\n                }\n                es, err := elasticsearch.NewClient(cfg)\n                if err != nil {\n                        fmt.Println(\"elasticsearch has error: \", err)\n                }\n                // 1. Get cluster info\n                //\n                res, err := es.Info()\n                if err != nil {\n                        fmt.Println(\"Error getting response: %s\", err)\n                }\n                c.JSON(200, gin.H{\n                        \"code\":      200,\n                        \"data\":      res,\n                        \"msg\":       \"success\",\n                        \"timestamp\": time.Now().Unix(),\n                })\n        }\n\n\n```\n\n### model 示例\n\n```\n        package model\n\n        import (\n                \"time\"\n        )\n\n        type User struct {\n                ID        int    `gorm:\"primary_key\" json:\"id\"`\n                Username  string `json:\"username\"`\n                Password  string `json:\"password\"`\n                Age       int    `json:\"age\"`\n                Email     string `json:\"email\"`\n                Gender    int    `json:\"gender\"`\n                CreatedAt int64  `json:\"created_at\"`\n                UpdatedAt int64  `json:\"updated_at\"`\n        }\n\n        type Page struct {\n                TotalCount int\n                List       interface{}\n        }\n\n        //通过 args可以动态传递多个参数\n        func UsersList(pageNo int, pageSize int, args ...interface{}) (page Page) {\n                var users []User\n                var userCount []User\n                var count uint\n\n                db := DB.Table(\"user\")\n                if len(args) \u003e= 2 {\n                        db = db.Where(args[0], args[1:]...)\n                } else {\n                        db = db.Where(args[0])\n                }\n                db.Select(\"id,username,age,email,gender,created_at\").Limit(pageSize).Offset((pageNo - 1) * pageSize).Scan(\u0026users)\n\n                if pageNo == 1 {\n                        db.Select(\"id,username,age,email,gender,created_at\").Scan(\u0026userCount).Count(\u0026count)\n                        TotalCount := count\n                        page.TotalCount = int(TotalCount)\n                } else {\n                        TotalCount := len(users)\n                        page.TotalCount = int(TotalCount)\n                }\n                page.List = users\n                return page\n        }\n        func GetUserById(id int) *User {\n                var user User\n                DB.First(\u0026user, \"id = ?\", id)\n                return \u0026user\n        }\n\n        func AddUser(name string, password string, age int, gender int, email string) error {\n                user := User{\n                        Username:  name,\n                        Password:  password,\n                        Age:       age,\n                        Gender:    gender,\n                        Email:     email,\n                        CreatedAt: time.Now().Unix(),\n                }\n                if err := DB.Create(\u0026user).Error; err != nil {\n                        return err\n                }\n                return nil\n        }\n\n        func DelUser(id int) error {\n                if err := DB.Where(\"id = ?\", id).Delete(\u0026User{}).Error; err != nil {\n                        return err\n                }\n\n                return nil\n        }\n\n        func UptUser(id int, data interface{}) error {\n\n                if err := DB.Model(\u0026User{}).Where(\"id = ? AND is_deleted = ? \", id, 0).Updates(data).Error; err != nil {\n                        return err\n                }\n\n                return nil\n        }\n\n```\n\n### websocket 示例\n\n#####  前端通过访问 ws://localhost:7777/ws 即可与服务端建立websocket连接\n\n```\n        package controller\n\n        import (\n                \"errors\"\n                \"fmt\"\n                \"github.com/gorilla/websocket\"\n                \"net/http\"\n                \"sync\"\n                \"time\"\n        )\n\n        var wsUpgrader = websocket.Upgrader{\n                ReadBufferSize:    4096,\n                WriteBufferSize:   4096,\n                EnableCompression: true,\n                HandshakeTimeout:  5 * time.Second,\n                // CheckOrigin: 处理跨域问题，线上环境慎用\n                CheckOrigin: func(r *http.Request) bool {\n                        return true\n                },\n        }\n\n        // 客户端读写消息\n        type wsMessage struct {\n                messageType int\n                data        []byte\n        }\n        type Wscontroller struct{}\n\n        // 客户端连接\n        type wsConnection struct {\n                wsSocket *websocket.Conn // 底层websocket\n                inChan   chan *wsMessage // 读队列\n                outChan  chan *wsMessage // 写队列\n\n                mutex     sync.Mutex // 避免重复关闭管道\n                isClosed  bool\n                closeChan chan byte // 关闭通知\n        }\n\n        func (wsConn *wsConnection) wsReadLoop() {\n                for {\n                        // 读一个message\n                        msgType, data, err := wsConn.wsSocket.ReadMessage()\n                        if err != nil {\n                                goto error\n                        }\n                        req := \u0026wsMessage{\n                                msgType,\n                                data,\n                        }\n                        // 放入请求队列\n                        select {\n                        case wsConn.inChan \u003c- req:\n                        case \u003c-wsConn.closeChan:\n                                goto closed\n                        }\n                }\n        error:\n                wsConn.wsClose()\n        closed:\n        }\n        func (wsConn *wsConnection) wsWriteLoop() {\n                for {\n                        select {\n                        // 取一个应答\n                        case msg := \u003c-wsConn.outChan:\n                                // 写给websocket\n                                if err := wsConn.wsSocket.WriteMessage(msg.messageType, msg.data); err != nil {\n                                        goto error\n                                }\n                        case \u003c-wsConn.closeChan:\n                                goto closed\n                        }\n                }\n        error:\n                wsConn.wsClose()\n        closed:\n        }\n\n        func (wsConn *wsConnection) procLoop() {\n                // 启动一个gouroutine发送心跳\n                go func() {\n                        for {\n                                time.Sleep(2 * time.Second)\n                                if err := wsConn.wsWrite(websocket.TextMessage, []byte(\"heartbeat from server\")); err != nil {\n                                        fmt.Println(\"heartbeat fail\")\n                                        wsConn.wsClose()\n                                        break\n                                }\n                        }\n                }()\n\n                // 这是一个同步处理模型（只是一个例子），如果希望并行处理可以每个请求一个gorutine，注意控制并发goroutine的数量!!!\n                for {\n                        msg, err := wsConn.wsRead()\n                        if err != nil {\n                                fmt.Println(\"read fail\")\n                                break\n                        }\n                        fmt.Println(string(msg.data))\n                        err = wsConn.wsWrite(msg.messageType, msg.data)\n                        if err != nil {\n                                fmt.Println(\"write fail\")\n                                break\n                        }\n                }\n        }\n\n        func (w *Wscontroller) WsHandler(resp http.ResponseWriter, req *http.Request) {\n                // 应答客户端告知升级连接为websocket\n                wsSocket, err := wsUpgrader.Upgrade(resp, req, nil)\n                if err != nil {\n                        return\n                }\n                wsConn := \u0026wsConnection{\n                        wsSocket:  wsSocket,\n                        inChan:    make(chan *wsMessage, 1000),\n                        outChan:   make(chan *wsMessage, 1000),\n                        closeChan: make(chan byte),\n                        isClosed:  false,\n                }\n\n                // 处理器\n                go wsConn.procLoop()\n                // 读协程\n                go wsConn.wsReadLoop()\n                // 写协程\n                go wsConn.wsWriteLoop()\n        }\n\n        func (wsConn *wsConnection) wsWrite(messageType int, data []byte) error {\n                select {\n                case wsConn.outChan \u003c- \u0026wsMessage{messageType, data}:\n                case \u003c-wsConn.closeChan:\n                        return errors.New(\"websocket closed\")\n                }\n                return nil\n        }\n\n        func (wsConn *wsConnection) wsRead() (*wsMessage, error) {\n                select {\n                case msg := \u003c-wsConn.inChan:\n                        return msg, nil\n                case \u003c-wsConn.closeChan:\n                }\n                return nil, errors.New(\"websocket closed\")\n        }\n\n        func (wsConn *wsConnection) wsClose() {\n                wsConn.wsSocket.Close()\n\n                wsConn.mutex.Lock()\n                defer wsConn.mutex.Unlock()\n                if !wsConn.isClosed {\n                        wsConn.isClosed = true\n                        close(wsConn.closeChan)\n                }\n        }\n\n```\n\n\n\n### RabbitMQ 示例\n\n```\n        package controller\n\n        import (\n                \"encoding/json\"\n                \"flag\"\n                \"fmt\"\n                \"io/ioutil\"\n                \"log\"\n                \"net/http\"\n\n                \"github.com/streadway/amqp\"\n        )\n\n        var (\n                amqpUri = flag.String(\"amqp\", \"amqp://guest:guest@127.0.0.1:5672/\", \"amqp uri\")\n        )\n\n        func init() {\n                flag.Parse()\n        }\n\n        type MqController struct{}\n\n        // Entity for HTTP Request Body: Message/Exchange/Queue/QueueBind JSON Input\n        type MessageEntity struct {\n                Exchange     string `json:\"exchange\"`\n                Key          string `json:\"key\"`\n                DeliveryMode uint8  `json:\"deliverymode\"`\n                Priority     uint8  `json:\"priority\"`\n                Body         string `json:\"body\"`\n        }\n\n        type ExchangeEntity struct {\n                Name       string `json:\"name\"`\n                Type       string `json:\"type\"`\n                Durable    bool   `json:\"durable\"`\n                AutoDelete bool   `json:\"autodelete\"`\n                NoWait     bool   `json:\"nowait\"`\n        }\n\n        type QueueEntity struct {\n                Name       string `json:\"name\"`\n                Durable    bool   `json:\"durable\"`\n                AutoDelete bool   `json:\"autodelete\"`\n                Exclusive  bool   `json:\"exclusive\"`\n                NoWait     bool   `json:\"nowait\"`\n        }\n\n        type QueueBindEntity struct {\n                Queue    string   `json:\"queue\"`\n                Exchange string   `json:\"exchange\"`\n                NoWait   bool     `json:\"nowait\"`\n                Keys     []string `json:\"keys\"` // bind/routing keys\n        }\n\n        // RabbitMQ Operate Wrapper\n        type RabbitMQ struct {\n                conn    *amqp.Connection\n                channel *amqp.Channel\n                done    chan error\n        }\n\n        func (r *RabbitMQ) Connect() (err error) {\n                r.conn, err = amqp.Dial(*amqpUri)\n                if err != nil {\n                        log.Printf(\"[amqp] connect error: %s\\n\", err)\n                        return err\n                }\n                r.channel, err = r.conn.Channel()\n                if err != nil {\n                        log.Printf(\"[amqp] get channel error: %s\\n\", err)\n                        return err\n                }\n                r.done = make(chan error)\n                return nil\n        }\n\n        func (r *RabbitMQ) Publish(exchange, key string, deliverymode, priority uint8, body string) (err error) {\n                err = r.channel.Publish(exchange, key, false, false,\n                        amqp.Publishing{\n                                Headers:         amqp.Table{},\n                                ContentType:     \"text/plain\",\n                                ContentEncoding: \"\",\n                                DeliveryMode:    deliverymode,\n                                Priority:        priority,\n                                Body:            []byte(body),\n                        },\n                )\n                if err != nil {\n                        log.Printf(\"[amqp] publish message error: %s\\n\", err)\n                        return err\n                }\n                return nil\n        }\n\n        func (r *RabbitMQ) DeclareExchange(name, typ string, durable, autodelete, nowait bool) (err error) {\n                err = r.channel.ExchangeDeclare(name, typ, durable, autodelete, false, nowait, nil)\n                if err != nil {\n                        log.Printf(\"[amqp] declare exchange error: %s\\n\", err)\n                        return err\n                }\n                return nil\n        }\n\n        func (r *RabbitMQ) DeleteExchange(name string) (err error) {\n                err = r.channel.ExchangeDelete(name, false, false)\n                if err != nil {\n                        log.Printf(\"[amqp] delete exchange error: %s\\n\", err)\n                        return err\n                }\n                return nil\n        }\n\n        func (r *RabbitMQ) DeclareQueue(name string, durable, autodelete, exclusive, nowait bool) (err error) {\n                _, err = r.channel.QueueDeclare(name, durable, autodelete, exclusive, nowait, nil)\n                if err != nil {\n                        log.Printf(\"[amqp] declare queue error: %s\\n\", err)\n                        return err\n                }\n                return nil\n        }\n\n        func (r *RabbitMQ) DeleteQueue(name string) (err error) {\n                // TODO: other property wrapper\n                _, err = r.channel.QueueDelete(name, false, false, false)\n                if err != nil {\n                        log.Printf(\"[amqp] delete queue error: %s\\n\", err)\n                        return err\n                }\n                return nil\n        }\n\n        func (r *RabbitMQ) BindQueue(queue, exchange string, keys []string, nowait bool) (err error) {\n                for _, key := range keys {\n                        if err = r.channel.QueueBind(queue, key, exchange, nowait, nil); err != nil {\n                                log.Printf(\"[amqp] bind queue error: %s\\n\", err)\n                                return err\n                        }\n                }\n                return nil\n        }\n\n        func (r *RabbitMQ) UnBindQueue(queue, exchange string, keys []string) (err error) {\n                for _, key := range keys {\n                        if err = r.channel.QueueUnbind(queue, key, exchange, nil); err != nil {\n                                log.Printf(\"[amqp] unbind queue error: %s\\n\", err)\n                                return err\n                        }\n                }\n                return nil\n        }\n\n        func (r *RabbitMQ) ConsumeQueue(queue string, message chan []byte) (err error) {\n                deliveries, err := r.channel.Consume(queue, \"\", true, false, false, false, nil)\n                if err != nil {\n                        log.Printf(\"[amqp] consume queue error: %s\\n\", err)\n                        return err\n                }\n                go func(deliveries \u003c-chan amqp.Delivery, done chan error, message chan []byte) {\n                        for d := range deliveries {\n                                message \u003c- d.Body\n                        }\n                        done \u003c- nil\n                }(deliveries, r.done, message)\n                return nil\n        }\n\n        func (r *RabbitMQ) Close() (err error) {\n                err = r.conn.Close()\n                if err != nil {\n                        log.Printf(\"[amqp] close error: %s\\n\", err)\n                        return err\n                }\n                return nil\n        }\n\n        // HTTP Handlers\n        func (m *MqController) QueueHandler(w http.ResponseWriter, r *http.Request) {\n                if r.Method == \"POST\" || r.Method == \"DELETE\" {\n                        if r.Body == nil {\n                                fmt.Println(\"missing form body\")\n                                return\n                        }\n\n                        body, err := ioutil.ReadAll(r.Body)\n                        if err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n\n                        entity := new(QueueEntity)\n                        if err = json.Unmarshal(body, entity); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n\n                        rabbit := new(RabbitMQ)\n                        if err = rabbit.Connect(); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n                        defer rabbit.Close()\n\n                        if r.Method == \"POST\" {\n                                if err = rabbit.DeclareQueue(entity.Name, entity.Durable, entity.AutoDelete, entity.Exclusive, entity.NoWait); err != nil {\n                                        http.Error(w, err.Error(), http.StatusInternalServerError)\n                                        return\n                                }\n                                w.Write([]byte(\"declare queue ok\"))\n                        } else if r.Method == \"DELETE\" {\n                                if err = rabbit.DeleteQueue(entity.Name); err != nil {\n                                        http.Error(w, err.Error(), http.StatusInternalServerError)\n                                        return\n                                }\n                                w.Write([]byte(\"delete queue ok\"))\n                        }\n                } else if r.Method == \"GET\" {\n                        r.ParseForm()\n                        rabbit := new(RabbitMQ)\n                        if err := rabbit.Connect(); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n                        defer rabbit.Close()\n\n                        message := make(chan []byte)\n\n                        for _, name := range r.Form[\"name\"] {\n                                if err := rabbit.ConsumeQueue(name, message); err != nil {\n                                        fmt.Println(\"Receive message \", message)\n                                        http.Error(w, err.Error(), http.StatusInternalServerError)\n                                        return\n                                }\n                        }\n\n                        w.Write([]byte(\"\"))\n                        w.(http.Flusher).Flush()\n\n                        for {\n                                fmt.Fprintf(w, \"%s\\n\", \u003c-message)\n                                w.(http.Flusher).Flush()\n                        }\n                } else {\n                        w.WriteHeader(http.StatusMethodNotAllowed)\n                }\n        }\n\n        func (m *MqController) QueueBindHandler(w http.ResponseWriter, r *http.Request) {\n                if r.Method == \"POST\" || r.Method == \"DELETE\" {\n                        body, err := ioutil.ReadAll(r.Body)\n                        if err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n\n                        entity := new(QueueBindEntity)\n                        if err = json.Unmarshal(body, entity); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n\n                        rabbit := new(RabbitMQ)\n                        if err = rabbit.Connect(); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n                        defer rabbit.Close()\n\n                        if r.Method == \"POST\" {\n                                if err = rabbit.BindQueue(entity.Queue, entity.Exchange, entity.Keys, entity.NoWait); err != nil {\n                                        http.Error(w, err.Error(), http.StatusInternalServerError)\n                                        return\n                                }\n                                w.Write([]byte(\"bind queue ok\"))\n                        } else if r.Method == \"DELETE\" {\n                                if err = rabbit.UnBindQueue(entity.Queue, entity.Exchange, entity.Keys); err != nil {\n                                        http.Error(w, err.Error(), http.StatusInternalServerError)\n                                        return\n                                }\n                                w.Write([]byte(\"unbind queue ok\"))\n                        }\n                } else {\n                        w.WriteHeader(http.StatusMethodNotAllowed)\n                }\n        }\n\n        func (m *MqController) PublishHandler(w http.ResponseWriter, r *http.Request) {\n                if r.Method == \"POST\" {\n                        body, err := ioutil.ReadAll(r.Body)\n                        if err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n\n                        entity := new(MessageEntity)\n                        if err = json.Unmarshal(body, entity); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n\n                        rabbit := new(RabbitMQ)\n                        if err = rabbit.Connect(); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n                        defer rabbit.Close()\n\n                        if err = rabbit.Publish(entity.Exchange, entity.Key, entity.DeliveryMode, entity.Priority, entity.Body); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n                        w.Write([]byte(\"publish message ok\"))\n                } else {\n                        w.WriteHeader(http.StatusMethodNotAllowed)\n                }\n        }\n\n        func (m *MqController) ExchangeHandler(w http.ResponseWriter, r *http.Request) {\n                if r.Method == \"POST\" || r.Method == \"DELETE\" {\n                        body, err := ioutil.ReadAll(r.Body)\n                        if err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n\n                        entity := new(ExchangeEntity)\n                        if err = json.Unmarshal(body, entity); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n\n                        rabbit := new(RabbitMQ)\n                        if err = rabbit.Connect(); err != nil {\n                                http.Error(w, err.Error(), http.StatusInternalServerError)\n                                return\n                        }\n                        defer rabbit.Close()\n\n                        if r.Method == \"POST\" {\n                                if err = rabbit.DeclareExchange(entity.Name, entity.Type, entity.Durable, entity.AutoDelete, entity.NoWait); err != nil {\n                                        http.Error(w, err.Error(), http.StatusInternalServerError)\n                                        return\n                                }\n                                w.Write([]byte(\"declare exchange ok\"))\n                        } else if r.Method == \"DELETE\" {\n                                if err = rabbit.DeleteExchange(entity.Name); err != nil {\n                                        http.Error(w, err.Error(), http.StatusInternalServerError)\n                                        return\n                                }\n                                w.Write([]byte(\"delete exchange ok\"))\n                        }\n                } else {\n                        w.WriteHeader(http.StatusMethodNotAllowed)\n                }\n        }\n\n```\n\n#### 声明queue，注意：你的request格式必须是 Content-Type:application/json\n\n        http://127.0.0.1:7777/queue POST\n\n        {\n                \"name\":\"test\",\n                \"durable\":false,\n                \"autodelete\":true,\n                \"exclusive\":false,\n                \"nowait\":false\n        }\n\n#### 声明exchange,注意：你的request格式必须是 Content-Type:application/json\n\n        http://127.0.0.1:7777/exchange POST\n\n       {\n                \"name\":\"test\",\n                \"type\":\"direct\",\n                \"durable\":false,\n                \"autodelete\":true,\n                \"nowait\":false\n        }\n\n#### 绑定queue，注意：你的request格式必须是 Content-Type:application/json\n\n        http://127.0.0.1:7777/queue/bind POST\n\n        {\n                \"queue\":\"test\",\n                \"exchange\":\"test\",\n                \"nowait\":false,\n                \"keys\": [\"router\"]\n        }\n\n#### pusblish messge,注意：你的request格式必须是 Content-Type:application/json\n\n        http://127.0.0.1:7777/publish POST\n\n        {\n                \"exchange\":\"test\",\n                \"key\":\"router\",\n                \"deliverymode\":2,  //1:不用持久化，2:消息持久化\n                \"priority\":3,  //优先级 （一般情况下1-10之间）\n                \"body\":\"this is a message from test.\"\n        }\n\n\n\n#### 消费queue\n\n        http://127.0.0.1:7777/queue?name=test   GET\n\n\n\n\n\n## 如果你使用的是MacOS,那么Mac下编译Linux, Windows平台的64位可执行程序如下：\n\n\n#### 编译Linux服务器可执行文件：\n        CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o go_init main.go\n\n#### 编译Windows服务器可执行文件：\n        CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o go_init main.go\n\n\n\n## 如果你使用的是Linux系统，那么Linux下编译Mac, Windows平台的64位可执行程序如下：\n\n#### 编译MacOS可执行文件：\n        CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o go_init main.go\n\n#### 编译windows下可执行文件：\n        CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o go_init main.go\n\n\n\n## 如果你使用的是Windows系统，那么Windows下编译Mac, Linux平台的64位可执行程序如下：\n\n#### 编译MacOS可执行文件如下：\n\n        SET CGO_ENABLED=0\n\n        SET GOOS=darwin\n\n        SET GOARCH=amd64\n\n        go build -o go_init main.go\n\n#### 编译Windows可执行文件如下：\n\n        SET CGO_ENABLED=0\n\n        SET GOOS=linux\n\n        SET GOARCH=amd64\n\n        go build -o go_init main.go\n\n\n\n## Nginx负载均衡\n\n\n```\n\n        user nginx;\n        worker_processes auto;\n        error_log /var/log/nginx/error.log;\n        pid /var/run/nginx.pid;\n\n        events {\n        worker_connections 1024;\n        }\n\n        http {\n        log_format  main  '$remote_addr - $remote_user [$time_local] \"$request\" '\n                        '$status $body_bytes_sent \"$http_referer\" '\n                        '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n        \n        access_log  /var/log/nginx/access.log  main;\n        \n        sendfile            on;\n        tcp_nopush          on;\n        tcp_nodelay         on;\n        keepalive_timeout   65;\n        types_hash_max_size 2048;\n        \n        include             /etc/nginx/mime.types;\n        default_type        application/octet-stream;\n                \n        index   index.html index.htm;\n        \n        upstream docker_nginx {\n                ip_hash; #同一个ip一定时间内负载到一台机器\n                server 172.31.0.155:8081;\n                server 172.31.0.155:8082;\n                server 172.31.0.155:8083;\n                server 172.31.0.155:8084;\n        }\n        \n        server {\n                # 使用openssl自建的rsa证书\n                ssl_certificate /opt/ssl/nginx.unclepang.com.crt;\n                ssl_certificate_key /opt/ssl/nginx.unclepang.com.key;\n                ssl_session_timeout 5m;\n                ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;\n                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n                ssl_prefer_server_ciphers on;\n        \n                listen 443;\n                ssl on;\n                server_name www.unclepang.com;\n                \n                location / {\n                        # 代理到真实机器，如果真实机器也安装了https则使用https\n                        # 一般代理集群对流量进行了https后，真实机器可不再使用https\n                        proxy_pass http://docker_nginx;\n                }\n        }\n        }\n\n```\n","funding_links":[],"categories":["Framework based on gin"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxiaobopang%2Fgo_init","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxiaobopang%2Fgo_init","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxiaobopang%2Fgo_init/lists"}