zrufo 4 years ago
commit
aea3d57492

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+
+.idea
+*.log
+go.sum

+ 33 - 0
controller/auth.go

@@ -0,0 +1,33 @@
+package controller
+
+import (
+	"github.com/sirupsen/logrus"
+	"net/http"
+)
+
+type Auth struct {
+	BaseController
+}
+
+// SignUp godoc
+// @Summary 用户添加
+// @tags Auth
+// @Description 用户添加
+// @Accept  x-www-form-urlencoded
+// @Produce  json
+// @Param userCode formData string true "用户名"
+// @Param password formData string true "密码"
+// @Param email formData string false "邮箱"
+// @Param phone formData string false "手机号"
+// @Param name formData string false "姓名"
+// @Success 200 {object} controller.ResponseBase
+// @Router /Auth/SignUp [post]
+func (a *Auth) HttpPostSignUp() (err error) {
+	userCode := a.Ctx().PostForm("userCode")
+	test := a.PostFromInt("test")
+	test2 := a.PostFromIntPtr("test2")
+	logrus.Info(userCode, test, test2)
+
+	a.Ctx().JSON(http.StatusOK, newResponseBase())
+	return
+}

+ 40 - 0
controller/base.go

@@ -0,0 +1,40 @@
+/*
+@Time : 2019-06-26 9:31
+@Author : zr
+@Software: GoLand
+*/
+package controller
+
+import (
+	"gframe/errors"
+	"gframe/model"
+	"gitee.com/zr233/bsf"
+)
+
+type Controller interface {
+}
+type BaseController struct {
+	*bsf.ControllerBase
+}
+
+type ResponseBase struct {
+	Code errors.ErrorCode
+	Memo string
+}
+
+func newResponseBase() ResponseBase {
+	return ResponseBase{
+		Code: errors.CodeSUCCESS,
+		Memo: "执行成功",
+	}
+}
+
+func (b BaseController) getSession() *model.Session {
+	if s, ok := b.Ctx().Get("session"); ok {
+		s, ok := s.(*model.Session)
+		if ok {
+			return s
+		}
+	}
+	return nil
+}

+ 202 - 0
docs/docs.go

