pixelqm
5 years ago
14 changed files with 450 additions and 0 deletions
-
38QMPlusServer/config/config.go
-
9QMPlusServer/config/dbconfig/config.json
-
21QMPlusServer/go.mod
-
21QMPlusServer/init/initMysql.go
-
14QMPlusServer/init/initRouter.go
-
32QMPlusServer/main.go
-
138QMPlusServer/middleware/jwt.go
-
60QMPlusServer/middleware/logger.go
-
9QMPlusServer/model/interface.go
-
21QMPlusServer/model/user.go
-
41QMPlusServer/tools/des.go
-
34QMPlusServer/tools/hasGap.go
-
12QMPlusServer/tools/md5.go
-
BINREADME.md
@ -0,0 +1,38 @@ |
|||
package config |
|||
|
|||
import ( |
|||
"fmt" |
|||
"github.com/fsnotify/fsnotify" |
|||
"github.com/spf13/viper" |
|||
) |
|||
|
|||
type Config struct { |
|||
Admin Admin |
|||
} |
|||
type Admin struct { |
|||
UserName string |
|||
Password string |
|||
Path string |
|||
Dbname string |
|||
Config string |
|||
} |
|||
|
|||
var Dbconfig Config |
|||
|
|||
func init() { |
|||
v := viper.New() |
|||
v.SetConfigName("config") // 设置配置文件名 (不带后缀)
|
|||
v.AddConfigPath("./config/dbconfig/") // 第一个搜索路径
|
|||
v.SetConfigType("json") |
|||
err := v.ReadInConfig() // 搜索路径,并读取配置数据
|
|||
if err != nil { |
|||
panic(fmt.Errorf("Fatal error config file: %s \n", err)) |
|||
} |
|||
v.WatchConfig() |
|||
v.OnConfigChange(func(e fsnotify.Event) { |
|||
fmt.Println("Config file changed:", e.Name) |
|||
}) |
|||
if err := v.Unmarshal(&Dbconfig); err != nil { |
|||
fmt.Println(err) |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
{ |
|||
"admin": { |
|||
"userName": "root", |
|||
"password": "Aa@6447985", |
|||
"path": "127.0.0.1:3306", |
|||
"dbname": "zhongzerong", |
|||
"config": "charset=utf8&parseTime=True&loc=Local" |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
module main |
|||
|
|||
go 1.12 |
|||
|
|||
require ( |
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible |
|||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect |
|||
github.com/fsnotify/fsnotify v1.4.7 |
|||
github.com/gin-gonic/gin v1.4.0 |
|||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect |
|||
github.com/jinzhu/gorm v1.9.10 |
|||
github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect |
|||
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f |
|||
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect |
|||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 |
|||
github.com/satori/go.uuid v1.2.0 |
|||
github.com/sirupsen/logrus v1.2.0 |
|||
github.com/spf13/viper v1.4.0 |
|||
github.com/swaggo/gin-swagger v1.2.0 |
|||
github.com/tebeka/strftime v0.1.3 // indirect |
|||
) |
@ -0,0 +1,21 @@ |
|||
package init |
|||
|
|||
import ( |
|||
"github.com/jinzhu/gorm" |
|||
_ "github.com/jinzhu/gorm/dialects/mysql" |
|||
"log" |
|||
"main/config" |
|||
) |
|||
|
|||
var DEFAULTDB *gorm.DB |
|||
|
|||
func InitMysql(admin config.Admin) { |
|||
if db, err := gorm.Open("mysql", admin.UserName+":"+admin.Password+"@("+admin.Path+")/"+admin.Dbname+"?"+admin.Config); err != nil { |
|||
log.Printf("DEFAULTDB数据库启动异常%S", err) |
|||
} else { |
|||
DEFAULTDB = db |
|||
DEFAULTDB.DB().SetMaxIdleConns(10) |
|||
DEFAULTDB.DB().SetMaxIdleConns(100) |
|||
DEFAULTDB.AutoMigrate() |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
package init |
|||
|
|||
import ( |
|||
"github.com/gin-gonic/gin" |
|||
"github.com/swaggo/gin-swagger" |
|||
"github.com/swaggo/gin-swagger/swaggerFiles" |
|||
) |
|||
|
|||
var Router = gin.Default() |
|||
|
|||
func InitRouter() { |
|||
Router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) |
|||
//Router.Use(middleware.Logger())
|
|||
} |
@ -0,0 +1,32 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"main/config" |
|||
"main/init" |
|||
"net/http" |
|||
"time" |
|||
) |
|||
|
|||
// @Summary 打印测试功能
|
|||
// @title Swagger Example API
|
|||
// @version 0.0.1
|
|||
// @description This is a sample server Petstore server.
|
|||
// @BasePath /api/v1
|
|||
// @Host 127.0.0.1:8080
|
|||
// @Produce json
|
|||
// @Param name query string true "Name"
|
|||
// @Success 200 {string} json "{"code":200,"data":"name","msg":"ok"}"
|
|||
// @Router / [get]
|
|||
func main() { |
|||
init.InitMysql(config.Dbconfig.Admin) |
|||
defer init.DEFAULTDB.Close() |
|||
init.InitRouter() |
|||
s := &http.Server{ |
|||
Addr: ":8888", |
|||
Handler: init.Router, |
|||
ReadTimeout: 10 * time.Second, |
|||
WriteTimeout: 10 * time.Second, |
|||
MaxHeaderBytes: 1 << 20, |
|||
} |
|||
_ = s.ListenAndServe() |
|||
} |
@ -0,0 +1,138 @@ |
|||
package middleware |
|||
|
|||
import ( |
|||
"errors" |
|||
"github.com/dgrijalva/jwt-go" |
|||
"github.com/gin-gonic/gin" |
|||
uuid "github.com/satori/go.uuid" |
|||
"net/http" |
|||
"time" |
|||
) |
|||
|
|||
func JWTAuth() gin.HandlerFunc { |
|||
return func(c *gin.Context) { |
|||
token := c.Request.Header.Get("x-token") |
|||
if token == "" { |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"success": false, |
|||
"msg": "未登录或非法访问", |
|||
"data": gin.H{}, |
|||
}) |
|||
c.Abort() |
|||
return |
|||
} |
|||
j := NewJWT() |
|||
// parseToken 解析token包含的信息
|
|||
claims, err := j.ParseToken(token) |
|||
if err != nil { |
|||
if err == TokenExpired { |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"success": false, |
|||
"msg": "授权已过期", |
|||
}) |
|||
c.Abort() |
|||
return |
|||
} |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"success": false, |
|||
"msg": err.Error(), |
|||
}) |
|||
c.Abort() |
|||
return |
|||
} |
|||
c.Set("claims", claims) |
|||
} |
|||
} |
|||
|
|||
type JWT struct { |
|||
SigningKey []byte |
|||
} |
|||
|
|||
var ( |
|||
TokenExpired error = errors.New("Token is expired") |
|||
TokenNotValidYet error = errors.New("Token not active yet") |
|||
TokenMalformed error = errors.New("That's not even a token") |
|||
TokenInvalid error = errors.New("Couldn't handle this token:") |
|||
SignKey string = "newtrekWang" |
|||
) |
|||
|
|||
type CustomClaims struct { |
|||
UUID uuid.UUID |
|||
ID uint |
|||
AuthorityID uint |
|||
jwt.StandardClaims |
|||
} |
|||
|
|||
func NewJWT() *JWT { |
|||
return &JWT{ |
|||
[]byte(GetSignKey()), |
|||
} |
|||
} |
|||
|
|||
//获取token
|
|||
func GetSignKey() string { |
|||
return SignKey |
|||
} |
|||
|
|||
// 这是SignKey
|
|||
func SetSignKey(key string) string { |
|||
SignKey = key |
|||
return SignKey |
|||
} |
|||
|
|||
//创建一个token
|
|||
func (j *JWT) CreateToken(claims CustomClaims) (string, error) { |
|||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |
|||
return token.SignedString(j.SigningKey) |
|||
} |
|||
|
|||
//解析 token
|
|||
func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) { |
|||
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) { |
|||
return j.SigningKey, nil |
|||
}) |
|||
if err != nil { |
|||
if ve, ok := err.(*jwt.ValidationError); ok { |
|||
if ve.Errors&jwt.ValidationErrorMalformed != 0 { |
|||
return nil, TokenMalformed |
|||
} else if ve.Errors&jwt.ValidationErrorExpired != 0 { |
|||
// Token is expired
|
|||
return nil, TokenExpired |
|||
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { |
|||
return nil, TokenNotValidYet |
|||
} else { |
|||
return nil, TokenInvalid |
|||
} |
|||
} |
|||
} |
|||
if token != nil { |
|||
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { |
|||
return claims, nil |
|||
} |
|||
return nil, TokenInvalid |
|||
|
|||
} else { |
|||
return nil, TokenInvalid |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
// 更新token
|
|||
func (j *JWT) RefreshToken(tokenString string) (string, error) { |
|||
jwt.TimeFunc = func() time.Time { |
|||
return time.Unix(0, 0) |
|||
} |
|||
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { |
|||
return j.SigningKey, nil |
|||
}) |
|||
if err != nil { |
|||
return "", err |
|||
} |
|||
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { |
|||
jwt.TimeFunc = time.Now |
|||
claims.StandardClaims.ExpiresAt = time.Now().Add(1 * time.Hour).Unix() |
|||
return j.CreateToken(*claims) |
|||
} |
|||
return "", TokenInvalid |
|||
} |
@ -0,0 +1,60 @@ |
|||
package middleware |
|||
|
|||
import ( |
|||
"fmt" |
|||
"github.com/gin-gonic/gin" |
|||
"github.com/lestrrat/go-file-rotatelogs" |
|||
"github.com/rifflock/lfshook" |
|||
"github.com/sirupsen/logrus" |
|||
"os" |
|||
"time" |
|||
) |
|||
|
|||
func Logger() gin.HandlerFunc { |
|||
logClient := logrus.New() |
|||
//禁止logrus的输出
|
|||
src, err := os.OpenFile(os.DevNull, os.O_APPEND|os.O_WRONLY, os.ModeAppend) |
|||
if err != nil { |
|||
fmt.Println("err", err) |
|||
} |
|||
logClient.Out = src |
|||
logClient.SetLevel(logrus.DebugLevel) |
|||
apiLogPath := "api.log" |
|||
logWriter, err := rotatelogs.New( |
|||
apiLogPath+".%Y-%m-%d-%H-%M.log", |
|||
rotatelogs.WithLinkName(apiLogPath), // 生成软链,指向最新日志文件
|
|||
rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
|
|||
rotatelogs.WithRotationTime(24*time.Hour), // 日志切割时间间隔
|
|||
) |
|||
writeMap := lfshook.WriterMap{ |
|||
logrus.InfoLevel: logWriter, |
|||
logrus.FatalLevel: logWriter, |
|||
} |
|||
lfHook := lfshook.NewHook(writeMap, &logrus.JSONFormatter{}) |
|||
logClient.AddHook(lfHook) |
|||
|
|||
return func(c *gin.Context) { |
|||
// 开始时间
|
|||
start := time.Now() |
|||
// 处理请求
|
|||
c.Next() |
|||
// 结束时间
|
|||
end := time.Now() |
|||
//执行时间
|
|||
latency := end.Sub(start) |
|||
|
|||
path := c.Request.URL.Path |
|||
clientIP := c.ClientIP() |
|||
method := c.Request.Method |
|||
statusCode := c.Writer.Status() |
|||
buf := make([]byte, 1024) |
|||
n, _ := c.Request.Body.Read(buf) |
|||
requestParams := buf[0:n] |
|||
logClient.Infof("| %3d | %13v | %15s | %s %s |%s|", |
|||
statusCode, |
|||
latency, |
|||
clientIP, |
|||
method, path, requestParams, |
|||
) |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
package model |
|||
|
|||
// 因为我也不确定项目要不要多人维护 所以定义了CURD接口 凡是对数据库进行简单CURD操作 请实现此接口 默认首位返回 error
|
|||
type CURD interface { |
|||
Create() (error, interface{}) |
|||
Updata() (error, interface{}) |
|||
Read() (error, interface{}) |
|||
Delete() (error, interface{}) |
|||
} |
@ -0,0 +1,21 @@ |
|||
package model |
|||
|
|||
import ( |
|||
"github.com/jinzhu/gorm" |
|||
uuid "github.com/satori/go.uuid" |
|||
) |
|||
|
|||
type User struct { |
|||
gorm.Model `json:"-"` |
|||
UUID uuid.UUID `json:"uuid"` |
|||
UserName string `json:"userName"` |
|||
PassWord string `json:"passWord"` |
|||
NickName string `json:"nickName" gorm:"default:'galeone'"` |
|||
HeaderImg string `json:"headerImg" gorm:"default:'galeone'"` |
|||
//Propertie // 多余属性自行添加
|
|||
//PropertieId uint // 自动关联 Propertie 的Id 附加属性过多 建议创建一对一关系
|
|||
} |
|||
|
|||
//type Propertie struct {
|
|||
// gorm.Model
|
|||
//}
|
@ -0,0 +1,41 @@ |
|||
package tools |
|||
|
|||
import ( |
|||
"bytes" |
|||
"crypto/cipher" |
|||
"crypto/des" |
|||
) |
|||
|
|||
func padding(src []byte, blocksize int) []byte { |
|||
n := len(src) |
|||
padnum := blocksize - n%blocksize |
|||
pad := bytes.Repeat([]byte{byte(padnum)}, padnum) |
|||
dst := append(src, pad...) |
|||
return dst |
|||
} |
|||
|
|||
func unpadding(src []byte) []byte { |
|||
n := len(src) |
|||
unpadnum := int(src[n-1]) |
|||
dst := src[:n-unpadnum] |
|||
return dst |
|||
} |
|||
|
|||
func EncryptDES(src []byte) []byte { |
|||
key := []byte("qimiao66") |
|||
block, _ := des.NewCipher(key) |
|||
src = padding(src, block.BlockSize()) |
|||
blockmode := cipher.NewCBCEncrypter(block, key) |
|||
blockmode.CryptBlocks(src, src) |
|||
return src |
|||
} |
|||
|
|||
func DecryptDES(src []byte) []byte { |
|||
key := []byte("qimiao66") |
|||
block, _ := des.NewCipher(key) |
|||
blockmode := cipher.NewCBCDecrypter(block, key) |
|||
blockmode.CryptBlocks(src, src) |
|||
src = unpadding(src) |
|||
return src |
|||
|
|||
} |
@ -0,0 +1,34 @@ |
|||
// 空值校验工具 仅用于检验空字符串 其余类型请勿使用
|
|||
|
|||
package tools |
|||
|
|||
import ( |
|||
"errors" |
|||
"fmt" |
|||
"reflect" |
|||
) |
|||
|
|||
func HasGap(input interface{}) error { |
|||
getType := reflect.TypeOf(input) |
|||
fmt.Println("获取类型 :", getType.Name()) |
|||
|
|||
getValue := reflect.ValueOf(input) |
|||
fmt.Println("所有字段", getValue) |
|||
|
|||
// 获取方法字段
|
|||
for i := 0; i < getType.NumField(); i++ { |
|||
field := getType.Field(i) |
|||
value := getValue.Field(i).Interface() |
|||
fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value) |
|||
if value == "" { |
|||
return errors.New(fmt.Sprintf("%s为空", field.Name)) |
|||
} |
|||
} |
|||
// 获取方法
|
|||
// 1. 先获取interface的reflect.Type,然后通过.NumMethod进行遍历
|
|||
//for i := 0; i < getType.NumMethod(); i++ {
|
|||
// m := getType.Method(i)
|
|||
// fmt.Printf("%s: %v\n", m.Name, m.Type)
|
|||
//}
|
|||
return nil |
|||
} |
@ -0,0 +1,12 @@ |
|||
package tools |
|||
|
|||
import ( |
|||
"crypto/md5" |
|||
"encoding/hex" |
|||
) |
|||
|
|||
func MD5V(str string) string { |
|||
h := md5.New() |
|||
h.Write([]byte(str)) |
|||
return hex.EncodeToString(h.Sum(nil)) |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue