1、go接入gin(完成)

2、go接入gorm(完成)
3、环境yaml配置(完成)
4、多库支持(完成)
5、接入日志(完成)
6、接入redis(完成)
7、自定义路由(完成)
8、接入jwt(完成)
This commit is contained in:
TianJun
2021-04-28 15:03:48 +08:00
parent 6b21987033
commit 1a8707eee6
21 changed files with 1400 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
"lingye-gin/src/config"
"strings"
)
type GinEngine struct {
}
func (GinEngine) Start() {
config.Logger.Info("GinWebServer Init...")
if strings.Compare(config.AppProps.App.Mode, "debug") == 0 {
gin.SetMode(gin.DebugMode)
} else if strings.Compare(config.AppProps.App.Mode, "release") == 0 {
gin.SetMode(gin.ReleaseMode)
}
config.Logger.Info("GinWebServer Starting...")
engine := gin.Default()
engine.Use(config.LoggerToFile())
// 设置路由
new(GinRouter).Init(engine)
engine.Run(fmt.Sprintf("0.0.0.0:%d", config.AppProps.Server.Port))
}
+115
View File
@@ -0,0 +1,115 @@
package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
"lingye-gin/src/config"
"lingye-gin/src/rest"
"strings"
)
type GinRouter struct {
}
func (v GinRouter) Init(r *gin.Engine) {
config.Logger.Info("GinRouter Init")
// 一般路由映射关系
groupMap := make(map[string]*gin.RouterGroup)
// api路由映射关系
apiUrls := make([]rest.RequestApi, 0)
// api组名称
apiGroupName := "api"
for _, normalRa := range rest.Urls {
// 判断是否在某一组下
if strings.Compare(normalRa.GroupName, "") == 0 {
// 批量处理
if handle(normalRa, r) {
continue
}
} else {
// 分组名称
groupName := fmt.Sprintf("/%s", normalRa.GroupName)
// api组, 基于jwt验证
if strings.Compare(normalRa.GroupName, apiGroupName) == 0 {
apiUrls = append(apiUrls, normalRa)
continue
}
// 分组不存在
if groupMap[normalRa.GroupName] == nil {
if normalRa.GroupHandleFunction == nil {
// 不存在分组过滤器
groupMap[normalRa.GroupName] = r.Group(groupName)
} else {
groupMap[normalRa.GroupName] = r.Group(groupName, normalRa.GroupHandleFunction)
}
}
// 批量处理
if handleGroup(normalRa, groupMap[normalRa.GroupName]) {
continue
}
}
}
for _, apiRa := range apiUrls {
jwtR := r.Group(apiGroupName)
jwtR.Use(config.JwtHandle)
// 批量处理
if handleGroup(apiRa, jwtR) {
continue
}
}
config.Logger.Info("GinRouter Ok")
}
func handle(request rest.RequestApi, engine *gin.Engine) bool {
// get
if strings.Compare(request.Mode, "get") == 0 {
engine.GET(request.RelativePath, request.HandleFunction)
return true
}
// post
if strings.Compare(request.Mode, "post") == 0 {
engine.POST(request.RelativePath, request.HandleFunction)
return true
}
// delete
if strings.Compare(request.Mode, "delete") == 0 {
engine.DELETE(request.RelativePath, request.HandleFunction)
return true
}
// put
if strings.Compare(request.Mode, "put") == 0 {
engine.PUT(request.RelativePath, request.HandleFunction)
return true
}
return false
}
func handleGroup(request rest.RequestApi, group *gin.RouterGroup) bool {
// get
if strings.Compare(request.Mode, "get") == 0 {
group.GET(request.RelativePath, request.HandleFunction)
return true
}
// post
if strings.Compare(request.Mode, "post") == 0 {
group.POST(request.RelativePath, request.HandleFunction)
return true
}
// delete
if strings.Compare(request.Mode, "delete") == 0 {
group.DELETE(request.RelativePath, request.HandleFunction)
return true
}
// put
if strings.Compare(request.Mode, "put") == 0 {
group.PUT(request.RelativePath, request.HandleFunction)
return true
}
return false
}
+158
View File
@@ -0,0 +1,158 @@
package middleware
import (
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"lingye-gin/src/config"
"lingye-gin/src/entity"
"net/http"
"strings"
"time"
)
// Jwt引擎
type JwtEngine struct {
}
// 认证请求头
const HeadAuthorization = "Authorization"
const HeadLingYe = "LingYe"
// Payload 载荷
// 继承jwt提供给载荷,扩展自己所需字段
type JwtClaims struct {
jwt.StandardClaims
UserId uint `json:"id"` // 用户ID
UserName string `json:"username"` // 用户名
NickName string `json:"nickname"` // 用户昵称
Email string `json:"email"` // 邮箱账号
UserRole []string `json:"userRoles"` // 用户角色编码合集
}
// 生成令牌
func (JwtEngine) CreateJwtToken(user entity.User, timeout int) (string, bool) {
// Jwt Secret 私钥
jwtSecret := config.AppProps.Jwt.Secret
// 过期时间
expiredAt := time.Now().Add(time.Hour * time.Duration(timeout)).Unix()
// 设置载荷
claims := JwtClaims{}
claims.UserId = user.ID
claims.UserName = user.UserName
claims.NickName = user.NickName
claims.Email = user.Email
claims.ExpiresAt = expiredAt
// claims.Issuer = "ginv" // 非必须,也可以填充用户名
// 生成令牌 采用HMAC SHA256算法加密
token := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
// 令牌签名
tokenString, err := token.SignedString([]byte(jwtSecret))
if err != nil {
return "", false
}
return tokenString, true
}
// 验证令牌
func (JwtEngine) validateJwt(tokenString string) (*JwtClaims, bool) {
// Jwt Secret 私钥
jwtSecret := config.AppProps.Jwt.Secret
// 解析令牌字符串
token, err := jwt.ParseWithClaims(tokenString, &JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(jwtSecret), nil
})
if err != nil {
config.Logger.Println(err)
return nil, false
}
// 获取载荷
claims, ok := token.Claims.(*JwtClaims)
if ok && token.Valid {
return claims, true
}
return nil, false
}
// 更新Token
func (engine JwtEngine) RefreshToken(tokenString string) (string, bool) {
// Jwt Secret 私钥
jwtSecret := config.AppProps.Jwt.Secret
jwt.TimeFunc = func() time.Time {
return time.Unix(0, 0)
}
// 解析令牌字符串
token, err := jwt.ParseWithClaims(tokenString, &JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(jwtSecret), nil
})
if err != nil {
config.Logger.Println(err)
return "", false
}
// 获取载荷
var claims *JwtClaims
var ok bool
if claims, ok = token.Claims.(*JwtClaims); ok && token.Valid {
jwt.TimeFunc = time.Now
// 过期时间
expiredAt := time.Now().Add(1 * time.Hour).Unix()
claims.StandardClaims.ExpiresAt = expiredAt
// 拷贝载体
currentUserInfo := entity.User{}
currentUserInfo.ID = claims.UserId
currentUserInfo.UserName = claims.UserName
currentUserInfo.NickName = claims.NickName
currentUserInfo.Email = claims.Email
return engine.CreateJwtToken(currentUserInfo, config.AppProps.Jwt.Expiry)
}
return "", false
}
// 初始化
func (engine JwtEngine) Init() {
config.Logger.Info("JwtEngine Init...")
config.JwtHandle = func(c *gin.Context) {
// 获取请求头中的Authorization
authorization := c.Request.Header.Get(HeadAuthorization)
if strings.Compare(authorization, "") == 0 {
c.JSON(http.StatusOK, gin.H{
"code": http.StatusUnauthorized,
"msg": "Authorization Header Is None, No Permission",
})
c.Abort()
return
}
// 拆分Authorization字段获取token字符串
strSlice := strings.SplitN(authorization, " ", 2)
if len(strSlice) != 2 || strings.Compare(HeadLingYe, strSlice[0]) != 0 {
c.JSON(http.StatusOK, gin.H{
"code": http.StatusUnauthorized,
"msg": "Authorization Header Format Is Error, No Permission",
})
c.Abort()
return
}
// 验证token字符串
claim, ok := engine.validateJwt(strSlice[1])
if !ok {
c.JSON(http.StatusOK, gin.H{
"code": http.StatusBadRequest,
"msg": "Token Validate Error",
})
c.Abort()
return
}
// 过期判断
if time.Now().Unix() > claim.ExpiresAt {
c.JSON(http.StatusOK, gin.H{
"code": http.StatusBadRequest,
"msg": "Token Is Expired",
})
c.Abort()
return
}
// 设置用户名
c.Set("username", claim.UserName)
c.Next()
}
config.Logger.Info("JwtEngine Ok...")
}
+355
View File
@@ -0,0 +1,355 @@
package middleware
import (
"fmt"
"github.com/go-redis/redis"
"lingye-gin/src/config"
"math/rand"
"time"
)
var RedisClient *redis.Client
type RedisPool struct{}
func (p RedisPool) Init() {
config.Logger.Info("RedisPool Init")
// 连接服务器
RedisClient = redis.NewClient(&redis.Options{
Addr: config.AppProps.Redis.Addr,
Password: config.AppProps.Redis.Passwd,
DB: config.AppProps.Redis.Database,
})
// 心跳
pong, err := RedisClient.Ping().Result()
// Output: PONG <nil>
config.Logger.Info("RedisPool Ping And ", pong, err)
config.Logger.Info("RedisPool Ok")
}
func (p RedisPool) Test() {
ExampleClient_String()
ExampleClient_List()
ExampleClient_Hash()
ExampleClient_Set()
ExampleClient_SortSet()
ExampleClient_HyperLogLog()
ExampleClient_CMD()
ExampleClient_Scan()
ExampleClient_Tx()
ExampleClient_Script()
ExampleClient_PubSub()
}
func ExampleClient_String() {
config.Logger.Println("ExampleClient_String")
defer config.Logger.Println("ExampleClient_String")
//kv读写
err := RedisClient.Set("key", "value", 1*time.Second).Err()
config.Logger.Println(err)
//获取过期时间
tm, err := RedisClient.TTL("key").Result()
config.Logger.Println(tm)
val, err := RedisClient.Get("key").Result()
config.Logger.Println(val, err)
val2, err := RedisClient.Get("missing_key").Result()
if err == redis.Nil {
config.Logger.Println("missing_key does not exist")
} else if err != nil {
config.Logger.Println("missing_key", val2, err)
}
//不存在才设置 过期时间 nx ex
value, err := RedisClient.SetNX("counter", 0, 1*time.Second).Result()
config.Logger.Println("setnx", value, err)
//Incr
result, err := RedisClient.Incr("counter").Result()
config.Logger.Println("Incr", result, err)
}
func ExampleClient_List() {
config.Logger.Println("ExampleClient_List")
defer config.Logger.Println("ExampleClient_List")
//添加
config.Logger.Println(RedisClient.RPush("list_test", "message1").Err())
config.Logger.Println(RedisClient.RPush("list_test", "message2").Err())
//设置
config.Logger.Println(RedisClient.LSet("list_test", 2, "message set").Err())
//remove
ret, err := RedisClient.LRem("list_test", 3, "message1").Result()
config.Logger.Println(ret, err)
rLen, err := RedisClient.LLen("list_test").Result()
config.Logger.Println(rLen, err)
//遍历
lists, err := RedisClient.LRange("list_test", 0, rLen-1).Result()
config.Logger.Println("LRange", lists, err)
//pop没有时阻塞
result, err := RedisClient.BLPop(1*time.Second, "list_test").Result()
config.Logger.Println("result:", result, err, len(result))
}
func ExampleClient_Hash() {
config.Logger.Println("ExampleClient_Hash")
defer config.Logger.Println("ExampleClient_Hash")
datas := map[string]interface{}{
"name": "LI LEI",
"sex": 1,
"age": 28,
"tel": 123445578,
}
//添加
if err := RedisClient.HMSet("hash_test", datas).Err(); err != nil {
config.Logger.Fatal(err)
}
//获取
rets, err := RedisClient.HMGet("hash_test", "name", "sex").Result()
config.Logger.Println("rets:", rets, err)
//成员
retAll, err := RedisClient.HGetAll("hash_test").Result()
config.Logger.Println("retAll", retAll, err)
//存在
bExist, err := RedisClient.HExists("hash_test", "tel").Result()
config.Logger.Println(bExist, err)
bRet, err := RedisClient.HSetNX("hash_test", "id", 100).Result()
config.Logger.Println(bRet, err)
//删除
config.Logger.Println(RedisClient.HDel("hash_test", "age").Result())
}
func ExampleClient_Set() {
config.Logger.Println("ExampleClient_Set")
defer config.Logger.Println("ExampleClient_Set")
//添加
ret, err := RedisClient.SAdd("set_test", "11", "22", "33", "44").Result()
config.Logger.Println(ret, err)
//数量
count, err := RedisClient.SCard("set_test").Result()
config.Logger.Println(count, err)
//删除
ret, err = RedisClient.SRem("set_test", "11", "22").Result()
config.Logger.Println(ret, err)
//成员
members, err := RedisClient.SMembers("set_test").Result()
config.Logger.Println(members, err)
bret, err := RedisClient.SIsMember("set_test", "33").Result()
config.Logger.Println(bret, err)
RedisClient.SAdd("set_a", "11", "22", "33", "44")
RedisClient.SAdd("set_b", "11", "22", "33", "55", "66", "77")
//差集
diff, err := RedisClient.SDiff("set_a", "set_b").Result()
config.Logger.Println(diff, err)
//交集
inter, err := RedisClient.SInter("set_a", "set_b").Result()
config.Logger.Println(inter, err)
//并集
union, err := RedisClient.SUnion("set_a", "set_b").Result()
config.Logger.Println(union, err)
ret, err = RedisClient.SDiffStore("set_diff", "set_a", "set_b").Result()
config.Logger.Println(ret, err)
rets, err := RedisClient.SMembers("set_diff").Result()
config.Logger.Println(rets, err)
}
func ExampleClient_SortSet() {
config.Logger.Println("ExampleClient_SortSet")
defer config.Logger.Println("ExampleClient_SortSet")
addArgs := make([]redis.Z, 100)
for i := 1; i < 100; i++ {
addArgs = append(addArgs, redis.Z{Score: float64(i), Member: fmt.Sprintf("a_%d", i)})
}
//Logger.Println(addArgs)
Shuffle := func(slice []redis.Z) {
r := rand.New(rand.NewSource(time.Now().Unix()))
for len(slice) > 0 {
n := len(slice)
randIndex := r.Intn(n)
slice[n-1], slice[randIndex] = slice[randIndex], slice[n-1]
slice = slice[:n-1]
}
}
//随机打乱
Shuffle(addArgs)
//添加
ret, err := RedisClient.ZAddNX("sortset_test", addArgs...).Result()
config.Logger.Println(ret, err)
//获取指定成员score
score, err := RedisClient.ZScore("sortset_test", "a_10").Result()
config.Logger.Println(score, err)
//获取制定成员的索引
index, err := RedisClient.ZRank("sortset_test", "a_50").Result()
config.Logger.Println(index, err)
count, err := RedisClient.SCard("sortset_test").Result()
config.Logger.Println(count, err)
//返回有序集合指定区间内的成员
rets, err := RedisClient.ZRange("sortset_test", 10, 20).Result()
config.Logger.Println(rets, err)
//返回有序集合指定区间内的成员分数从高到低
rets, err = RedisClient.ZRevRange("sortset_test", 10, 20).Result()
config.Logger.Println(rets, err)
//指定分数区间的成员列表
rets, err = RedisClient.ZRangeByScore("sortset_test", redis.ZRangeBy{Min: "(30", Max: "(50", Offset: 1, Count: 10}).Result()
config.Logger.Println(rets, err)
}
//用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
//每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数
func ExampleClient_HyperLogLog() {
config.Logger.Println("ExampleClient_HyperLogLog")
defer config.Logger.Println("ExampleClient_HyperLogLog")
for i := 0; i < 10000; i++ {
RedisClient.PFAdd("pf_test_1", fmt.Sprintf("pfkey%d", i))
}
ret, err := RedisClient.PFCount("pf_test_1").Result()
config.Logger.Println(ret, err)
for i := 0; i < 10000; i++ {
RedisClient.PFAdd("pf_test_2", fmt.Sprintf("pfkey%d", i))
}
ret, err = RedisClient.PFCount("pf_test_2").Result()
config.Logger.Println(ret, err)
RedisClient.PFMerge("pf_test", "pf_test_2", "pf_test_1")
ret, err = RedisClient.PFCount("pf_test").Result()
config.Logger.Println(ret, err)
}
func ExampleClient_PubSub() {
config.Logger.Println("ExampleClient_PubSub")
defer config.Logger.Println("ExampleClient_PubSub")
//发布订阅
pubsub := RedisClient.Subscribe("subkey")
_, err := pubsub.Receive()
if err != nil {
config.Logger.Fatal("pubsub.Receive")
}
ch := pubsub.Channel()
time.AfterFunc(1*time.Second, func() {
config.Logger.Println("Publish")
err = RedisClient.Publish("subkey", "test publish 1").Err()
if err != nil {
config.Logger.Fatal("RedisClient.Publish", err)
}
RedisClient.Publish("subkey", "test publish 2")
})
for msg := range ch {
config.Logger.Println("recv channel:", msg.Channel, msg.Pattern, msg.Payload)
}
}
func ExampleClient_CMD() {
config.Logger.Println("ExampleClient_CMD")
defer config.Logger.Println("ExampleClient_CMD")
//执行自定义redis命令
Get := func(rdb *redis.Client, key string) *redis.StringCmd {
cmd := redis.NewStringCmd("get", key)
RedisClient.Process(cmd)
return cmd
}
v, err := Get(RedisClient, "NewStringCmd").Result()
config.Logger.Println("NewStringCmd", v, err)
v, err = RedisClient.Do("get", "RedisClient.do").String()
config.Logger.Println("RedisClient.Do", v, err)
}
func ExampleClient_Scan() {
config.Logger.Println("ExampleClient_Scan")
defer config.Logger.Println("ExampleClient_Scan")
//scan
for i := 1; i < 1000; i++ {
RedisClient.Set(fmt.Sprintf("skey_%d", i), i, 0)
}
cusor := uint64(0)
for {
keys, retCusor, err := RedisClient.Scan(cusor, "skey_*", int64(100)).Result()
config.Logger.Println(keys, cusor, err)
cusor = retCusor
if cusor == 0 {
break
}
}
}
func ExampleClient_Tx() {
pipe := RedisClient.TxPipeline()
incr := pipe.Incr("tx_pipeline_counter")
pipe.Expire("tx_pipeline_counter", time.Hour)
// Execute
//
// MULTI
// INCR pipeline_counter
// EXPIRE pipeline_counts 3600
// EXEC
//
// using one rdb-server roundtrip.
_, err := pipe.Exec()
fmt.Println(incr.Val(), err)
}
func ExampleClient_Script() {
IncrByXX := redis.NewScript(`
if redis.call("GET", KEYS[1]) ~= false then
return redis.call("INCRBY", KEYS[1], ARGV[1])
end
return false
`)
n, err := IncrByXX.Run(RedisClient, []string{"xx_counter"}, 2).Result()
fmt.Println(n, err)
err = RedisClient.Set("xx_counter", "40", 0).Err()
if err != nil {
panic(err)
}
n, err = IncrByXX.Run(RedisClient, []string{"xx_counter"}, 2).Result()
fmt.Println(n, err)
}