From e98c0f3b34e883db5d698ee993a4efae5badc27e Mon Sep 17 00:00:00 2001 From: virus Date: Tue, 15 Sep 2020 12:25:30 +0800 Subject: [PATCH] [ADD]first commit --- conf/app.ini | 18 ++++++++++++ go.mod | 40 +++++++++++++++++++++++++++ main.go | 22 +++++++++++++++ middleware/jwt/jwt.go | 38 +++++++++++++++++++++++++ models/models.go | 60 ++++++++++++++++++++++++++++++++++++++++ pkg/e/code.go | 16 +++++++++++ pkg/e/msg.go | 23 +++++++++++++++ pkg/logging/file.go | 44 +++++++++++++++++++++++++++++ pkg/logging/log.go | 63 ++++++++++++++++++++++++++++++++++++++++++ pkg/setting/setting.go | 54 ++++++++++++++++++++++++++++++++++++ pkg/util/jwt.go | 45 ++++++++++++++++++++++++++++++ pkg/util/pagenation.go | 17 ++++++++++++ routers/router.go | 29 +++++++++++++++++++ 13 files changed, 469 insertions(+) create mode 100644 conf/app.ini create mode 100644 go.mod create mode 100644 main.go create mode 100644 middleware/jwt/jwt.go create mode 100644 models/models.go create mode 100644 pkg/e/code.go create mode 100644 pkg/e/msg.go create mode 100644 pkg/logging/file.go create mode 100644 pkg/logging/log.go create mode 100644 pkg/setting/setting.go create mode 100644 pkg/util/jwt.go create mode 100644 pkg/util/pagenation.go create mode 100644 routers/router.go diff --git a/conf/app.ini b/conf/app.ini new file mode 100644 index 0000000..9415757 --- /dev/null +++ b/conf/app.ini @@ -0,0 +1,18 @@ +RUN_MODE = debug + +[app] +PAGE_SIZE = 10 +JWT_SECRET = 23347$040412 + +[server] +HTTP_PORT = 8001 +READ_TIMEOUT = 60 +WRITE_TIMEOUT = 60 + +[database] +TYPE = mysql +USER = root +PASSWORD = a19960425 +HOST = localhost:3306 +NAME = blog +TABLE_PREFIX = blog_ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d46f870 --- /dev/null +++ b/go.mod @@ -0,0 +1,40 @@ +module github.com/go-pripro/shop + +go 1.15 + +require ( + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/gin-gonic/gin v1.6.3 + github.com/go-ini/ini v1.61.0 + github.com/go-playground/validator/v10 v10.3.0 // indirect + github.com/golang/protobuf v1.4.2 // indirect + github.com/jinzhu/gorm v1.9.16 + github.com/json-iterator/go v1.1.10 // indirect + github.com/lib/pq v1.2.0 // indirect + github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect + github.com/ugorji/go v1.1.8 // indirect + github.com/unknwon/com v1.0.1 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect + golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/protobuf v1.25.0 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/ini.v1 v1.61.0 // indirect + gopkg.in/yaml.v2 v2.3.0 // indirect +) + +replace ( + github.com/go-pripro/shop/conf => ./shop/pkg/conf + github.com/go-pripro/shop/docs => ./shop/docs + github.com/go-pripro/shop/middleware => ./shop/middleware + github.com/go-pripro/shop/models => ./shop/models + github.com/go-pripro/shop/pkg/e => ./shop/pkg/e + github.com/go-pripro/shop/pkg/logging => ./shop/pkg/logging + github.com/go-pripro/shop/pkg/setting => ./shop/pkg/setting + github.com/go-pripro/shop/pkg/util => ./shop/pkg/util + github.com/go-pripro/shop/routers => ./shop/routers +) diff --git a/main.go b/main.go new file mode 100644 index 0000000..0eac00a --- /dev/null +++ b/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "github.com/go-pripro/shop/pkg/setting" + "github.com/go-pripro/shop/routers" + "net/http" +) + +func main() { + router := routers.InitRouter() + + s := &http.Server{ + Addr: fmt.Sprintf(":%d", setting.HTTPPort), + Handler: router, + ReadTimeout: setting.ReadTimeout, + WriteTimeout: setting.WriteTimeout, + MaxHeaderBytes: 1 << 20, + } + + s.ListenAndServe() +} \ No newline at end of file diff --git a/middleware/jwt/jwt.go b/middleware/jwt/jwt.go new file mode 100644 index 0000000..8cae3ad --- /dev/null +++ b/middleware/jwt/jwt.go @@ -0,0 +1,38 @@ +package jwt + +import ( + "github.com/gin-gonic/gin" + "github.com/go-pripro/shop/pkg/e" + "github.com/go-pripro/shop/pkg/util" + "net/http" + "time" +) + +func JWT() gin.HandlerFunc { + return func(c *gin.Context) { + var code int + var data interface{} + code = e.SUCCESS + token := c.Query("token") + 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() + } +} \ No newline at end of file diff --git a/models/models.go b/models/models.go new file mode 100644 index 0000000..191aa8a --- /dev/null +++ b/models/models.go @@ -0,0 +1,60 @@ +package models + +import ( + "fmt" + "github.com/go-pripro/shop/pkg/setting" + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/mysql" + "log" +) + +var db *gorm.DB + +type Model struct { + ID int `gorm:"primary_key" json:"id"` + CreatedOn int `json:"created_on"` + ModifiedOn int `json:"modified_on"` +} + +func init() { + var ( + err error + dbType, dbName, user, password, host, tablePrefix string + ) + + sec, err := setting.Cfg.GetSection("database") + if err != nil { + log.Fatal(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() + tablePrefix = sec.Key("TABLE_PREFIX").String() + + db, err = gorm.Open(dbType, fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local", + user, + password, + host, + dbName)) + + if err != nil { + log.Println(err) + } + + gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string { + return tablePrefix + defaultTableName + } + + //db.AutoMigrate(&Tag{}, &Article{}, &Auth{}) + //db.SingularTable(true) + db.LogMode(true) + db.DB().SetMaxIdleConns(10) + db.DB().SetMaxOpenConns(100) +} + +func CloseDB() { + defer db.Close() +} \ No newline at end of file diff --git a/pkg/e/code.go b/pkg/e/code.go new file mode 100644 index 0000000..5f0773b --- /dev/null +++ b/pkg/e/code.go @@ -0,0 +1,16 @@ +package e + +const ( + SUCCESS = 200 + ERROR = 500 + INVALID_PARAMS = 400 + + ERROR_EXIST_TAG = 10001 + ERROR_NOT_EXIST_TAG = 10002 + ERROR_NOT_EXIST_ARTICLE = 10003 + + ERROR_AUTH_CHECK_TOKEN_FAIL = 20001 + ERROR_AUTH_CHECK_TOKEN_TIMEOUT = 20002 + ERROR_AUTH_TOKEN = 20003 + ERROR_AUTH = 20004 +) diff --git a/pkg/e/msg.go b/pkg/e/msg.go new file mode 100644 index 0000000..cf21a30 --- /dev/null +++ b/pkg/e/msg.go @@ -0,0 +1,23 @@ +package e + +var MsgFlags = map[int]string{ + SUCCESS: "ok", + ERROR: "fail", + INVALID_PARAMS: "请求参数错误", + ERROR_EXIST_TAG: "已存在该标签名称", + ERROR_NOT_EXIST_TAG: "该标签不存在", + ERROR_NOT_EXIST_ARTICLE: "该文章不存在", + 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] +} diff --git a/pkg/logging/file.go b/pkg/logging/file.go new file mode 100644 index 0000000..1c58afe --- /dev/null +++ b/pkg/logging/file.go @@ -0,0 +1,44 @@ +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) + } +} \ No newline at end of file diff --git a/pkg/logging/log.go b/pkg/logging/log.go new file mode 100644 index 0000000..f31bbce --- /dev/null +++ b/pkg/logging/log.go @@ -0,0 +1,63 @@ +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) +} diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go new file mode 100644 index 0000000..3dea4f7 --- /dev/null +++ b/pkg/setting/setting.go @@ -0,0 +1,54 @@ +package setting + +import ( + "github.com/go-ini/ini" + "log" + "time" +) + +var Cfg *ini.File +var ( + 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.Fatalf("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 'sever' : %v", err) + } + + HTTPPort = sec.Key("HTTP_PORT").MustInt(8000) + ReadTimeout = time.Duration(sec.Key("READ_TIMEOUT").MustUint(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("!@#!@#!@#!@@#!@#") + PageSize = sec.Key("PAGE_SIZE").MustInt(10) +} diff --git a/pkg/util/jwt.go b/pkg/util/jwt.go new file mode 100644 index 0000000..38470c1 --- /dev/null +++ b/pkg/util/jwt.go @@ -0,0 +1,45 @@ +package util + +import ( + jwt "github.com/dgrijalva/jwt-go" + "github.com/go-pripro/shop/pkg/setting" + "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, + password, + jwt.StandardClaims{ + ExpiresAt: expireTime.Unix(), + Issuer: "gin-blog", + }, + } + + 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 +} diff --git a/pkg/util/pagenation.go b/pkg/util/pagenation.go new file mode 100644 index 0000000..0afc4af --- /dev/null +++ b/pkg/util/pagenation.go @@ -0,0 +1,17 @@ +package util + +import ( + "github.com/gin-gonic/gin" + "github.com/go-pripro/shop/pkg/setting" + "github.com/unknwon/com" +) + +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 +} diff --git a/routers/router.go b/routers/router.go new file mode 100644 index 0000000..5977f7f --- /dev/null +++ b/routers/router.go @@ -0,0 +1,29 @@ +package routers + +import ( + "github.com/gin-gonic/gin" + "github.com/go-pripro/shop/pkg/setting" +) + +func InitRouter() *gin.Engine { + r := gin.New() + + r.Use(gin.Logger()) + + r.Use(gin.Recovery()) + + gin.SetMode(setting.RunMode) + + r.GET("/ping", func(c *gin.Context) { + c.JSON(200, gin.H{ + "message": "pong", + }) + }) + r.GET("/test", func(c *gin.Context) { + c.JSON(200, gin.H{ + "message": "test", + }) + }) + + return r +}