提交 84a9cbda 编写于 作者: Mr.奇淼('s avatar Mr.奇淼(

项目基本构成

上级 76d3e97a
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)
}
}
{
"admin": {
"userName": "root",
"password": "Aa@6447985",
"path": "127.0.0.1:3306",
"dbname": "zhongzerong",
"config": "charset=utf8&parseTime=True&loc=Local"
}
}
\ No newline at end of file
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
)
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()
}
}
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())
}
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()
}
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
}
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,
)
}
}
package model
// 因为我也不确定项目要不要多人维护 所以定义了CURD接口 凡是对数据库进行简单CURD操作 请实现此接口 默认首位返回 error
type CURD interface {
Create() (error, interface{})
Updata() (error, interface{})
Read() (error, interface{})
Delete() (error, interface{})
}
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
//}
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
}
// 空值校验工具 仅用于检验空字符串 其余类型请勿使用
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
}
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))
}
B# QMPlus gin+vue开源快速项目模板
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册