基于 gin框架搭建入门项目

news2024/11/20 9:38:08
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)

}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1081407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

圭亚那奥罗拉金矿配电工程中AM5SE系列微机保护装置

安科瑞 崔丽洁 摘要&#xff1a;目前&#xff0c;微机保护装置广泛应用于电力系统中&#xff0c;该类装置能够有效监测电力系统的运行状况&#xff0c;并实时记录电力系统出现故障的位置及性质&#xff0c;从而为故障的快速处理提供有效的参考信息。本文介绍的AM5SE系列微机保…

android:can not find libdevapi.so

一、为什么会出现这样的报错&#xff1f; 引用了一些第三方的sdk的so库之后通常都会遇到这样的错误&#xff0c;&#xff08;“nativeLibraryDirectories”[/data/app/com.lukouapp-1/lib/arm64, /vendor/lib64, /system/lib64]]] couldnt find "libxxxx.so"&#x…

zookeeper节点数据类型介绍及集群搭建

一、zookeeper介绍 zookeeper官网&#xff1a;Apache ZooKeeper zookeeper是一个分布式协调框架&#xff0c;保证的是CP&#xff0c;即一致性和分区容错性&#xff1b;zookeeper是一个分布式文件存储系统&#xff0c;文件节点可以存储数据&#xff0c;监听子文件节点等可以实…

绥化市中心广场焕发新活力:OLED透明拼接屏的奇观展示

OLED透明拼接屏技术在绥化城市的应用引起了广泛关注。 绥化市位于中国东北地区&#xff0c;是黑龙江省的一个重要城市。 该市拥有悠久的历史&#xff0c;历经多个朝代的兴衰。绥化的历史背景赋予了这座城市独特的文化底蕴和魅力。 绥化市内有许多著名景点&#xff0c;其中最…

day

#include <iostream> using namespace std; class Per {//算术运算符friend const Per operator(const Per &k1,const Per &k2);friend const Per operator-(const Per &k1,const Per &k2);friend const Per operator*(const Per &k1,const Per &…

vue项目npm intall时发生版本冲突的解决办法

在日常使用命令npm install / npm install XX下载依赖的操作中&#xff0c;我经常会遇到无法解析依赖树的问题&#xff08;依赖冲突&#xff09; 当遇到这种情况的时候&#xff0c;可以通过以下命令完成依赖安装&#xff1a; npm install --legacy-peer-deps npm install xxx…

国产化即时通讯平台WorkPlus,助力企业实现自主可控的沟通与协作

作为在线沟通与协作的重要工具&#xff0c;即时通讯平台在企业中扮演着不可或缺的角色。然而&#xff0c;为了保护企业的核心数据和机密信息&#xff0c;越来越多的企业开始转向国产化的即时通讯平台。在这一背景下&#xff0c;国内软件品牌WorkPlus应运而生&#xff0c;为企业…

基于 chinese-roberta-wwm-ext 微调训练中文命名实体识别任务

一、模型和数据集介绍 1.1 预训练模型 chinese-roberta-wwm-ext 是基于 RoBERTa 架构下开发&#xff0c;其中 wwm 代表 Whole Word Masking&#xff0c;即对整个词进行掩码处理&#xff0c;通过这种方式&#xff0c;模型能够更好地理解上下文和语义关联&#xff0c;提高中文文…

mongodb简介、安装、搭建复制集

一、 简介 NoSQL数据库四大家族&#xff1a;列存储 Hbase&#xff0c;键值(Key-Value)存储 Redis&#xff0c;图像存储 Neo4j&#xff0c;基于分布式文档存储的数据库MongoDb。 MongoDB 和关系型数据库对比 关系型数据库MongoDBdatabase&#xff08;库&#xff09;database&…

.net也能写内存挂

最近在研究.net的内存挂。 写了很久的c,发现c#写出来的东西实在太香。 折腾c#外挂已经有很长时间了。都是用socket和c配合。 这个模式其实蛮成功的&#xff0c;用rpc调用的方式加上c#的天生await 非常好写逻辑 类似这样 最近想换个口味。注入托管dll到非托管进程 这样做只…