@@ -0,0 +1,202 @@
+// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// This file was generated by swaggo/swag at
+// 2021-01-08 16:28:24.8381164 +0800 CST m=+0.073999901
+
+package docs
+
+import (
+	"bytes"
+	"encoding/json"
+	"strings"
+
+	"github.com/alecthomas/template"
+	"github.com/swaggo/swag"
+)
+
+var doc = `{
+    "schemes": {{ marshal .Schemes }},
+    "swagger": "2.0",
+    "info": {
+        "description": "{{.Description}}",
+        "title": "{{.Title}}",
+        "termsOfService": "http://swagger.io/terms/",
+        "contact": {
+            "name": "API Support",
+            "url": "http://www.swagger.io/support",
+            "email": "support@swagger.io"
+        },
+        "license": {
+            "name": "Apache 2.0",
+            "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+        },
+        "version": "{{.Version}}"
+    },
+    "host": "{{.Host}}",
+    "basePath": "{{.BasePath}}",
+    "paths": {
+        "/Auth/SignUp": {
+            "post": {
+                "description": "用户添加",
+                "consumes": [
+                    "application/x-www-form-urlencoded"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "Auth"
+                ],
+                "summary": "用户添加",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "用户名",
+                        "name": "userCode",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "密码",
+                        "name": "password",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "邮箱",
+                        "name": "email",
+                        "in": "formData"
+                    },
+                    {
+                        "type": "string",
+                        "description": "手机号",
+                        "name": "phone",
+                        "in": "formData"
+                    },
+                    {
+                        "type": "string",
+                        "description": "姓名",
+                        "name": "name",
+                        "in": "formData"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/controller.ResponseBase"
+                        }
+                    }
+                }
+            }
+        }
+    },
+    "definitions": {
+        "controller.ResponseBase": {
+            "type": "object",
+            "properties": {
+                "code": {
+                    "type": "integer"
+                },
+                "memo": {
+                    "type": "string"
+                }
+            }
+        }
+    },
+    "securityDefinitions": {
+        "ApiKeyAuth": {
+            "type": "apiKey",
+            "name": "Authorization",
+            "in": "header"
+        },
+        "BasicAuth": {
+            "type": "basic"
+        },
+        "OAuth2AccessCode": {
+            "type": "oauth2",
+            "flow": "accessCode",
+            "authorizationUrl": "https://example.com/oauth/authorize",
+            "tokenUrl": "https://example.com/oauth/token",
+            "scopes": {
+                "admin": " Grants read and write access to administrative information"
+            }
+        },
+        "OAuth2Application": {
+            "type": "oauth2",
+            "flow": "application",
+            "tokenUrl": "https://example.com/oauth/token",
+            "scopes": {
+                "admin": " Grants read and write access to administrative information",
+                "write": " Grants write access"
+            }
+        },
+        "OAuth2Implicit": {
+            "type": "oauth2",
+            "flow": "implicit",
+            "authorizationUrl": "https://example.com/oauth/authorize",
+            "scopes": {
+                "admin": " Grants read and write access to administrative information",
+                "write": " Grants write access"
+            }
+        },
+        "OAuth2Password": {
+            "type": "oauth2",
+            "flow": "password",
+            "tokenUrl": "https://example.com/oauth/token",
+            "scopes": {
+                "admin": " Grants read and write access to administrative information",
+                "read": " Grants read access",
+                "write": " Grants write access"
+            }
+        }
+    }
+}`
+
+type swaggerInfo struct {
+	Version     string
+	Host        string
+	BasePath    string
+	Schemes     []string
+	Title       string
+	Description string
+}
+
+// SwaggerInfo holds exported Swagger Info so clients can modify it
+var SwaggerInfo = swaggerInfo{
+	Version:     "1.0",
+	Host:        "",
+	BasePath:    "/v1",
+	Schemes:     []string{},
+	Title:       "web框架",
+	Description: "web框架 API 文档",
+}
+
+type s struct{}
+
+func (s *s) ReadDoc() string {
+	sInfo := SwaggerInfo
+	sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
+
+	t, err := template.New("swagger_info").Funcs(template.FuncMap{
+		"marshal": func(v interface{}) string {
+			a, _ := json.Marshal(v)
+			return string(a)
+		},
+	}).Parse(doc)
+	if err != nil {
+		return doc
+	}
+
+	var tpl bytes.Buffer
+	if err := t.Execute(&tpl, sInfo); err != nil {
+		return doc
+	}
+
+	return tpl.String()
+}
+
+func init() {
+	swag.Register(swag.Name, &s{})
+}

+ 138 - 0
docs/swagger.json

