优秀的编程知识分享平台

网站首页 > 技术文章 正文

golang+gin+gorm实现一个短链服务(中)

nanyue 2024-09-09 04:58:17 技术文章 9 ℃

mysql数据表初始化

通过Navicat连接上mysql新建一个数据库

编辑配置文件config.yaml

mysql_config:
  user: 'root'
  password: '123456'
  host: '127.0.0.1'
  port: '3307'
  db_name: "short_chain"

我们在config下面新建一个config.go的文件

代码如下:

package config

type SysConfig struct {
	MysqlConfig MysqlConfig `yaml:"mysql_config"`

}
type MysqlConfig struct {
	User     string `yaml:"user"`
	Password string `yaml:"password"`
	Host     string `yaml:"host"`
	Port     string `yaml:"port"`
	DbName   string `yaml:"db_name"`
}

接着我们需要初始化一下这个配置文件 在initializes 下新建一个init_config.go的文件

package initializes

import (
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
	"short_chain/config"
)

func InitConfig()  {
	configs := new(config.SysConfig)
	yamlFile, err := ioutil.ReadFile("./config.yaml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
		return
	}

	err = yaml.Unmarshal(yamlFile, configs)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
	}
	
}

虽然我们已经把config.yaml文件解析到config上了,但是我们外部是获取不到的,所以这里我们新建一个全局变量

在global文件夹下新建一个global.go的文件

代码如下:

package global

import "short_chain/config"

var(
	SysConfig *config.SysConfig
)

然后我们返回修改初始化解析配置文件的代码:

package initializes

import (
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
	"short_chain/config"
	"short_chain/global"
)

func InitConfig()  {
	configs := new(config.SysConfig)
	yamlFile, err := ioutil.ReadFile("./config.yaml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
		return
	}
	err = yaml.Unmarshal(yamlFile, configs)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
	}
	global.SysConfig=configs
}

接下来我们初始化我们的mysql链接

我们需要定义一个全局的db变量 也就是mysql的连接

package global

import (
	"gorm.io/gorm"
	"short_chain/config"
)

var(
	SysConfig *config.SysConfig
	Db *gorm.DB
)

接着我们在initializes文件夹下面新建一个init_mysql.go的文件

代码如下:

package initializes

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"short_chain/global"
)

func InitMysql()  {
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		logger.Config{},
	)
	mysqlUrl := fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local",
		global.SysConfig.MysqlConfig.User,
		global.SysConfig.MysqlConfig.Password,
		global.SysConfig.MysqlConfig.Host,
		global.SysConfig.MysqlConfig.Port,
		global.SysConfig.MysqlConfig.DbName,
	)
	var err error
	DB, err := gorm.Open(mysql.Open(mysqlUrl), &gorm.Config{Logger: newLogger})
	if err != nil {
		fmt.Println("数据库连接失败")
	}
	sqlDb, _ := DB.DB()
	sqlDb.SetMaxIdleConns(200) //设置最大连接数
	sqlDb.SetMaxOpenConns(200) //设置最大的空闲连接数
	global.Db=DB
}

然后我们在runserver里面去调用它

package initializes

func RunServe()  {
	InitConfig()
	InitMysql()
	InitRouter()
}

上面的做完以后我们就可以创建表了

在models里面创建一个table的文件夹

在table新建一个short_chain_data.go的文件

代码如下:

package table

import (
	"gorm.io/gorm"
	"short_chain/models"
)

type ShortChainData struct {
	gorm.Model
	ShortId string `gorm:"size:255;comment:'短链id'" json:"short_id"`
	OriginalLink string `gorm:"text;comment:'原始链接'" json:"original_link"`
	MappingLinks string `gorm:"size:255;comment:'映射链接'" json:"mapping_links"`
}

func (ShortChainData) TableName() string  {
	return "short_chain_data"
}


然后我们在initializes文件夹下新建一个初始化init_table.go的文件

package initializes

import (
	"short_chain/global"
	"short_chain/models/table"
)

func InitTable() {
	db := global.Db
	db.AutoMigrate(
		table.ShortChainData{},
	)
}

然后我们在runserver里面调用它

让我们让是运行一下看看是否创建了表

通过运行以后可以看到创建了我们所需要的表


业务层

那么接下来我们就需要开发接口了

首先我们在service里面创建一个short_chain_data.go的文件

package services

import (
	"github.com/gin-gonic/gin"
	"short_chain/models/table"
)

