gin实践,连载一 搭建blogs的基础配置

初始化项目目录

  • conf:用于存储配置文件
  • middleware:应用中间件
  • models:应用数据库模型
  • pkg:第三方包
  • routers 路由逻辑处理
  • runtime 应用运行时数据

初始化项目数据库

新建blog数据库,编码为utf8_general_ci
在blog数据库下,新建以下表

  1. 标签表
CREATE TABLE `blog_tag` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT '' COMMENT '标签名称',
  `created_on` int(10) unsigned DEFAULT '0' COMMENT '创建时间',
  `created_by` varchar(100) DEFAULT '' COMMENT '创建人',
  `modified_on` int(10) unsigned DEFAULT '0' COMMENT '修改时间',
  `modified_by` varchar(100) DEFAULT '' COMMENT '修改人',
  `state` tinyint(3) unsigned DEFAULT '1' COMMENT '状态 0为禁用、1为启用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文章标签管理';
  1. 文章表
CREATE TABLE `blog_article` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `tag_id` int(10) unsigned DEFAULT '0' COMMENT '标签ID',
  `title` varchar(100) DEFAULT '' COMMENT '文章标题',
  `desc` varchar(255) DEFAULT '' COMMENT '简述',
  `content` text,
  `created_on` int(11) DEFAULT NULL,
  `created_by` varchar(100) DEFAULT '' COMMENT '创建人',
  `modified_on` int(10) unsigned DEFAULT '0' COMMENT '修改时间',
  `modified_by` varchar(255) DEFAULT '' COMMENT '修改人',
  `state` tinyint(3) unsigned DEFAULT '1' COMMENT '状态 0为禁用1为启用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文章管理';
  1. 认证表
CREATE TABLE `blog_auth` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT '' COMMENT '账号',
  `password` varchar(50) DEFAULT '' COMMENT '密码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `blog`.`blog_auth` (`id`, `username`, `password`) VALUES (null, 'test', 'test123456');

编写项目配置包

拉取go-ini/ini的依赖包
go get -u github.com/go-ini/ini
我们需要编写基础的应用配置文件,在gin-blog的conf目录下新建app.ini文件,写入内容:

#debug or release
RUN_MODE = debug
[app]
PAGE_SIZE = 10
JWT_SECRET = 23347$040412

[server]
HTTP_PORT = 8000
READ_TIMEOUT = 60
WRITE_TIMEOUT = 60

[database]
TYPE = mysql
USER = 数据库账号
PASSWORD = 数据库密码
#127.0.0.1:3306
HOST = 数据库IP:数据库端口号
NAME = blog
TABLE_PREFIX = blog_

建立调用配置的setting模块,在gin-blog的pkg目录下新建setting目录,新建setting.go文件,写入内容:

package setting

import (
	"github.com/go-ini/ini"
	"log"
	"time"
)

var (
	Cfg *ini.File

	RunMode string

	HTTPPort     int
	ReadTimeout  time.Duration
	WriteTimeout time.Duration

	PageSize  int
	JwtSecret string
)

func init() {
	var err error
	Cfg, err = ini.Load("conf/app.ini")
	if err != nil {
		log.Fatalf("fail to parse 'conf/app.ini': %v", err)
	}

	LoadBase()
	LoadServer()
	LoadApp()
}
func LoadBase() {
	RunMode = Cfg.Section("").Key("RUN_MODE").MustString("debug")
}
func LoadServer() {
	sec, err := Cfg.GetSection("server")
	if err != nil {
		log.Fatalf("fail to parse 'server': %v", err)
	}
	HTTPPort = sec.Key("HTTP_PORT").MustInt(8000)
	ReadTimeout = time.Duration(sec.Key("READ_TIMEOUT").MustInt(60)) * time.Second
	WriteTimeout = time.Duration(sec.Key("WRITE_TIMEOUT").MustInt(60)) * time.Second
}
func LoadApp() {
	sec, err := Cfg.GetSection("app")
	if err != nil {
		log.Fatalf("fail to parse 'app': %v", err)
	}
	PageSize = sec.Key("PAGE_SIZE").MustInt(10)
	JwtSecret = sec.Key("JWT_SECRET").MustString("!@)*#)!@U#@*!@!)")
}

当前的目录结构:

编写API错误码包

建立错误码的e模块,在gin-blog的pkg目录下新建e目录,新建code.go和msg.go文件,写入内容:

  1. code.go
package e

const (
	SUCCESS = 200
	ERROR = 500
	INVALID_PARAMS = 400

	ERROR_EXIST_TAG = 10001
	ERROR_NOT_EXIST_TAG = 10002
	ERROR_NOT_EXIST_ARTICLE = 10003

	ERROR_AUTH_CHECK_TOKEN_FAIL = 20001
	ERROR_AUTH_CHECK_TOKEN_TIMEOUT = 20002
	ERROR_AUTH_TOKEN = 20003
	ERROR_AUTH = 20004
)
  1. msg.go