@@ -0,0 +1,138 @@
+{
+    "swagger": "2.0",
+    "info": {
+        "description": "web框架 API 文档",
+        "title": "web框架",
+        "termsOfService": "http://swagger.io/terms/",
+        "contact": {
+            "name": "API Support",
+            "url": "http://www.swagger.io/support",
+            "email": "support@swagger.io"
+        },
+        "license": {
+            "name": "Apache 2.0",
+            "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+        },
+        "version": "1.0"
+    },
+    "basePath": "/v1",
+    "paths": {
+        "/Auth/SignUp": {
+            "post": {
+                "description": "用户添加",
+                "consumes": [
+                    "application/x-www-form-urlencoded"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "Auth"
+                ],
+                "summary": "用户添加",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "用户名",
+                        "name": "userCode",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "密码",
+                        "name": "password",
+                        "in": "formData",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "邮箱",
+                        "name": "email",
+                        "in": "formData"
+                    },
+                    {
+                        "type": "string",
+                        "description": "手机号",
+                        "name": "phone",
+                        "in": "formData"
+                    },
+                    {
+                        "type": "string",
+                        "description": "姓名",
+                        "name": "name",
+                        "in": "formData"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/controller.ResponseBase"
+                        }
+                    }
+                }
+            }
+        }
+    },
+    "definitions": {
+        "controller.ResponseBase": {
+            "type": "object",
+            "properties": {
+                "code": {
+                    "type": "integer"
+                },
+                "memo": {
+                    "type": "string"
+                }
+            }
+        }
+    },
+    "securityDefinitions": {
+        "ApiKeyAuth": {
+            "type": "apiKey",
+            "name": "Authorization",
+            "in": "header"
+        },
+        "BasicAuth": {
+            "type": "basic"
+        },
+        "OAuth2AccessCode": {
+            "type": "oauth2",
+            "flow": "accessCode",
+            "authorizationUrl": "https://example.com/oauth/authorize",
+            "tokenUrl": "https://example.com/oauth/token",
+            "scopes": {
+                "admin": " Grants read and write access to administrative information"
+            }
+        },
+        "OAuth2Application": {
+            "type": "oauth2",
+            "flow": "application",
+            "tokenUrl": "https://example.com/oauth/token",
+            "scopes": {
+                "admin": " Grants read and write access to administrative information",
+                "write": " Grants write access"
+            }
+        },
+        "OAuth2Implicit": {
+            "type": "oauth2",
+            "flow": "implicit",
+            "authorizationUrl": "https://example.com/oauth/authorize",
+            "scopes": {
+                "admin": " Grants read and write access to administrative information",
+                "write": " Grants write access"
+            }
+        },
+        "OAuth2Password": {
+            "type": "oauth2",
+            "flow": "password",
+            "tokenUrl": "https://example.com/oauth/token",
+            "scopes": {
+                "admin": " Grants read and write access to administrative information",
+                "read": " Grants read access",
+                "write": " Grants write access"
+            }
+        }
+    }
+}

+ 97 - 0
docs/swagger.yaml

@@ -0,0 +1,97 @@
+basePath: /v1
+definitions:
+  controller.ResponseBase:
+    properties:
+      code:
+        type: integer
+      memo:
+        type: string
+    type: object
+info:
+  contact:
+    email: support@swagger.io
+    name: API Support
+    url: http://www.swagger.io/support
+  description: web框架 API 文档
+  license:
+    name: Apache 2.0
+    url: http://www.apache.org/licenses/LICENSE-2.0.html
+  termsOfService: http://swagger.io/terms/
+  title: web框架
+  version: "1.0"
+paths:
+  /Auth/SignUp:
+    post:
+      consumes:
+      - application/x-www-form-urlencoded
+      description: 用户添加
+      parameters:
+      - description: 用户名
+        in: formData
+        name: userCode
+        required: true
+        type: string
+      - description: 密码
+        in: formData
+        name: password
+        required: true
+        type: string
+      - description: 邮箱
+        in: formData
+        name: email
+        type: string
+      - description: 手机号
+        in: formData
+        name: phone
+        type: string
+      - description: 姓名
+        in: formData
+        name: name
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/controller.ResponseBase'
+      summary: 用户添加
+      tags:
+      - Auth
+securityDefinitions:
+  ApiKeyAuth:
+    in: header
+    name: Authorization
+    type: apiKey
+  BasicAuth:
+    type: basic
+  OAuth2AccessCode:
+    authorizationUrl: https://example.com/oauth/authorize
+    flow: accessCode
+    scopes:
+      admin: ' Grants read and write access to administrative information'
+    tokenUrl: https://example.com/oauth/token
+    type: oauth2
+  OAuth2Application:
+    flow: application
+    scopes:
+      admin: ' Grants read and write access to administrative information'
+      write: ' Grants write access'
+    tokenUrl: https://example.com/oauth/token
+    type: oauth2
+  OAuth2Implicit:
+    authorizationUrl: https://example.com/oauth/authorize
+    flow: implicit
+    scopes:
+      admin: ' Grants read and write access to administrative information'
+      write: ' Grants write access'
+    type: oauth2
+  OAuth2Password:
+    flow: password
+    scopes:
+      admin: ' Grants read and write access to administrative information'
+      read: ' Grants read access'
+      write: ' Grants write access'
+    tokenUrl: https://example.com/oauth/token
+    type: oauth2
+swagger: "2.0"