type Service struct {
	table.ShortChainData
	Page int `json:"page"`
	Size int `json:"size"`
}
//添加短链
func (c *Service) Add(g *gin.Context)  {
	
}
//编辑短链短链
func (c *Service) Update(g *gin.Context)  {

}
//查询短链列表
func (c *Service) List(g *gin.Context)  {

}
//删除短链
func (c *Service) Delete(g *gin.Context)  {

}
//短链映射
func (c *Service) Mapping(g *gin.Context)  {
	
}

在写这些功能之前我们先去封装一些model模块的常用函数

我们在models文件夹下新建一个crud.go

package table

import "short_chain/global"

type Crud struct {

}

func (c *Crud) Add(data interface{}) error {
	db := global.Db
	err := db.Create(data).Error
	return err
}
func (c *Crud) QueryOne(query interface{}) error {
	db := global.Db
	err := db.Where(*&query).First(query).Error
	return err
}

暂时封装两个函数

然后我们的数据表需要内嵌crud

package table

import (
	"gorm.io/gorm"
	"short_chain/models"
)

type ShortChainData struct {
	models.Crud
	gorm.Model
	ShortId string `gorm:"size:255;comment:'短链id'" json:"short_id"`
	OriginalLink string `gorm:"text;comment:'原始链接'" json:"original_link"`
	MappingLinks string `gorm:"size:255;comment:'映射链接'" json:"mapping_links"`
}

func (ShortChainData) TableName() string  {
	return "short_chain_data"
}

我们在封装一个通用的gin返回json的函数

在根目录新建msg模块


代码如下:

package msg

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

//请求成功
func Success(c *gin.Context, msg string, data ...interface{}) {
	if data != nil {
		c.JSON(http.StatusOK, gin.H{"code": 200, "msg": msg, "data": data[0]})
	} else {
		c.JSON(http.StatusOK, gin.H{"code": 200, "msg": msg, "data": data})
	}
	return
}

//请求失败
func Error(c *gin.Context, msg string) {
	c.JSON(http.StatusOK, gin.H{"code": 201, "msg": msg, "data": ""})
	return
}

接着我们回到业务层:

我们新建一个工具文件来写一个生成uuid的方法和结构体通用转map的方法

package utils

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	uuid "github.com/satori/go.uuid"
	"time"
)

//获取uuid
func GetUuid() string {
	u := uuid.NewV4()
	return Get16MD5Encode(u.String())
}

func Get16MD5Encode(data string) string {
	return GetMD5Encode(data)[8:24]
}

//返回一个32位md5加密后的字符串
func GetMD5Encode(data string) string {
	h := md5.New()
	h.Write([]byte(data))
	return hex.EncodeToString(h.Sum(nil))
}
//通用转map功能
func ToMap(data interface{}, removeKey []string) (map[string]interface{}, error) {
	m := make(map[string]interface{})
	j, _ := json.Marshal(data)
	err := json.Unmarshal(j, &m)
	createTime, _ := time.Parse(time.RFC3339, m["CreatedAt"].(string))
	updateTime, _ := time.Parse(time.RFC3339, m["UpdatedAt"].(string))
	m["create_time"] = createTime.Format("2006-01-02 15:04:05")
	m["update_time"] = updateTime.Format("2006-01-02 15:04:05")
	m["id"] = m["ID"]
	delete(m, "ID")
	delete(m, "CreatedAt")
	delete(m, "UpdatedAt")
	delete(m, "DeletedAt")
	if removeKey != nil && len(removeKey) > 0 {
		for _, v := range removeKey {
			delete(m, v)
		}
	}
	return m, err
}

然后我们接着写短链的业务层逻辑

package services

import (
	"github.com/gin-gonic/gin"
	"short_chain/global"
	"short_chain/models/table"
	"short_chain/msg"
	"short_chain/utils"
)

