[ADD]项目初始化,包括gorm、gin、jwt以及swagger
This commit is contained in:
commit
ca47c25386
|
@ -0,0 +1,18 @@
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
||||||
|
conf/app.ini
|
||||||
|
.idea/*
|
||||||
|
main
|
|
@ -0,0 +1,10 @@
|
||||||
|
# game_demo
|
||||||
|
```bush
|
||||||
|
game_demo/
|
||||||
|
├── conf # 用于存储配置文件
|
||||||
|
├── middleware # 应用中间件
|
||||||
|
├── models # 应用数据库模型
|
||||||
|
├── pkg # 第三方包
|
||||||
|
├── routers # 路由逻辑处理
|
||||||
|
└── runtime # 应用运行时数据
|
||||||
|
```
|
|
@ -0,0 +1,55 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"game_demo/models"
|
||||||
|
"game_demo/pkg/e"
|
||||||
|
"game_demo/pkg/logging"
|
||||||
|
"game_demo/pkg/util"
|
||||||
|
"github.com/astaxie/beego/validation"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type auth struct {
|
||||||
|
Username string `valid:"Required; MaxSize(50)"`
|
||||||
|
Password string `valid:"Required; MaxSize(50)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAuth(c *gin.Context) {
|
||||||
|
username := c.Query("username")
|
||||||
|
password := c.Query("password")
|
||||||
|
|
||||||
|
valid := validation.Validation{}
|
||||||
|
a := auth{Username : username, Password : password}
|
||||||
|
ok, err := valid.Valid(&a)
|
||||||
|
|
||||||
|
logging.Info(err)
|
||||||
|
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
code := e.INVALID_PARAMS
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
isExist := models.CheckAuth(username, password)
|
||||||
|
if isExist {
|
||||||
|
token, err := util.GenerateToken(username, password)
|
||||||
|
if err != nil {
|
||||||
|
code = e.ERROR_AUTH_TOKEN
|
||||||
|
} else {
|
||||||
|
data["token"] = token
|
||||||
|
code = e.SUCCESS
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
code = e.ERROR_AUTH
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, err := range valid.Errors {
|
||||||
|
logging.Info(err.Key, err.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"code": code,
|
||||||
|
"msg" : e.GetMsg(code),
|
||||||
|
"data" : data,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"game_demo/models"
|
||||||
|
"game_demo/pkg/e"
|
||||||
|
"game_demo/pkg/logging"
|
||||||
|
"game_demo/pkg/setting"
|
||||||
|
"game_demo/pkg/util"
|
||||||
|
"github.com/Unknwon/com"
|
||||||
|
"github.com/astaxie/beego/validation"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Summary 获取多个游戏
|
||||||
|
// @Description
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param Authorization header string true "auth by /auth"
|
||||||
|
// @Success 200 {string} json "{"code" : 200, "data" : {}, msg: "ok"}"
|
||||||
|
// @Router /v1/games [get]
|
||||||
|
func GetGames(c *gin.Context) {
|
||||||
|
name := c.Query("name")
|
||||||
|
|
||||||
|
maps := make(map[string]interface{})
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
maps["name"] = name
|
||||||
|
}
|
||||||
|
|
||||||
|
code := e.SUCCESS
|
||||||
|
|
||||||
|
data["lists"] = models.GetGames(util.GetPage(c), setting.PageSize, maps)
|
||||||
|
data["total"] = models.GetGameTotal(maps)
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"code": code,
|
||||||
|
"msg": e.GetMsg(code),
|
||||||
|
"data": data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增游戏
|
||||||
|
func AddGame(c *gin.Context) {
|
||||||
|
name := c.PostForm("name")
|
||||||
|
cnName := c.PostForm("cn_name")
|
||||||
|
logo := c.PostForm("logo")
|
||||||
|
|
||||||
|
valid := validation.Validation{}
|
||||||
|
valid.Required(name, "name").Message("名称不能为空")
|
||||||
|
valid.Required(cnName, "cn_name").Message("英文名称不能为空")
|
||||||
|
valid.Required(logo, "logo").Message("logo不能为空")
|
||||||
|
|
||||||
|
code := e.INVALID_PARAMS
|
||||||
|
|
||||||
|
logging.Info(ioutil.ReadAll(c.Request.Body))
|
||||||
|
logging.Info(valid)
|
||||||
|
if ! valid.HasErrors() {
|
||||||
|
if ! models.ExistGameByName(name) {
|
||||||
|
code = e.SUCCESS
|
||||||
|
models.AddGame(name, cnName, logo)
|
||||||
|
} else {
|
||||||
|
code = e.ERROR_EXIST_GAME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"code" : code,
|
||||||
|
"msg" : e.GetMsg(code),
|
||||||
|
"data" : make(map[string]string),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改游戏
|
||||||
|
func EditGame(c *gin.Context) {
|
||||||
|
id := com.StrTo(c.Param("id")).MustInt()
|
||||||
|
|
||||||
|
name := c.PostForm("name")
|
||||||
|
cnName := c.PostForm("cn_name")
|
||||||
|
logo := c.PostForm("logo")
|
||||||
|
|
||||||
|
valid := validation.Validation{}
|
||||||
|
|
||||||
|
valid.Min(id, 1, "id").Message("ID必须大于0")
|
||||||
|
|
||||||
|
code := e.INVALID_PARAMS
|
||||||
|
if ! valid.HasErrors() {
|
||||||
|
code = e.SUCCESS
|
||||||
|
if models.ExistGameById(id) {
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
if name != "" {
|
||||||
|
data["name"] = name
|
||||||
|
}
|
||||||
|
if cnName != "" {
|
||||||
|
data["cn_name"] = cnName
|
||||||
|
}
|
||||||
|
if logo != "" {
|
||||||
|
data["logo"] = logo
|
||||||
|
}
|
||||||
|
models.EditGame(id, data)
|
||||||
|
} else {
|
||||||
|
code = e.ERROR_NOT_EXIST_GAME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"code" : code,
|
||||||
|
"msg" : e.GetMsg(code),
|
||||||
|
"data" : make(map[string]string),
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除游戏
|
||||||
|
func DeleteGame(c *gin.Context) {
|
||||||
|
id := com.StrTo(c.Param("id")).MustInt()
|
||||||
|
|
||||||
|
valid := validation.Validation{}
|
||||||
|
valid.Min(id, 1, "id").Message("ID必须大于0")
|
||||||
|
|
||||||
|
code := e.INVALID_PARAMS
|
||||||
|
if ! valid.HasErrors() {
|
||||||
|
code = e.SUCCESS
|
||||||
|
if models.ExistGameById(id) {
|
||||||
|
models.DeleteGame(id)
|
||||||
|
} else {
|
||||||
|
code = e.ERROR_NOT_EXIST_GAME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"code" : code,
|
||||||
|
"msg" : e.GetMsg(code),
|
||||||
|
"data" : make(map[string]string),
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||||
|
// This file was generated by swaggo/swag at
|
||||||
|
// 2019-08-03 00:06:46.857848 +0800 CST m=+0.026554074
|
||||||
|
|
||||||
|
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": {},
|
||||||
|
"license": {},
|
||||||
|
"version": "{{.Version}}"
|
||||||
|
},
|
||||||
|
"host": "{{.Host}}",
|
||||||
|
"basePath": "{{.BasePath}}",
|
||||||
|
"paths": {
|
||||||
|
"/v1/games": {
|
||||||
|
"get": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"summary": "获取多个游戏",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "auth by /auth",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "{\"code\" : 200, \"data\" : {}, msg: \"ok\"}",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
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: "/api",
|
||||||
|
Schemes: []string{},
|
||||||
|
Title: "GameDemo API",
|
||||||
|
Description: "This is a sample server Petstore server.",
|
||||||
|
}
|
||||||
|
|
||||||
|
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{})
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "This is a sample server Petstore server.",
|
||||||
|
"title": "GameDemo API",
|
||||||
|
"termsOfService": "http://swagger.io/terms/",
|
||||||
|
"contact": {},
|
||||||
|
"license": {},
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"basePath": "/api",
|
||||||
|
"paths": {
|
||||||
|
"/v1/games": {
|
||||||
|
"get": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"summary": "获取多个游戏",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "auth by /auth",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "{\"code\" : 200, \"data\" : {}, msg: \"ok\"}",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
basePath: /api
|
||||||
|
info:
|
||||||
|
contact: {}
|
||||||
|
description: This is a sample server Petstore server.
|
||||||
|
license: {}
|
||||||
|
termsOfService: http://swagger.io/terms/
|
||||||
|
title: GameDemo API
|
||||||
|
version: "1.0"
|
||||||
|
paths:
|
||||||
|
/v1/games:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: auth by /auth
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: '{"code" : 200, "data" : {}, msg: "ok"}'
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
summary: 获取多个游戏
|
||||||
|
swagger: "2.0"
|
|
@ -0,0 +1,56 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "./docs"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"game_demo/pkg/setting"
|
||||||
|
"game_demo/routers"
|
||||||
|
ginSwagger "github.com/swaggo/gin-swagger"
|
||||||
|
"github.com/swaggo/gin-swagger/swaggerFiles"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @title GameDemo API
|
||||||
|
// @version 1.0
|
||||||
|
// @description This is a sample server Petstore server.
|
||||||
|
// @termsOfService http://swagger.io/terms/
|
||||||
|
// @BasePath /api
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
router := routers.InitRouter()
|
||||||
|
|
||||||
|
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||||
|
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: fmt.Sprintf(":%d", setting.HTTPPort),
|
||||||
|
Handler: router,
|
||||||
|
ReadTimeout: setting.ReadTimeout,
|
||||||
|
WriteTimeout: setting.WriteTimeout,
|
||||||
|
MaxHeaderBytes: 1 << 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := s.ListenAndServe(); err != nil {
|
||||||
|
log.Printf("Listen: %s\n", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
quit := make(chan os.Signal)
|
||||||
|
signal.Notify(quit, os.Interrupt)
|
||||||
|
<- quit
|
||||||
|
|
||||||
|
log.Printf("Shutdown Server")
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := s.Shutdown(ctx); err != nil {
|
||||||
|
log.Fatal("Server Shutdown:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Server exiting")
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package jwt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"game_demo/pkg/e"
|
||||||
|
"game_demo/pkg/util"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func JWT() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var code int
|
||||||
|
var data interface{}
|
||||||
|
|
||||||
|
code = e.SUCCESS
|
||||||
|
token := c.Request.Header.Get("Authorization")
|
||||||
|
if token == "" {
|
||||||
|
code = e.INVALID_PARAMS
|
||||||
|
} else {
|
||||||
|
claims, err := util.ParseToken(token)
|
||||||
|
if err != nil {
|
||||||
|
code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
|
||||||
|
} else if time.Now().Unix() > claims.ExpiresAt {
|
||||||
|
code = e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if code != e.SUCCESS {
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"code" : code,
|
||||||
|
"msg" : e.GetMsg(code),
|
||||||
|
"data" : data,
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
ID int `gorm:"primary_key" json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckAuth(username, password string) bool {
|
||||||
|
var auth Auth
|
||||||
|
db.Select("id").Where(Auth{Username : username, Password : password}).First(&auth)
|
||||||
|
if auth.ID > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
type Game struct {
|
||||||
|
Model
|
||||||
|
|
||||||
|
Name string `json:"name"`
|
||||||
|
CnName string `json:"cn_name"`
|
||||||
|
Logo string `json:"logo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGames(pageNum int, pageSize int, maps interface{}) (games []Game) {
|
||||||
|
db.Where(maps).Offset(pageNum).Limit(pageSize).Find(&games)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGameTotal(maps interface{}) (count int) {
|
||||||
|
db.Model(&Game{}).Where(maps).Count(&count)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExistGameByName(name string) bool {
|
||||||
|
var game Game
|
||||||
|
db.Select("id").Where("name = ?", name).First(&game)
|
||||||
|
if game.ID > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExistGameById(id int) bool {
|
||||||
|
var game Game
|
||||||
|
db.Select("id").Where("id = ?", id).First(&game)
|
||||||
|
if game.ID > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddGame(name string, cnName string, logo string) bool {
|
||||||
|
db.Create(&Game {
|
||||||
|
Name: name,
|
||||||
|
CnName: cnName,
|
||||||
|
Logo: logo,
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func EditGame(id int, data interface{}) bool {
|
||||||
|
db.Model(&Game{}).Where("id = ?", id).Update(data)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteGame(id int) bool {
|
||||||
|
db.Where("id = ?", id).Delete(&Game{})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"game_demo/pkg/logging"
|
||||||
|
"game_demo/pkg/setting"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var db = InitDbConnect()
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
ID int `gorm:"primary_key" json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt *time.Time `sql:"index" json:"deleted_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
db.LogMode(true)
|
||||||
|
|
||||||
|
db.SingularTable(true)
|
||||||
|
db.DB().SetMaxIdleConns(10)
|
||||||
|
db.DB().SetMaxOpenConns(100)
|
||||||
|
|
||||||
|
DbMigrate()
|
||||||
|
//CloseDB()
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitDbConnect() *gorm.DB {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
dbType, dbName, user, password, host, port, tablePrefix string
|
||||||
|
)
|
||||||
|
|
||||||
|
sec, err := setting.Cfg.GetSection("database")
|
||||||
|
if err != nil {
|
||||||
|
logging.Info(2, "Fail to get section 'database': %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dbType = sec.Key("TYPE").String()
|
||||||
|
dbName = sec.Key("NAME").String()
|
||||||
|
user = sec.Key("USER").String()
|
||||||
|
password = sec.Key("PASSWORD").String()
|
||||||
|
host = sec.Key("HOST").String()
|
||||||
|
port = sec.Key("PORT").String()
|
||||||
|
tablePrefix = sec.Key("TABLE_PREFIX").String()
|
||||||
|
|
||||||
|
db, err := gorm.Open(dbType, fmt.Sprintf("host=%s user=%s dbname=%s port=%s sslmode=disable password=%s", host, user, dbName, port, password))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logging.Info(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
|
||||||
|
return tablePrefix + defaultTableName
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func DbMigrate() {
|
||||||
|
db.AutoMigrate(&Game{}, &Auth{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseDB() {
|
||||||
|
defer db.Close()
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package e
|
||||||
|
|
||||||
|
const (
|
||||||
|
SUCCESS = 200
|
||||||
|
ERROR = 500
|
||||||
|
INVALID_PARAMS = 400
|
||||||
|
|
||||||
|
ERROR_EXIST_GAME = 10001
|
||||||
|
ERROR_EXIST_TEAM = 10002
|
||||||
|
ERROR_NOT_EXIST_GAME = 10003
|
||||||
|
ERROR_NOT_EXIST_TEAM = 10004
|
||||||
|
ERROR_NOT_EXIST_LEAGUE = 10005
|
||||||
|
ERROR_NOT_EXIST_SERIES = 10006
|
||||||
|
|
||||||
|
ERROR_AUTH_CHECK_TOKEN_FAIL = 20001
|
||||||
|
ERROR_AUTH_CHECK_TOKEN_TIMEOUT = 20002
|
||||||
|
ERROR_AUTH_TOKEN = 20003
|
||||||
|
ERROR_AUTH = 20004
|
||||||
|
)
|
|
@ -0,0 +1,27 @@
|
||||||
|
package e
|
||||||
|
|
||||||
|
var MsgFlags = map[int]string {
|
||||||
|
SUCCESS : "ok",
|
||||||
|
ERROR : "fail",
|
||||||
|
INVALID_PARAMS : "请求参数错误",
|
||||||
|
ERROR_EXIST_GAME : "已存在该游戏",
|
||||||
|
ERROR_EXIST_TEAM : "已存在该队伍",
|
||||||
|
ERROR_NOT_EXIST_GAME : "该游戏不存在",
|
||||||
|
ERROR_NOT_EXIST_TEAM : "该队伍不存在",
|
||||||
|
ERROR_NOT_EXIST_LEAGUE : "该联赛不存在",
|
||||||
|
ERROR_NOT_EXIST_SERIES : "该系列赛不存在",
|
||||||
|
|
||||||
|
ERROR_AUTH_CHECK_TOKEN_FAIL : "Token鉴权失败",
|
||||||
|
ERROR_AUTH_CHECK_TOKEN_TIMEOUT : "Token已超时",
|
||||||
|
ERROR_AUTH_TOKEN : "Token生成失败",
|
||||||
|
ERROR_AUTH : "Token错误",
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMsg(code int) string {
|
||||||
|
msg, ok := MsgFlags[code]
|
||||||
|
if ok {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
return MsgFlags[ERROR]
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
LogSavePath = "runtime/logs/"
|
||||||
|
LogSaveName = "log"
|
||||||
|
LogFileExt = "log"
|
||||||
|
TimeFormat = "20060102"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLogFilePath() string {
|
||||||
|
return fmt.Sprintf("%s", LogSavePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLogFileFullPath() string {
|
||||||
|
prefixPath := getLogFilePath()
|
||||||
|
suffixPath := fmt.Sprintf("%s%s.%s", LogSaveName, time.Now().Format(TimeFormat), LogFileExt)
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s%s", prefixPath, suffixPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func openLogFile(filePath string) *os.File {
|
||||||
|
_, err := os.Stat(filePath)
|
||||||
|
switch {
|
||||||
|
case os.IsNotExist(err):
|
||||||
|
mkDir()
|
||||||
|
case os.IsPermission(err):
|
||||||
|
log.Fatalf("Permission :%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
handle, err := os.OpenFile(filePath, os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Fail to OpenFile :%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkDir() {
|
||||||
|
dir, _ := os.Getwd()
|
||||||
|
err := os.MkdirAll(dir + "/" + getLogFilePath(), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Level int
|
||||||
|
|
||||||
|
var (
|
||||||
|
F *os.File
|
||||||
|
|
||||||
|
DefaultPrefix = ""
|
||||||
|
DefaultCallerDepth = 2
|
||||||
|
|
||||||
|
logger *log.Logger
|
||||||
|
logPrefix = ""
|
||||||
|
levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DEBUG Level = iota
|
||||||
|
INFO
|
||||||
|
WARNING
|
||||||
|
ERROR
|
||||||
|
FATAL
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
filePath := getLogFileFullPath()
|
||||||
|
F = openLogFile(filePath)
|
||||||
|
|
||||||
|
logger = log.New(F, DefaultPrefix, log.LstdFlags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Debug(v ...interface{}) {
|
||||||
|
setPrefix(DEBUG)
|
||||||
|
logger.Println(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Info(v ...interface{}) {
|
||||||
|
setPrefix(INFO)
|
||||||
|
logger.Println(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Warn(v ...interface{}) {
|
||||||
|
setPrefix(WARNING)
|
||||||
|
logger.Println(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(v ...interface{}) {
|
||||||
|
setPrefix(ERROR)
|
||||||
|
logger.Println(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatal(v ...interface{}) {
|
||||||
|
setPrefix(FATAL)
|
||||||
|
logger.Fatalln(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPrefix(level Level) {
|
||||||
|
_, file, line, ok := runtime.Caller(DefaultCallerDepth)
|
||||||
|
if ok {
|
||||||
|
logPrefix = fmt.Sprintf("[%s][%s:%d]", levelFlags[level], filepath.Base(file), line)
|
||||||
|
} else {
|
||||||
|
logPrefix = fmt.Sprintf("[%s]", levelFlags[level])
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.SetPrefix(logPrefix)
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package setting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/ini.v1"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Cfg *ini.File
|
||||||
|
|
||||||
|
RunMode string
|
||||||
|
|
||||||
|
HTTPPort int
|
||||||
|
ReadTimeout time.Duration
|
||||||
|
WriteTimeout time.Duration
|
||||||
|
|
||||||
|
PageSize int
|
||||||
|
JwtSecret string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
Cfg, err = ini.Load("conf/app.ini")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Fail to parse 'conf/app.ini': %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadBase()
|
||||||
|
LoadServer()
|
||||||
|
LoadApp()
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadBase() {
|
||||||
|
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("debug")
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadServer() {
|
||||||
|
sec, err := Cfg.GetSection("server")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Fail to get section 'server': %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("debug")
|
||||||
|
|
||||||
|
HTTPPort = sec.Key("HTTP_PORT").MustInt(8000)
|
||||||
|
ReadTimeout = time.Duration(sec.Key("READ_TIMEOUT").MustInt(60)) * time.Second
|
||||||
|
WriteTimeout = time.Duration(sec.Key("WRITE_TIMEOUT").MustInt(60)) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadApp() {
|
||||||
|
sec, err := Cfg.GetSection("app")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Fail to get section 'app': %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
JwtSecret = sec.Key("JWT_SECRET").MustString("!@)*#)!@U#@*!@!)")
|
||||||
|
PageSize = sec.Key("PAGE_SIZE").MustInt(10)
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"game_demo/pkg/setting"
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var jwtSecret = []byte(setting.JwtSecret)
|
||||||
|
|
||||||
|
type Claims struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
jwt.StandardClaims
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateToken(username, password string) (string, error) {
|
||||||
|
nowTime := time.Now()
|
||||||
|
expireTime := nowTime.Add(3 * time.Hour)
|
||||||
|
|
||||||
|
claims := Claims{
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
StandardClaims: jwt.StandardClaims{
|
||||||
|
ExpiresAt: expireTime.Unix(),
|
||||||
|
Issuer : "gin-game-demo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
token, err := tokenClaims.SignedString(jwtSecret)
|
||||||
|
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseToken(token string) (*Claims, error) {
|
||||||
|
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return jwtSecret, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if tokenClaims != nil {
|
||||||
|
if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"game_demo/pkg/setting"
|
||||||
|
"github.com/Unknwon/com"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetPage(c *gin.Context) int {
|
||||||
|
result := 0
|
||||||
|
page, _ := com.StrTo(c.Query("page")).Int()
|
||||||
|
if page > 0 {
|
||||||
|
result = (page - 1) * setting.PageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package routers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"game_demo/api"
|
||||||
|
"game_demo/pkg/setting"
|
||||||
|
"game_demo/routers/v1"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitRouter() *gin.Engine {
|
||||||
|
r := gin.New()
|
||||||
|
|
||||||
|
r.Use(gin.Logger())
|
||||||
|
|
||||||
|
r.Use(gin.Recovery())
|
||||||
|
|
||||||
|
gin.SetMode(setting.RunMode)
|
||||||
|
|
||||||
|
r.GET("/auth", api.GetAuth)
|
||||||
|
|
||||||
|
// 加载模块的路由
|
||||||
|
v1.GameRouter(r)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"game_demo/api/v1"
|
||||||
|
"game_demo/middleware/jwt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GameRouter(r *gin.Engine) {
|
||||||
|
apiv1 := r.Group("../api/v1")
|
||||||
|
apiv1.Use(jwt.JWT())
|
||||||
|
{
|
||||||
|
// 获取游戏列表
|
||||||
|
apiv1.GET("/games", v1.GetGames)
|
||||||
|
// 新建游戏
|
||||||
|
apiv1.POST("/games", v1.AddGame)
|
||||||
|
// 更新指定游戏
|
||||||
|
apiv1.PUT("/games/:id", v1.EditGame)
|
||||||
|
// 删除指定游戏
|
||||||
|
apiv1.DELETE("/games/:id", v1.DeleteGame)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
[INFO][auth.go:26]2019/08/02 19:59:10 [<nil>]
|
||||||
|
[INFO][auth.go:26]2019/08/02 19:59:27 [<nil>]
|
||||||
|
[INFO][auth.go:26]2019/08/02 19:59:29 [<nil>]
|
||||||
|
[INFO][auth.go:26]2019/08/02 19:59:38 [<nil>]
|
||||||
|
[INFO][auth.go:46]2019/08/02 19:59:38 [Password.Required Can not be empty]
|
||||||
|
[INFO][auth.go:26]2019/08/02 19:59:45 [<nil>]
|
||||||
|
[INFO][auth.go:46]2019/08/02 19:59:45 [Username.Required Can not be empty]
|
||||||
|
[INFO][auth.go:46]2019/08/02 19:59:45 [Password.Required Can not be empty]
|
||||||
|
[INFO][models.go:54]2019/08/02 20:01:16 [dial tcp 127.0.0.1:543: connect: connection refused]
|
||||||
|
[INFO][main.go:36]2019/08/02 20:18:21 [Shutdown Server]
|
||||||
|
[INFO][main.go:44]2019/08/02 20:18:21 [Server exiting]
|
||||||
|
[INFO][main.go:36]2019/08/02 20:22:44 [Shutdown Server]
|
||||||
|
[INFO][main.go:44]2019/08/02 20:22:44 [Server exiting]
|
||||||
|
[INFO][main.go:28]2019/08/02 20:22:44 [Listen: %s
|
||||||
|
http: Server closed]
|
||||||
|
[INFO][main.go:36]2019/08/02 20:22:53 [Shutdown Server]
|
||||||
|
[INFO][main.go:44]2019/08/02 20:22:53 [Server exiting]
|
||||||
|
[INFO][main.go:28]2019/08/02 20:22:53 [Listen: %s
|
||||||
|
http: Server closed]
|
||||||
|
[INFO][main.go:36]2019/08/02 20:23:35 [Shutdown Server]
|
||||||
|
[INFO][main.go:28]2019/08/02 20:23:35 [Listen: %s
|
||||||
|
http: Server closed]
|
||||||
|
[INFO][main.go:44]2019/08/02 20:23:35 [Server exiting]
|
||||||
|
[INFO][main.go:36]2019/08/02 20:23:38 [Shutdown Server]
|
||||||
|
[INFO][main.go:44]2019/08/02 20:23:38 [Server exiting]
|
||||||
|
[INFO][main.go:28]2019/08/02 20:23:38 [Listen: %s
|
||||||
|
http: Server closed]
|
||||||
|
[INFO][main.go:36]2019/08/02 20:28:25 [Shutdown Server]
|
||||||
|
[INFO][main.go:44]2019/08/02 20:28:25 [Server exiting]
|
||||||
|
[INFO][main.go:28]2019/08/02 20:28:25 [Listen: %s
|
||||||
|
http: Server closed]
|
||||||
|
[INFO][main.go:36]2019/08/02 20:28:31 [Shutdown Server]
|
||||||
|
[INFO][main.go:44]2019/08/02 20:28:31 [Server exiting]
|
||||||
|
[INFO][main.go:36]2019/08/02 20:28:49 [Shutdown Server]
|
||||||
|
[INFO][main.go:44]2019/08/02 20:28:49 [Server exiting]
|
||||||
|
[INFO][main.go:37]2019/08/02 20:28:59 [Shutdown Server]
|
||||||
|
[INFO][main.go:45]2019/08/02 20:28:59 [Server exiting]
|
||||||
|
[INFO][auth.go:26]2019/08/02 23:42:23 [<nil>]
|
||||||
|
[INFO][auth.go:46]2019/08/02 23:42:23 [Username.Required Can not be empty]
|
||||||
|
[INFO][auth.go:46]2019/08/02 23:42:23 [Password.Required Can not be empty]
|
|
@ -0,0 +1 @@
|
||||||
|
[INFO][auth.go:26]2019/08/03 00:19:40 [<nil>]
|
Loading…
Reference in New Issue