+ 54 - 0
errors/error.go

@@ -0,0 +1,54 @@
+/*
+@Time : 2019-06-26 16:21
+@Author : zr
+@File : error
+@Software: GoLand
+*/
+package errors
+
+import (
+	"fmt"
+	"gitee.com/zr233/bsf/errors"
+)
+
+type ErrorCode int
+
+const (
+	CodeUNKNOWN                       = ErrorCode(errors.ErrorCode_Unknown)
+	CodeSUCCESS             ErrorCode = 0
+	CodeBusy                ErrorCode = 1
+	CodeServiceNotAvailable ErrorCode = 2
+	CodeKeyNotExist         ErrorCode = 3
+	CodePermissionDenied    ErrorCode = 1004
+	CodePasswordErr         ErrorCode = 1006
+	CodeTokenErr            ErrorCode = 1010
+	CodeNoRecord            ErrorCode = 1014
+	CodeDATABASE            ErrorCode = 9000
+	CodeREDIS               ErrorCode = 10000
+	CodeParam                         = ErrorCode(errors.CodeParam)
+)
+
+func (e ErrorCode) ShowMsg() string {
+	switch e {
+	case CodeSUCCESS:
+		return "执行成功"
+	case CodePasswordErr:
+		return "密码错误"
+	case CodeTokenErr:
+		return "登录失效"
+	default:
+		return fmt.Sprintf("系统错误[%d],请联系管理员", e)
+	}
+}
+
+func NewParamErr(err error) error {
+	return errors.NewParamErr(err)
+}
+
+func FromError(err error) (stdErr *errors.StandardError) {
+	return errors.NewFromError(err, errors.ErrorCode(CodeUNKNOWN))
+}
+
+func NewFromError(err error, code ErrorCode) (stdErr *errors.StandardError) {
+	return errors.NewFromError(err, errors.ErrorCode(code))
+}

+ 40 - 0
global/global.go

@@ -0,0 +1,40 @@
+package global
+
+import (
+	"github.com/ZR233/gconfig/v2"
+	"github.com/hashicorp/consul/api"
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/viper"
+	"path"
+)
+
+const (
+	envName_CONSUL_ADDR = "CONSUL_ADDR"
+)
+
+func Init() (db gconfig.DB) {
+	err := viper.BindEnv(envName_CONSUL_ADDR)
+	if err != nil {
+		panic(err)
+	}
+
+	var consulCfg *api.Config
+	consulAddr := viper.GetString(envName_CONSUL_ADDR)
+	if consulAddr != "" {
+		ConsulAddr = consulAddr
+
+		consulCfg = &api.Config{
+			Address: ConsulAddr,
+		}
+		logrus.Info("consul addr: %s", ConsulAddr)
+	}
+
+	Config = gconfig.NewConfig(path.Join(ProjectName, AppName)).UseConsul(consulCfg)
+	err = Config.Unmarshal(&Project)
+	if err != nil {
+		panic(err)
+	}
+	logrus.Info("config finish")
+
+	return
+}

+ 21 - 0
global/init.go

@@ -0,0 +1,21 @@
+package global
+
+import "github.com/ZR233/gconfig/v2"
+
+const (
+	ProjectName = "gframe"
+	AppName     = "api_server"
+	Port        = 58080
+)
+
+var (
+	ConsulAddr string
+	Config     *gconfig.Config
+
+	Project struct {
+		DBName   string
+		LogLevel string
+		Host     string
+		Debug    bool
+	}
+)

+ 22 - 0
go.mod