type Service struct {
	table.ShortChainData
	Page int `json:"page"`
	Size int `json:"size"`
}
//添加短链
func (c *Service) Add(g *gin.Context)  {
    c.ShortId=utils.GetUuid()
	err:=c.ShortChainData.Add(&c.ShortChainData)
	if err!=nil{
		msg.Error(g,"添加短链失败")
		return
	}
	msg.Success(g,"添加短链成功")
	return
}
//编辑短链短链
func (c *Service) Update(g *gin.Context)  {
	shortQuery:=table.ShortChainData{
		ShortId: c.ShortId,
	}
	err:=shortQuery.QueryOne(&shortQuery)
	if err!=nil{
		msg.Error(g,"编辑失败,短链不存在")
		return
	}
	shortQuery.MappingLinks=c.MappingLinks
	shortQuery.OriginalLink=c.OriginalLink
	db:=global.Db
	err=db.Save(&shortQuery).Error
	if err!=nil{
		msg.Error(g,"编辑短链失败")
		return
	}
	msg.Success(g,"编辑短链成功")
	return
}
//查询短链列表
func (c *Service) List(g *gin.Context)  {
	list:=new([]table.ShortChainData)
	var count int64
	db:=global.Db
	db.Find(&list).Count(&count)
	db.Limit(c.Size).Offset((c.Page-1)*c.Size).Order("created_at desc").Find(&list)
	data:=make([]map[string]interface{},len(*list))
	for k,v:=range *list{
		item,_:=utils.ToMap(v,nil)
		data[k]=item
	}
	res:=make(map[string]interface{})
	res["count"]=count
	res["list"]=data
	msg.Success(g,"查询成功",res)
	return
}
//删除短链
func (c *Service) Delete(g *gin.Context)  {
	shortQuery:=table.ShortChainData{
		ShortId: c.ShortId,
	}
	err:=shortQuery.QueryOne(&shortQuery)
	if err!=nil{
		msg.Error(g,"删除失败,短链不存在")
		return
	}
	db:=global.Db
	err=db.Delete(&shortQuery).Error
	if err!=nil{
		msg.Error(g,"删除短链失败")
		return
	}
	msg.Success(g,"删除成功")
	return
}
//短链映射
func (c *Service) Mapping(g *gin.Context)  {

}


控制层:

我们在controllers下面新建一个controllers.go的文件


package controllers

import (
	"github.com/gin-gonic/gin"
	"short_chain/msg"
	"short_chain/services"
)

//添加短链
func Add(g *gin.Context) {
	var dataService services.Service
	err := g.ShouldBindJSON(&dataService)
	if err != nil {
		msg.Error(g, "请求参数错误:"+err.Error())
		return
	}
	if dataService.MappingLinks == "" {
		msg.Error(g, "原始链接不能为空")
		return
	}
	if dataService.OriginalLink == "" {
		msg.Error(g, "隐射链接不能为空")
		return
	}
	dataService.Add(g)
	return
}

//编辑短链
func Update(g *gin.Context) {
	var dataService services.Service
	err := g.ShouldBindJSON(&dataService)
	if err != nil {
		msg.Error(g, "请求参数错误:"+err.Error())
		return
	}
	if dataService.MappingLinks == "" {
		msg.Error(g, "原始链接不能为空")
		return
	}
	if dataService.OriginalLink == "" {
		msg.Error(g, "隐射链接不能为空")
		return
	}
	if dataService.ShortId == "" {
		msg.Error(g, "短链id不能为空")
		return
	}
	dataService.Update(g)
	return
}

//查询短链列表
func List(g *gin.Context) {
	var dataService services.Service
	err := g.ShouldBindJSON(&dataService)
	if err != nil {
		msg.Error(g, "请求参数错误:"+err.Error())
		return
	}
	if dataService.Page == 0 {
		dataService.Page = 1
	}
	if dataService.Size == 0 {
		dataService.Size = 10
	}
	dataService.List(g)
	return
}

//删除短链
func Delete(g *gin.Context) {
	var dataService services.Service
	err := g.ShouldBindJSON(&dataService)
	if err != nil {
		msg.Error(g, "请求参数错误:"+err.Error())
		return
	}
	if dataService.ShortId == "" {
		msg.Error(g, "短链id不能为空")
		return
	}
	dataService.Delete(g)
	return
}

路由

写完控制层我们就可以写路由了

我们在router文件下面新建一个router.go的文件

代码如下:

package router

import (
	"github.com/gin-gonic/gin"
	"short_chain/controllers"
)

func ShortRouter(r *gin.Engine) {
	r.POST("/add", controllers.Add)
	r.POST("/list", controllers.List)
	r.POST("/update", controllers.Update)
	r.POST("/delete", controllers.Delete)
}


然后我们在初始化router的时候初始化它

package initializes

import (
	"github.com/gin-gonic/gin"
	"short_chain/router"
)

func InitRouter()  {
	r:=gin.Default()
	r.GET("/", func(context *gin.Context) {
		context.Writer.WriteString("hello world")
	})
	router.ShortRouter(r)
	r.Run(":8000")
}

Tags:

最近发表
标签列表