需求说明
- 管理后台所有修改,添加,删除的操作都要记录
- 操作日志的统计不影响主程序的性能
需求分析
- 把相关代码封装成中间件,独立使用
- 合理使用goroutine,不影响主线程的性能
文档说明
- 基于golang语言开发
- 基于gin网络框架开发
- 基于MySQL5.8开发
- 把操作日志部分封装成中间件,在rourter文件中引用
- 非核心代码已省略,用3个竖着排列的点号.表示
数据库表结构设置
操作日志表
代码
中间件代码
代码分析
- 我们可以通过context直接获得请求方式和请求的url
- 无法直接获得返回信息,我们可以借助"ResponseWriter",运用拦截器的思想,把返回信息先截取到,再向下继续传递
- 像获得客户端ip这类方法封装到util中,方便灵活调用
- 我们无法将adminLogs()方法整体设置为goroutine,因为这样会将context的事件传递在新的协程中进行,无法正常传递。
- 所以我们再c.Next()事件传递之后,把json解析成结构体,以及保存操作日志到数据库的操作设置为使用goroutine协程操作
- 操作日志是没有比较记录查询操作的,所以我们把请求方式为GET的过滤掉
package middleware
//amdin操作日志
import (
.
.
.
"bytes"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"strings"
)
type bodyLogWriter struct {
gin.ResponseWriter
bodyBuf *bytes.Buffer
}
func (w bodyLogWriter) Write(b []byte) (int, error) {
w.bodyBuf.Write(b)
return w.ResponseWriter.Write(b)
}
var CommonLogInterceptor = commonLogInterceptor()
/*
1 使用goroutine和channel实现操作日志的入库保存,尽可能的不影响主程序
2 goroutine协程,提高并发量
3 channel通道
*/
func commonLogInterceptor() gin.HandlerFunc {
return func(c *gin.Context) {
adminLogs(c)
}
}
//获得每次请求返回的code和message
func adminLogs(c *gin.Context) {
if admin, _ := c.Get("admin"); admin != nil {
method := c.Request.Method
url := c.Request.URL.Path
strBody := ""
var blw bodyLogWriter
blw = bodyLogWriter{bodyBuf: bytes.NewBufferString(""), ResponseWriter: c.Writer}
c.Writer = blw
c.Next()
if method != "GET" {
strBody = strings.Trim(blw.bodyBuf.String(), "n")
go func(strBody string) {
var returnJson api.ReturnJson
json.Unmarshal([]byte(strBody), &returnJson)
message := fmt.Sprintf("%v", returnJson.Message)
adminInfo := admin.(**service.RunningClaims)
adminId := (*adminInfo).ID
adminName := (*adminInfo).Account
var log = model.AdminLog{
AdminId: adminId,
AdminName: adminName,
Method: method,
Url: url,
Ip: util.RemoteIP(c.Request),
Code: returnJson.Code,
Message: message,
}
model.CreateLog(log)
}(strBody)
}
}
}
model层代码
代码语言:javascript复制package model
type AdminLog struct {
ID int `json:"id"`
AdminId uint `json:"admin_id"`
AdminName string `json:"admin_name"`
Method string `json:"method"`
Ip string `json:"ip"`
Url string `json:"url"`
Code int `json:"code"`
Message string `json:"message"`
}
func CreateLog(log AdminLog) {
DB.Create(&log)
}
路由代码
代码语言:javascript复制package server
import (
.
.
.
"os"
"github.com/gin-gonic/gin"
)
// NewRouter 路由配置
func NewRouter() *gin.Engine {
r := gin.Default()
// 其他中间件
.
.
.
// 路由
v1 := r.Group("/api/v1")
{
v1.POST("login", api.Login)
auth := v1.Group("")
//登录校验中间件
auth.Use(middleware.AuthRequired())
//关键代码:权限角色校验
auth.Use(middleware.AuthCheckMiddleware)
//操作日志
auth.Use(middleware.CommonLogInterceptor)
{
.
.
.
// 获取所有学校
{
auth.GET("/school/", api.GetSchoolInfo)
}
.
.
.
}
}
return r
}
总结
- 以上则是我的实现思路
- 还有另外一种思路,计划已消息队列的方式实现,发送通知进行日志的报错
相关文章
- GO部分打算做成一个系列,最终把封装好的代码开源出来
- 上一篇:你用Go写过中间件吗?带你用Gin实现【用户角色权限管理中间件】
联系我
如果有更好的实现思路,或者项目合作,可以私信我或者在文章底部留言。