@@ -0,0 +1,22 @@
+module gframe
+
+go 1.15
+
+require (
+	gitee.com/zr233/bsf v1.2.3
+	github.com/ZR233/gconfig/v2 v2.0.4
+	github.com/ZR233/glog v0.0.7
+	github.com/ZR233/goutils v1.4.12
+	github.com/ZR233/session v1.1.5
+	github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
+	github.com/gin-gonic/gin v1.6.3
+	github.com/go-redis/redis v6.15.9+incompatible // indirect
+	github.com/go-redis/redis/v7 v7.2.0
+	github.com/hashicorp/consul/api v1.8.1
+	github.com/jackc/pgconn v1.8.0
+	github.com/jackc/pgx/v4 v4.10.1
+	github.com/sirupsen/logrus v1.7.0
+	github.com/spf13/viper v1.7.1
+	github.com/swaggo/gin-swagger v1.3.0
+	github.com/swaggo/swag v1.7.0
+)

+ 39 - 0
lib/session/session.go

@@ -0,0 +1,39 @@
+/*
+@Time : 2019-08-21 11:19
+@Author : zr
+*/
+package session
+
+import (
+	"gframe/global"
+	"github.com/ZR233/session"
+	"github.com/go-redis/redis/v7"
+	"sync"
+)
+
+var sessionManager *session.Manager
+var once sync.Once
+
+func newSM() {
+
+	cfg, err := global.Config.GetRedis()
+	if err != nil {
+		panic(err)
+	}
+
+	opt := &redis.UniversalOptions{
+		Addrs:      cfg.Addrs,
+		Password:   cfg.Password,
+		MasterName: cfg.Mastername,
+	}
+
+	db := session.NewRedisAdapter(opt, global.AppName)
+
+	sessionManager = session.NewManager(db)
+}
+
+func GetSessionManager() *session.Manager {
+	once.Do(newSM)
+
+	return sessionManager
+}

+ 32 - 0
logger/init.go

@@ -0,0 +1,32 @@
+package logger
+
+import (
+	"gframe/global"
+	"github.com/ZR233/glog"
+	"github.com/sirupsen/logrus"
+)
+
+var processor *glog.Processor
+
+func Init() {
+	processor = glog.NewProcessor(global.ProjectName, global.AppName)
+
+}
+func SetOnlineWriters() {
+	level, err := logrus.ParseLevel(global.Project.LogLevel)
+	if err != nil {
+		panic(err)
+	}
+	logrus.SetLevel(level)
+
+	writer := glog.NewWriterConfigLogstash()
+	zk, err := global.Config.GetZookeeper()
+	if err != nil {
+		panic(err)
+	}
+
+	writer.ZkHosts = zk.Hosts
+	processor.AddWriters(writer)
+
+	return
+}

+ 109 - 0
main.go

