源码可查看我的github地址 如果喜欢,动动小手点个star, 谢谢大佬~


Go语言开发Web应用博客教程。教程分为两部分

第一部分为API集合

第二部分Vue调用api渲染页面

文章有点长,感兴趣的同学可以耐心看完。附有详细操作步骤,示例代码。源码可查看我的github地址

喜欢的同学可以动动小手,在github上帮忙点个小星星~

在写代码之前,先分析需求。大致有哪些功能,需要哪些技术栈。


设计目录结构

目录结构

	state.go 
	db                                 # 数据库连接初始化
		core.go
	handler                            # 控制器
		......
	middleware                         # 中间件
		......
	models                             # 模型
		......
	routers                            # 路由
		router.go
	service                            # 服务层,业务逻辑处理,与models交互操作数据库
		......
	types                              # 状态码,状态信息
		code.go
	util                               # 工具包
		encrypt.go
		result.go
	.gitignore
	gin-blog
	go.mod 
	main.go
	README.md

一. 项目初始化

➜ cd /Users/cc/goproject  # go项目目录
➜ mkdir gin-blog # 创建项目
➜ go mod init gin-blog
➜ go get -u github.com/gin-gonic/gin
  1. vim main.go测试ping
package main

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

func main() {
	r :=  gin.Default()
	r.Use(gin.Logger())
	r.Use(gin.Recovery())

	r.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "success...",
		})
	})

	r.Run(":8080")
}
go run main.go

2. 配置热重载,热重载方式有很多种,小编这配了两种方式 fresh和gowatch,小编采用的是gowatch

fresh