package e

var MsgFlags = map[int]string{
	SUCCESS: "ok",
	ERROR: "fail",
	INVALID_PARAMS: "请求参数错误",
	ERROR_EXIST_TAG: "已存在该标签名称",
	ERROR_NOT_EXIST_TAG: "不存在该标签名称",
	ERROR_NOT_EXIST_ARTICLE: "该文章不存在",
	ERROR_AUTH_CHECK_TOKEN_FAIL: "Token鉴权失败",
	ERROR_AUTH_CHECK_TOKEN_TIMEOUT: "Token已超时",
	ERROR_AUTH_TOKEN: "Token生成失败",
	ERROR_AUTH: "Token错误",
}
func GetMsg(code int) string {
	if msg, ok := MsgFlags[code]; ok {
		return msg
	}
	return MsgFlags[ERROR]
}

编写工具目录

在gin-blog的pkg目录下新建util目录,
拉取com的依赖包
go get -u github.com/Unknwon/com

编写分页页码的获取方法

在util目录下新建pagination.go,写入内容:

package util

import (
	"gin_log/pkg/setting"
	"github.com/gin-gonic/gin"
	"log"
	"strconv"
)

func GetPage(c *gin.Context) int {
	result := 0
	page, err := strconv.Atoi(c.Query("page"))
	if err != nil {
		log.Printf("fail to parse 'page': %v", err)
	}
	if page > 0 {
		result = (page - 1) * setting.PageSize
	}
	return result
}

编写models init

拉取gorm的依赖包
go get -u gorm.io/gorm
拉取mysql驱动的依赖包
go get -u github.com/go-sql-driver/mysql
完成后,在gin-blog的models目录下新建models.go,用于models的初始化使用

package models

import (
	"fmt"
	"gin_log/pkg/setting"
	"gorm.io/gorm"
	"log"

	"gorm.io/driver/mysql"
)

var db *gorm.DB

type Model struct {
	ID int `gorm:"primary_key" json:"id"`
	CreatedOn int `json:"created_on"`
	ModifiedOn int `json:"modified_on"`
}
func init() {
	var (
		err error
		dbName, user, password, host string
	)
	sec, err := setting.Cfg.GetSection("database")
	if err != nil {
		log.Fatal(2, "fail to GetSection 'database': %v", err)
	}

	dbName = sec.Key("NAME").String()
	user = sec.Key("USER").String()
	password = sec.Key("PASSWORD").String()
	host = sec.Key("HOST").String()

	dsn := fmt.Sprintf(
		"%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		user, password, host, dbName,
		)
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Println(err)
	}

	if err = db.AutoMigrate(&Model{}); err != nil {
		log.Println(err)
	}
}

编写项目启动,路由文件

最基础的准备工作完成啦,让我们开始编写Demo吧!

编写demo

在gin-blog下建立main.go作为启动文件(也就是main包),
我们先写个Demo,帮助大家理解,写入文件内容:

package main

import (
	"fmt"
	"gin_log/pkg/setting"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	router := gin.Default()
	router.GET("/test", func(context *gin.Context) {
		context.JSON(200, gin.H{
			"message": "test",
		})
	})
	s := &http.Server{
		Addr: fmt.Sprintf(":%d", setting.HTTPPort),
		Handler: router,
		ReadTimeout: setting.ReadTimeout,
		WriteTimeout: setting.WriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}
	_ = s.ListenAndServe()
}

执行go run main.go
在本机执行curl 127.0.0.1:8000/test,检查是否返回{"message":"test"}。

抽离路由和处理函数

在gin-blog下routers目录新建router.go文件,写入内容:

package routers

import (
	"gin_log/pkg/setting"
	"github.com/gin-gonic/gin"
)

func InitRouter() *gin.Engine {
	r := gin.New()
	r.Use(gin.Logger())
	r.Use(gin.Recovery())
	gin.SetMode(setting.RunMode)
	r.GET("/test", func(context *gin.Context) {
		context.JSON(200, gin.H{"message": "test"})
	})
	return r
}

修改main.go的文件内容:

package main

import (
	"fmt"
	"gin_log/pkg/setting"
	"gin_log/routers"
	"net/http"
)

func main() {
	router := routers.InitRouter()
	s := &http.Server{
		Addr: fmt.Sprintf(":%d", setting.HTTPPort),
		Handler: router,
		ReadTimeout: setting.ReadTimeout,
		WriteTimeout: setting.WriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}
	_ = s.ListenAndServe()
}

当前目录结构:

重启服务,执行curl 127.0.0.1:8000/test查看是否正确返回。

下一节,我们将以我们的Demo为起点进行修改,开始编码!

posted @ 2022-09-05 15:44  专职  阅读(169)  评论(0编辑  收藏  举报