基于 SOFAJRaft 实现注册中心

文章目录 1.前言2.git 示例地址3.官网示例分析3.SOFAJRAFT 注册中心实现&#xff08;服务端&#xff09;3.1 核心功能3.2 模块设计3.3 请求消息数据结构设计3.3.1 Registration 注册消息3.3.2 GetServiceInstancesRequest 获取服务实例请求3.3.3 GetServiceInstancesResponse 获…

Android中级——ListView和RecycleView解析

ListView和RecycleView ListViewRecycleView ListView 使用步骤可看Android基础——ListView&#xff0c;其setAdapter()如下&#xff0c;回调getCount()获取Item个数 Override public void setAdapter(ListAdapter adapter) {if (mAdapter ! null && mDataSetObserv…

v-model绑定input、textarea、checkbox、radio、select

1.input <div><!-- v-model绑定input --><input type"text" v-model"message"><h2>{{message}}</h2></div><script>const App{template:#my-app,data() {return {message:Hello World,}},}Vue.createApp(App).…

Java:设计模式之结构型-装饰者模式(decorator pattern)

装饰者模式(decorator pattern): 动态地将责任附加到对象上 意图&#xff1a;为对象动态添加功能 类图 实现 设计不同种类的饮料&#xff0c;饮料可以添加配料&#xff0c;比如可以添加牛奶&#xff0c;并且支持动态添加新配料。每增加一种配料&#xff0c;该饮料的价格就…

微信怎么查看名下所有微信号?

一般大家都会有两个或者更多的微信号&#xff0c;那怎么知道自己名下有几个微信号呢&#xff1f; 微信号要使用支付或者其他一些功能是要实名才可以使用的&#xff0c;有时候不知道自己的名下绑定了多少微信号&#xff0c;怎么查询呢&#xff1f; 微信最近出了开通小号的功能&…

当下测试行业中UI自动化面临的难点及如何解决

经常有人会问&#xff0c;什么样的项目才适合进行UI自动化测试呢&#xff1f;UI自动化测试相当于模拟手工测试&#xff0c;通过程序去操作页面上的控件。而在实际测试过程中&#xff0c;经常会遇到无法找到控件&#xff0c;或者因控件定义变更而带来的维护成本等问题。 哪些场…

Python数组添加元素append的时间复杂度分析

由于数组需要连续的存储空间&#xff0c;append&#xff08;&#xff09;函数的时间复杂度可能为1也可能为n&#xff0c;主要看在后面添加元素时&#xff0c;当前位置是否可以添加&#xff0c;有位置可以添加的话&#xff0c;则直接在后面添加&#xff0c;此时时间复杂度为1&am…

工学云打卡签到自动完成在异地的问题就解决了|蘑菇钉

工学云打卡助手&#xff0c;能解决你在异地时每天不间断签到的问题&#xff0c;仔细看图哦 1.自动签到 2.自定义打卡地区 3.生成日周月报与总结自动发表 4.支持随机通用内容 5.支持打卡结果推送 对于许多即将步入职场的新人来说&#xff0c;实习是一个非常重要的阶段。实习…

【算法挨揍日记】day13—— DP34 【模板】前缀和、DP35 【模板】二维前缀和

DP34 【模板】前缀和 【模板】前缀和_牛客题霸_牛客网 题目描述&#xff1a; 给定一个长度为n的数组. 接下来有q次查询, 每次查询有两个参数l, r. 对于每个询问, 请输出 输入描述: 第一行包含两个整数n和q.第二行包含n个整数, 表示.接下来q行,每行包含两个整数 l和r. …

聊聊Android签名检测7种核心检测方案详解

聊聊Android签名检测总结与反思 背景&#xff1a; 这篇文章只讲Android端签名检测&#xff0c;安卓发展到现在&#xff0c;因为国内环境没有谷歌市场&#xff0c;所以很多官方推荐的Api没法使用 &#xff0c;所以国内的签名检测方式也是“千奇百怪” 。发展至今每种方法都有一…