@@ -0,0 +1,109 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"gframe/controller"
+	"gframe/docs"
+	"gframe/global"
+	"gframe/logger"
+	"gframe/middleware"
+	"gframe/repository/postgres"
+	"gitee.com/zr233/bsf"
+	"github.com/gin-gonic/gin"
+	"github.com/sirupsen/logrus"
+	ginSwagger "github.com/swaggo/gin-swagger"
+	"github.com/swaggo/gin-swagger/swaggerFiles"
+	"os"
+)
+
+var _VERSION_ = "unknown"
+
+func flagInit() {
+
+	flag.BoolVar(&global.Project.Debug, "d", global.Project.Debug, "是否debug")
+	flag.StringVar(&global.Project.Host, "s", global.Project.Host, "swag host")
+	flag.BoolVar(&help, "h", false, "this help")
+
+	flag.Parse()
+	if help {
+		flag.Usage()
+		os.Exit(0)
+	}
+}
+
+// @title web框架
+// @version 1.0
+// @description web框架 API 文档
+// @termsOfService http://swagger.io/terms/
+
+// @contact.name API Support
+// @contact.url http://www.swagger.io/support
+// @contact.email support@swagger.io
+
+// @license.name Apache 2.0
+// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
+
+// @BasePath /v1
+
+// @securityDefinitions.basic BasicAuth
+
+// @securityDefinitions.apikey ApiKeyAuth
+// @in header
+// @name Authorization
+
+// @securitydefinitions.oauth2.application OAuth2Application
+// @tokenUrl https://example.com/oauth/token
+// @scope.write Grants write access
+// @scope.admin Grants read and write access to administrative information
+
+// @securitydefinitions.oauth2.implicit OAuth2Implicit
+// @authorizationurl https://example.com/oauth/authorize
+// @scope.write Grants write access
+// @scope.admin Grants read and write access to administrative information
+
+// @securitydefinitions.oauth2.password OAuth2Password
+// @tokenUrl https://example.com/oauth/token
+// @scope.read Grants read access
+// @scope.write Grants write access
+// @scope.admin Grants read and write access to administrative information
+
+// @securitydefinitions.oauth2.accessCode OAuth2AccessCode
+// @tokenUrl https://example.com/oauth/token
+// @authorizationurl https://example.com/oauth/authorize
+// @scope.admin Grants read and write access to administrative information
+func main() {
+	logger.Init()
+	global.Init()
+	logger.SetOnlineWriters()
+	flagInit()
+	postgres.Init()
+
+	r := bsf.NewDefaultEngine()
+	gin.SetMode(gin.ReleaseMode)
+	r.Use(
+		middleware.ErrorResponse(),
+		middleware.Logger(),
+		middleware.Session(),
+	)
+	r.AutoRegisterController("/v1", &controller.Auth{})
+
+	//debug模式下启用swag文档
+	if global.Project.Debug {
+		gin.SetMode(gin.DebugMode)
+		//设置swagger文档主机
+		docs.SwaggerInfo.Host = fmt.Sprintf("%s:%d", global.Project.Host, global.Port)
+		// 注册swagger文档
+		// 查看地址为 /v1/docs/index.html     /v1/SignIn/docs/doc.json
+		r.GET("/v1/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
+	}
+
+	logrus.Infof("Version:[%s]\n", _VERSION_)
+
+	_ = r.Run(fmt.Sprintf(":%d", global.Port))
+
+}
+
+var (
+	help bool
+)

+ 20 - 0
middleware/base.go

@@ -0,0 +1,20 @@
+/*
+@Time : 2019-07-15 14:32
+@Author : zr
+*/
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+)
+
+type base struct {
+	c *gin.Context
+}
+
+func newBase(c *gin.Context) base {
+	b := base{
+		c,
+	}
+	return b
+}

+ 75 - 0
middleware/logger.go

@@ -0,0 +1,75 @@
+/*
+@Time : 2019-06-28 17:48
+@Author : zr
+@File : logger
+@Software: GoLand
+*/
+package middleware
+
+import (
+	"encoding/json"
+	"gframe/errors"
+	"gframe/model"
+	"github.com/ZR233/goutils/stackx"
+	"github.com/gin-gonic/gin"
+	"github.com/sirupsen/logrus"
+	"time"
+)
+
+func Logger() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		beginTime := time.Now()
+
+		defer func() {
+			code := 0
+			logMsg := "success"
+
+			if p := recover(); p != nil {
+				err := p.(error)
+
+				stdErr := errors.FromError(err)
+				logMsg = stdErr.Error() + "\n" + string(stackx.Stack(0))
+
+				code = int(stdErr.Code)
+				_ = c.Error(err)
+			}
+
+			userid := 0
+			src := ""
+
+			endTime := time.Now()
+
+			if i, exists := c.Get("session"); exists {
+				s, ok := i.(*model.Session)
+				if ok {
+					if s != nil {
+						userid = s.UserId
+						src = s.Channel
+					}
+				}
+			}
+
+			postForm := c.Request.PostForm
+			params, _ := json.Marshal(postForm)
+			url := c.Request.URL.Path
+
+			event := logrus.WithFields(logrus.Fields{
+				"execTime":  endTime.Sub(beginTime).Milliseconds(),
+				"trace":     url,
+				"optUserId": userid,
+				"src":       src,
+				"code":      code,
+				"params":    string(params),
+			})
+			event.Time = beginTime
+			if len(c.Errors) > 0 {
+				event.Warn(logMsg)
+			} else {
+				event.Info(logMsg)
+			}
+
+		}()
+
+		c.Next()
+	}
+}