# 项目目录gin-blog下执行
➜ go get github.com/pilu/fresh
➜ fresh
```
**gowatch**


# 项目目录gin-blog-apis下执行
➜ go get github.com/silenceper/gowatch
➜ go build  # 会生成一个gin-blog可执行文件
➜ gowatch gin-blog

以上不管哪一种,在安装完执行fresh或者gowatch时,会报commond not foud错误,需要将命令添加到环境变量中,即可使用。小编这里采用的是添加全部变量中。(以后创建新的项目,不需要再次go get github.com/silenceper/gowatch 直接在项目下使用即可)

➜ sduo vim ~/.zshrc
➜ export PATH=${PATH}:/Users/cc/gopath/bin #写到~/.zshrc文件中 /Users/cc/gopath为你的gopath路径
➜ source ~/.zshrc

3. 设计状态码 && 提示信息

vim types/code.go

package types

type Codes struct {
	SUCCESS  uint
	FAILED   uint
	GENERATETOKEN uint
	NOAUTH uint
	AUTHFAILED uint
	AUTHFORMATERROR uint
	INVALIDTOKEN uint
	NOSUCHID uint
	CREATEUSERFAILED uint
	LCAKPARAMETERS uint
	CONVERTFAILED uint
	NOSUCHNAME uint
	EXISTSNAME uint
	Message  map[uint]string
}

var ApiCode = &Codes{
	SUCCESS: 200,
	FAILED: 0,
	AUTHFAILED: 4001,
	GENERATETOKEN: 4002,
	NOAUTH: 4003,
	AUTHFORMATERROR: 4004,
	INVALIDTOKEN: 4005,
	NOSUCHID: 1001,
	CREATEUSERFAILED: 2001,
	LCAKPARAMETERS: 3001,
	CONVERTFAILED: 3002,
	NOSUCHNAME: 5001,
	EXISTSNAME: 5002,
}

func init()  {
	ApiCode.Message = map[uint]string{
		ApiCode.SUCCESS: "成功",
		ApiCode.FAILED:  "失败",
		ApiCode.GENERATETOKEN: "生成Token失败",
		ApiCode.AUTHFAILED: "鉴权失败",
		ApiCode.NOAUTH: "请求头中auth为空",
		ApiCode.AUTHFORMATERROR: "请求头中auth格式有误",
		ApiCode.INVALIDTOKEN:"无效的Token",
		ApiCode.NOSUCHID: "id不存在",
		ApiCode.CREATEUSERFAILED: "用户创建失败",
		ApiCode.LCAKPARAMETERS: "缺少参数",
		ApiCode.CONVERTFAILED: "参数类型转换报错",
		ApiCode.NOSUCHNAME: "根据名称查不到数据",
		ApiCode.EXISTSNAME: "名称重复",
	}
}

func (c *Codes) GetMessage(code uint) string {
	message, ok := c.Message[code]
	if !ok {
		return ""
	}
	return message
}

4. 封装统一APT返回格式

vim util/result.go

package util

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

//返回的结果:
type Result struct {
	Time  time.Time   `json:"time"`
	Code  int         `json:"code"`
	Msg   string      `json:"msg"`
	Data  interface{} `json:"data"`
}


//成功
func Success(c *gin.Context, data interface{}) {
	if (data == nil) {
		data = gin.H{}
	}
	res := Result{}
	res.Time = time.Now()
	res.Code = int(types.ApiCode.SUCCESS)
	res.Msg = types.ApiCode.GetMessage(types.ApiCode.SUCCESS)
	res.Data = data

	c.JSON(http.StatusOK,res)
}

//出错
func Error(c *gin.Context, code int,msg string) {
	res := Result{}
	res.Time = time.Now()
	res.Code = code
	res.Msg = msg
	res.Data = gin.H{}

	c.JSON(http.StatusOK,res)
}

5. 封装md5加密

vim util/encrypt.go

package util
import (
	"crypto/md5"
	"encoding/hex"
)
//EncryMd5
func EncryMd5(s string) string {
	ctx := md5.New()
	ctx.Write([]byte(s))
	return hex.EncodeToString(ctx.Sum(nil))
}


6. 封装连接mysql

vim db/core.go

package core

import (
	"Gorm"
	"Gorm"
	"GORM"
	"GORM"
)

// 定义db全局变量
var Db *gorm.DB

func init() {
	var err error
	dsn := "root:root@tcp(127.0.0.1:3306)/gin-blog-api?charset=utf8mb4&parseTime=True&loc=Local"
	Db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		SkipDefaultTransaction: false,
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true, // 禁用表名加s
		},
		Logger: logger.Default.LogMode(logger.Info),// 打印sql语句
		DisableAutomaticPing: false,
		DisableForeignKeyConstraintWhenMigrating: true, // 禁用创建外键约束
	})
	if err != nil {
		panic("Connecting database failed: " + err.Error())
	}
}

//GetDB
func GetDB() *gorm.DB {
	return Db
}

7. 设计路由

vim routers/router.go

package routers
import (
	"gin-blog/handler"
	"gin-blog/middleware"
	"github.com/gin-gonic/gin"
)

func InitRouter() {
	r := gin.Default()

	// 管理后台
	// 管理员登陆
	r.POST("/login", handler.AuthLogin)

	// 管理员路由组
	userGroup := r.Group("/user/v1")
	userGroup.Use(middleware.AuthMiddleware())
	{
		userGroup.POST("/create-user", handler.CreateUser)
		userGroup.GET("/get-users", handler.GetUsers)
		userGroup.POST("/del-user-by-id", handler.DeleteUserById)
		userGroup.GET("/get-user-by-id", handler.GetUserById)
		userGroup.POST("/update-user-by-id", handler.UpdateUserById)
		userGroup.POST("/disable-user-by-id", handler.DisableUserById)
		userGroup.POST("/enable-user-by-id", handler.EnableUserById)

	}

	// 标签路由组
	tagsGroup := r.Group("/tags/v1")
	tagsGroup.Use(middleware.AuthMiddleware())
	{
		tagsGroup.POST("/create-tags", handler.CreateTags)
		tagsGroup.GET("/get-tags-list", handler.GetTagsList)
		tagsGroup.POST("/update-Tags-by-id", handler.UpdateTagsById)
		tagsGroup.POST("/del-tags-by-id", handler.DeleteTagsById)
	}

	// 分类路由组
	cateGroup := r.Group("/cate/v1")
	cateGroup.Use(middleware.AuthMiddleware())
	{
		cateGroup.POST("/create-cate", handler.CreateCate)
		cateGroup.GET("/get-cate-list", handler.GetCateList)
		cateGroup.POST("/update-cate-by-id", handler.UpdateCateById)
		cateGroup.POST("/del-cate-by-id", handler.DeleteCateById)
	}

	// 文章路由组
	postsGroup := r.Group("/posts/v1")
	postsGroup.Use(middleware.AuthMiddleware())
	{
		postsGroup.POST("/create-post", handler.CreatePost)
		postsGroup.GET("/get-posts-list", handler.GetPostsList)
		postsGroup.POST("/update-post-by-id", handler.UpdatePostById)
		postsGroup.POST("/del-post-by-id", handler.DeletePostById)
	}

	// 文章评论路由组
	commentGroup := r.Group("/comment/v1")
	{
		commentGroup.POST("/create-comment", handler.CreateComment)
		commentGroup.GET("/get-comment-list", handler.GetCommentList)
		commentGroup.POST("/del-comment-by-id", handler.DelCommentById)
	}

	// 友联路由组
	linkGroup := r.Group("/link/v1")
	{
		linkGroup.POST("/create-link", handler.CreateLink)
		linkGroup.GET("/get-link-list", handler.GetLinkList)
		linkGroup.POST("/update-link-by-id", handler.UpdateLinkById)
		linkGroup.POST("/del-link-by-id", handler.DeleteLinkById)
	}


	r.Run(":8080")
}


以上配置完成后,开始功能代码编写

代码放在了github git地址