日志的处理
使用的并不是gin框架自带的logger包,而是logrus
,还用到了分割日志的包
go get github.com/sirupsen/logrus
// 分割日志
go get github.com/lestrrat-go/file-rotatelogs
// 分段记录
go get github.com/rifflock/lfshook
在根目录下新建一个log文件夹,然后在middleware下新建一个logger.go
文件,来写日志中间件。
package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
retalog "github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"math"
"os"
"time"
)
func Logger() gin.HandlerFunc {
// 定义文件路径
filePath := "log/blog.log"
// 软连接路径(可以根据运维来进行调整)
// linkName := "latest_log.log"
// 初始化
logger := logrus.New()
// 定位到log文件夹(路径,os新建文件,赋值权限)
src,err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0755)
if err!=nil {
fmt.Println(err)
}
// 输出到日志文件中
logger.Out = src
logger.SetLevel(logrus.DebugLevel)
logWriter, _ := retalog.New(
filePath+"%Y%m%d.log",
retalog.WithMaxAge(7*24*time.Hour),
retalog.WithRotationTime(24*time.Hour),
// retalog.WithLinkName(linkName),
)
// 日志级别
writeMap := lfshook.WriterMap{
logrus.InfoLevel: logWriter,
logrus.FatalLevel: logWriter,
logrus.DebugLevel: logWriter,
logrus.WarnLevel: logWriter,
logrus.ErrorLevel: logWriter,
logrus.PanicLevel: logWriter,
}
// 时间格式化分割
Hook := lfshook.NewHook(writeMap, &logrus.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05",
})
logger.AddHook(Hook)
return func(c *gin.Context) {
// 输出开始时间
startTime := time.Now()
c.Next()
// 结束时间运行时间
stopTime := time.Since(startTime)
spendTime := fmt.Sprintf("%d ms", int(math.Ceil(float64(stopTime.Nanoseconds())/1000000.0)))
// 主机名
hostName, err := os.Hostname()
if err != nil {
hostName = "unKnown"
}
// 状态码
statusCode := c.Writer.Status()
// 客户端ip
clientIP := c.ClientIP()
// 客户端信息
userAgent := c.Request.UserAgent()
// 请求大小
dataSize := c.Writer.Size()
if dataSize < 0{
dataSize = 0
}
// 请求方法和路径
method := c.Request.Method
path := c.Request.RequestURI
// 组合数据
entry := logger.WithFields(logrus.Fields{
"HostName":hostName,
"Status":statusCode,
"SpendTime":spendTime,
"IP":clientIP,
"Method":method,
"Path":path,
"DataSize":dataSize,
"Agent": userAgent,
})
// 分级别
if len(c.Errors) > 0{
entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
}
if statusCode >= 500{
entry.Error()
}else if statusCode >= 400{
entry.Warn()
}else {
entry.Info()
}
}
}
然后将router.go
下实例的r改为New方法
func InitRouter() {
gin.SetMode(utils.AppMode)
r := gin.New()
r.Use(middleware.Logger())
r.Use(gin.Recovery())
Auth := r.Group("api/admin")
Auth.Use(middleware.JwtToken())
{
// User模块的路由接口
Auth.PUT("user/:id/", v1.EditUser)
Auth.DELETE("user/:id/", v1.DeleteUser)
// Category模块的路由接口
Auth.POST("category/", v1.AddCategory)
Auth.PUT("category/:id/", v1.EditCategory)
Auth.DELETE("category/:id/", v1.DeleteCategory)
// Article模块的路由接口
Auth.POST("article/", v1.AddArticle)
Auth.PUT("article/:id/", v1.EditArticle)
Auth.DELETE("article/:id/", v1.DeleteArticle)
Auth.POST("upload/", v1.UploadFile)
}
router := r.Group("api/v1")
{
router.GET("user/", v1.GetUsers)
Auth.POST("user/", v1.AddUser)
router.POST("login/", v1.Login)
router.GET("category/", v1.GetCategorys)
router.GET("category/:id/", v1.GetCateInfo)
router.GET("article/", v1.GetArticles)
router.GET("article/:id/", v1.GetArticleInfo)
router.GET("catelist/:id/", v1.GetCateArt)
}
_ = r.Run(utils.HttpPort)
}
跨域配置与数据限制
数据限制
go get github.com/go-playground/locales/zh_Hans_CN@v0.13.0
go get github.com/gin-contrib/cors
数据限制,改造model/User.go
,添加validate。
type User struct {
gorm.Model
Username string `gorm:"type:varchar(20);not null " json:"username" validate:"required,min=4,max=12" label:"用户名"`
Password string `gorm:"type:varchar(500);not null" json:"password" validate:"required,min=6,max=120" label:"密码"`
Avatar string `gorm:"type:varchar(40);not null" json:"avatar" label:"头像"`
Role int `gorm:"type:int;DEFAULT:2" json:"role" validate:"required,gte=2" label:"角色"`
}
在utils下,新建validator文件夹和文件
package validator
import (
"blog/utils/errmsg"
"fmt"
"github.com/go-playground/locales/zh_Hans_CN"
unTrans "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zhTrans "github.com/go-playground/validator/v10/translations/zh"
"reflect"
)
func Validate(data interface{}) (string, int) {
validate := validator.New()
uni := unTrans.New(zh_Hans_CN.New())
trans, _ := uni.GetTranslator("zh_Hans_CN")
err := zhTrans.RegisterDefaultTranslations(validate, trans)
if err != nil {
fmt.Println("err:", err)
}
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
label := field.Tag.Get("label")
return label
})
err = validate.Struct(data)
if err != nil {
for _, v := range err.(validator.ValidationErrors) {
return v.Translate(trans), errmsg.ERROR
}
}
return "", errmsg.SUCCSE
}
工具写好后,在api/user.go
使用验证,保证添加的数据是正确的。
func AddUser(c *gin.Context) {
var data model.User
var msg string
_ = c.ShouldBindJSON(&data)
msg, code = validator.Validate(&data)
if code != errmsg.SUCCSE {
c.JSON(
http.StatusOK, gin.H{
"status": code,
"message": msg,
},
)
c.Abort()
return
}
code = model.CheckUser(data.Username)
if code == errmsg.SUCCSE {
model.CreateUser(&data)
}
if code == errmsg.ERROR_USERNAME_USED {
code = errmsg.ERROR_USERNAME_USED
}
c.JSON(http.StatusOK,gin.H{
"code":code,
"msg":errmsg.GetErrorMsg(code),
"data":data,
})
}
跨域配置
在middleware下,新建cors.go文件,编写跨域中间件
package middleware
import (
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"time"
)
func Cors() gin.HandlerFunc {
return cors.New(
cors.Config{
AllowAllOrigins: true,
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"*"},
ExposeHeaders: []string{"Content-Length", "text/plain", "Authorization", "Content-Type"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
},
)
}
和之前的中间件一样在router中配置即可。
大体功能基本实现,在后期可能会加一些新的,不断的完善,不过目前这种程度就已经能够做一个博客了,后期项目先到此为止,然后前端的话,使用vue来做,未完待续…
- Post link: https://www.godhearing.cn/gin-vue-da-jian-ge-ren-bo-ke-5/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.