+ 48 - 0
middleware/response.go

@@ -0,0 +1,48 @@
+/*
+@Time : 2019-11-07 14:55
+@Author : zr
+*/
+package middleware
+
+import (
+	"gframe/errors"
+	"gframe/global"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+type ResponseBase struct {
+	Code int
+	Memo string
+}
+
+func ErrorResponse() gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		defer func() {
+			if len(c.Errors) > 0 {
+				stdErr := errors.FromError(c.Errors[0].Err)
+				var resp interface{}
+
+				resp1 := &ResponseBase{
+					Code: int(stdErr.Code),
+					Memo: errors.ErrorCode(stdErr.Code).ShowMsg(),
+				}
+				resp = resp1
+				if global.Project.Debug {
+					var resp2 struct {
+						ResponseBase
+						DebugMsg string
+					}
+					resp2.ResponseBase = *resp1
+					resp2.DebugMsg = stdErr.Error()
+					resp = resp2
+				}
+				c.JSON(http.StatusOK, resp)
+			}
+
+		}()
+
+		c.Next()
+	}
+}

+ 36 - 0
middleware/session.go

@@ -0,0 +1,36 @@
+/*
+@Time : 2019-08-22 14:33
+@Author : zr
+*/
+package middleware
+
+import (
+	"gframe/lib/session"
+	"gframe/model"
+	"github.com/ZR233/session/serr"
+	"github.com/gin-gonic/gin"
+)
+
+func Session() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		token := c.PostForm("token")
+		if token == "" {
+			token = c.Param("token")
+		}
+
+		if token != "" {
+			sm := session.GetSessionManager()
+			sess, err := sm.FindByToken(token)
+			if err != nil {
+				if err != serr.TokenNotFound {
+					panic(err)
+				}
+			} else {
+				sess_ := model.NewSession(sess)
+				c.Set("session", sess_)
+			}
+		}
+
+		c.Next()
+	}
+}

+ 32 - 0
model/session.go

@@ -0,0 +1,32 @@
+/*
+@Time : 2019-07-12 16:24
+@Author : zr
+*/
+package model
+
+import (
+	model2 "github.com/ZR233/session/model"
+	"strconv"
+	"time"
+)
+
+type Session struct {
+	Token    string
+	UserId   int
+	Channel  string
+	ExpireAt time.Time
+}
+
+func NewSession(s *model2.Session) *Session {
+	userId, err := strconv.Atoi(s.UserId)
+	if err != nil {
+		panic(err)
+	}
+	s_ := &Session{
+		s.Token,
+		userId,
+		s.Channel,
+		s.ExpireAt,
+	}
+	return s_
+}

+ 9 - 0
model/user.go

@@ -0,0 +1,9 @@
+package model
+
+import "time"
+
+type User struct {
+	Id       int
+	Name     string
+	CreateAt time.Time
+}

+ 73 - 0
repository/postgres/init.go

