[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