go mod init gin-ranking
go: creating new go.mod: module gin-ranking
go: to add module requirements and sums:
go mod tidy
下载gin框架
cmd窗口中执行命令:
go get -u github.com/gin-gonic/gin
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/hello", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "hello world!")
})
r.POST("/user/list", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user list!")
})
r.PUT("/user/add", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user add !")
})
r.DELETE("/user/delete", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user delete!")
})
r.Run(":9999")
}
运行
go run main.go
也可以支持分组
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/hello", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "hello world!")
})
user := r.Group("/user")
{
user.POST("/list", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user list!")
})
user.PUT("/add", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user add !")
})
user.DELETE("/delete", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user delete!")
})
}
r.Run(":9999")
}
如果路由有很多个都放在main.go文件中不太好
封装Json 返回统一格式
main.go
package main
import "gin-ranking/router"
func main() {
r := router.Router()
r.Run(":9999")
}
router.go
package router
import (
"gin-ranking/controllers"
"github.com/gin-gonic/gin"
"net/http"
)
func Router() *gin.Engine {
r := gin.Default()
user := r.Group("/user")
{
user.GET("/info", controllers.GetUserInfo)
user.POST("/list", controllers.GetList)
user.PUT("/add", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user add !")
})
user.DELETE("/delete", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user delete!")
})
}
return r
}
user.go
package controllers
import "github.com/gin-gonic/gin"
func GetUserInfo(c *gin.Context) {
ReturnSuccess(c, 0, "success", "user info", 1)
}
func GetList(c *gin.Context) {
ReturnError(c, 404, "没有相关信息")
}
common.go
package controllers
import "github.com/gin-gonic/gin"
type JsonStruct struct {
Code int `json:"code"`
Msg interface{} `json:"msg"`
Data interface{} `json:"data"`
Count int64 `json:"count"`
}
type JsonErrStruct struct {
Code int `json:"code"`
Msg interface{} `json:"msg"`
}
func ReturnSuccess(c *gin.Context, code int, msg interface{}, data interface{}, count int64) {
json := &JsonStruct{
Code: code, Msg: msg, Data: data, Count: count,
}
c.JSON(200, json)
}
func ReturnError(c *gin.Context, code int, msg interface{}) {
json := &JsonErrStruct{Code: code, Msg: msg}
c.JSON(200, json)
}
127.0.0.1:9999/user/info
{
"code": 0,
"msg": "success",
"data": "user info",
"count": 1
}
127.0.0.1:9999/user/list
{
"code": 404,
"msg": "没有相关信息"
}
但是有个问题,如果在别的包中调用同一个方法就会报错,可以借用结构体
router.go
package router
import (
"gin-ranking/controllers"
"github.com/gin-gonic/gin"
"net/http"
)
func Router() *gin.Engine {
r := gin.Default()
user := r.Group("/user")
{
user.GET("/info", controllers.UserController{}.GetUserInfo)
user.POST("/list", controllers.UserController{}.GetList)
user.PUT("/add", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user add !")
})
user.DELETE("/delete", func(ctx *gin.Context) {
ctx.String(http.StatusOK, "user delete!")
})
}
order := r.Group("/order")
{
order.POST("/list", controllers.OrderController{}.GetList)
}
return r
}
order.go
package controllers
import "github.com/gin-gonic/gin"
type OrderController struct {
}
func (o OrderController) GetList(c *gin.Context) {
ReturnError(c, 404, "没有相关信息 order")
}
user.go
package controllers
import "github.com/gin-gonic/gin"
type UserController struct {
}
func (u UserController) GetUserInfo(c *gin.Context) {
ReturnSuccess(c, 0, "success", "user info", 1)
}
func (u UserController) GetList(c *gin.Context) {
ReturnError(c, 404, "没有相关信息")
}
获取请求参数并和struct结构体绑定
1.get 请求 携带路由参数
Post传递表单类型的参数
传递json类型的数据
通过定义结构体的方式传递
自定义Logger中间件实现日志收集
根目录下新建 runtime/log 目录用以保存生成的日志
根目录下新建pkg/logger/logger.go
package logger
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"io"
"net/http"
"os"
"path"
"runtime/debug"
"time"
)
func init() {
// 设置日志格式为json格式
logrus.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006-01-02 15:04:05",
})
logrus.SetReportCaller(false)
}
func Write(msg string, filename string) {
setOutPutFile(logrus.InfoLevel, filename)
logrus.Info(msg)
}
func Debug(fields logrus.Fields, args ...interface{}) {
setOutPutFile(logrus.DebugLevel, "debug")
logrus.WithFields(fields).Debug(args)
}
func Info(fields logrus.Fields, args ...interface{}) {
setOutPutFile(logrus.InfoLevel, "info")
logrus.WithFields(fields).Info(args)
}
func Warn(fields logrus.Fields, args ...interface{}) {
setOutPutFile(logrus.WarnLevel, "warn")
logrus.WithFields(fields).Warn(args)
}
func Fatal(fields logrus.Fields, args ...interface{}) {
setOutPutFile(logrus.FatalLevel, "fatal")
logrus.WithFields(fields).Fatal(args)
}
func Error(fields logrus.Fields, args ...interface{}) {
setOutPutFile(logrus.ErrorLevel, "error")
logrus.WithFields(fields).Error(args)
}
func Panic(fields logrus.Fields, args ...interface{}) {
setOutPutFile(logrus.PanicLevel, "panic")
logrus.WithFields(fields).Panic(args)
}
func Trace(fields logrus.Fields, args ...interface{}) {
setOutPutFile(logrus.TraceLevel, "trace")
logrus.WithFields(fields).Trace(args)
}
func setOutPutFile(level logrus.Level, logName string) {
if _, err := os.Stat("./runtime/log"); os.IsNotExist(err) {
err = os.MkdirAll("./runtime/log", 0777)
if err != nil {
panic(fmt.Errorf("create log dir '%s' error: %s", "./runtime/log", err))
}
}
timeStr := time.Now().Format("2006-01-02")
fileName := path.Join("./runtime/log", logName+"_"+timeStr+".log")
var err error
os.Stderr, err = os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
fmt.Println("open log file err", err)
}
logrus.SetOutput(os.Stderr)
logrus.SetLevel(level)
return
}
func LoggerToFile() gin.LoggerConfig {
if _, err := os.Stat("./runtime/log"); os.IsNotExist(err) {
err = os.MkdirAll("./runtime/log", 0777)
if err != nil {
panic(fmt.Errorf("create log dir '%s' error: %s", "./runtime/log", err))
}
}
timeStr := time.Now().Format("2006-01-02")
fileName := path.Join("./runtime/log", "success_"+timeStr+".log")
os.Stderr, _ = os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
var conf = gin.LoggerConfig{
Formatter: func(param gin.LogFormatterParams) string {
return fmt.Sprintf("%s - %s \"%s %s %s %d %s \"%s\" %s\"\n",
param.TimeStamp.Format("2006-01-02 15:04:05"),
param.ClientIP,
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
},
Output: io.MultiWriter(os.Stdout, os.Stderr),
}
return conf
}
func Recover(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
if _, errDir := os.Stat("./runtime/log"); os.IsNotExist(errDir) {
errDir = os.MkdirAll("./runtime/log", 0777)
if errDir != nil {
panic(fmt.Errorf("create log dir '%s' error: %s", "./runtime/log", errDir))
}
}
timeStr := time.Now().Format("2006-01-02")
fileName := path.Join("./runtime/log", "error_"+timeStr+".log")
f, errFile := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if errFile != nil {
fmt.Println(errFile)
}
timeFileStr := time.Now().Format("2006-01-02 15:04:05")
f.WriteString("panic error time:" + timeFileStr + "\n")
f.WriteString(fmt.Sprintf("%v", err) + "\n")
f.WriteString("stacktrace from panic:" + string(debug.Stack()) + "\n")
f.Close()
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": fmt.Sprintf("%v", err),
})
//终止后续接口调用,不加的话recover到异常后,还会继续执行接口里后续代码
c.Abort()
}
}()
c.Next()
}
直接在方法中调用
引入Gorm
根目录新建config/db.go
根目录新建dao/dao.go
package dao
import (
"gin-ranking/config"
"gin-ranking/pkg/logger"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"time"
)
var (
Db *gorm.DB
err error
)
func init() {
Db, err = gorm.Open("mysql", config.Mysqldb)
if err != nil {
logger.Error(map[string]interface{}{"mysql connect error": err.Error()})
}
if Db.Error != nil {
logger.Error(map[string]interface{}{"database error": Db.Error})
}
// ----------------------- 连接池设置 -----------------------
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
Db.DB().SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量。
Db.DB().SetMaxOpenConns(100)
// SetConnMaxLifetime 设置了连接可复用的最大时间。
Db.DB().SetConnMaxLifetime(time.Hour)
}
新建models/user 测试
在请求方法中直接调用
新增用户
更新数据
删除
查询多条数据
models
func GerUserListTest() ([]User, error) {
var users []User
err := dao.Db.Where("id<?", 3).Find(&users).Error
return users, err
}
controllers
func (u UserController) GerUserListTest(c *gin.Context) {
users, err := models.GerUserListTest()
if err != nil {
ReturnError(c, 4004, "删除失败")
return
}
ReturnSuccess(c, 0, "删除成功", users, 1)
}