@@ -0,0 +1,73 @@
+package postgres
+
+import (
+	"context"
+	e "errors"
+	"fmt"
+	"gframe/errors"
+	"gframe/global"
+	"github.com/jackc/pgconn"
+	"github.com/jackc/pgx/v4"
+	"github.com/jackc/pgx/v4/pgxpool"
+	"github.com/sirupsen/logrus"
+)
+
+var writeDB *pgxpool.Pool
+
+func Init() {
+	logrus.Info("初始化数据库")
+
+	dbCfg, err := global.Config.GetPostgreSQL()
+	if err != nil {
+		panic(err)
+	}
+	writeCfg := dbCfg.Write
+
+	connStr := fmt.Sprintf("host=%s port=%d user=%s dbname=%s password=%s sslmode=disable TimeZone=Asia/Shanghai",
+		writeCfg.Host, writeCfg.Port, writeCfg.User, global.Project.DBName, writeCfg.Password)
+	writeDB, err = pgxpool.Connect(context.Background(), connStr)
+	if err != nil {
+		logrus.Panicf("连接数据库失败:%v\n", err)
+		panic(err)
+	}
+}
+
+type base struct {
+	c context.Context
+}
+
+func (b base) ctx() context.Context {
+	if b.c == nil {
+		b.c = context.Background()
+	}
+	return b.c
+}
+
+func (b base) writeDB() *pgxpool.Pool {
+	return writeDB
+}
+
+func panicError(err error) {
+	if err != nil {
+		err = errors.NewFromError(err, errors.CodeDATABASE)
+		panic(err)
+	}
+}
+func panicExec(tag pgconn.CommandTag, err error) {
+	if err != nil {
+		if e.Is(err, pgx.ErrNoRows) {
+			err = errors.NewFromError(err, errors.CodeNoRecord)
+		} else {
+			err = errors.NewFromError(err, errors.CodeDATABASE)
+		}
+		panic(err)
+	}
+}
+func isRecordNotFound(err error) bool {
+	if e.Is(err, pgx.ErrNoRows) {
+		return true
+	} else {
+		panicError(err)
+		return false
+	}
+}

+ 17 - 0
repository/postgres/init_test.go

@@ -0,0 +1,17 @@
+package postgres
+
+import (
+	"gframe/global"
+	"gframe/logger"
+	"testing"
+)
+
+func testInit() {
+	logger.Init()
+	global.Init()
+	Init()
+}
+
+func TestInit(t *testing.T) {
+	testInit()
+}

+ 51 - 0
repository/postgres/user.go

@@ -0,0 +1,51 @@
+package postgres
+
+import (
+	"gframe/model"
+)
+
+type User struct {
+	base
+}
+
+func (u User) Create(user *model.User) {
+
+	sql := `insert into t_user (id, name, create_at) VALUES 
+($1, $2, $3)`
+
+	panicExec(u.writeDB().Exec(u.ctx(), sql,
+		user.Id, user.Name, user.CreateAt))
+}
+
+func (u User) ById(userId int) (user *model.User) {
+	user = &model.User{}
+
+	sql := `select id, name, create_at from t_user 
+    where id = $1 `
+
+	panicError(
+		u.writeDB().
+			QueryRow(u.ctx(), sql, userId).
+			Scan(&user.Id, &user.Name, &user.CreateAt))
+
+	return
+}
+
+func (u User) All() (users []*model.User) {
+
+	sql := `select id, name, create_at from t_user`
+
+	rows, err := u.writeDB().
+		Query(u.ctx(), sql)
+	panicError(err)
+	defer rows.Close()
+
+	for rows.Next() {
+		user := &model.User{}
+		err = rows.Scan(&user.Id, &user.Name, &user.CreateAt)
+		panicError(err)
+		users = append(users, user)
+	}
+
+	return
+}

+ 30 - 0
repository/postgres/user_test.go

@@ -0,0 +1,30 @@
+package postgres
+
+import (
+	"gframe/model"
+	"testing"
+	"time"
+)
+
+func TestUser_Create(t *testing.T) {
+	testInit()
+
+	User{}.Create(&model.User{
+		Id: 2, Name: "test", CreateAt: time.Now(),
+	})
+}
+
+func TestUser_ById(t *testing.T) {
+	testInit()
+
+	u := User{}.ById(1)
+	u = User{}.ById(2)
+
+	println(u)
+}
+
+func TestUser_All(t *testing.T) {
+	testInit()
+	l := User{}.All()
+	println(len(l))
+}