go项目

利用gin写一个blog(后端部分)

主框架:gin

数据库:gorm v1

前端:vue

数据加载框架:ini

加密:scrypt

总的来说gin框架是很好用的,我学的是gorm的v1版,在使用的时候感觉v1版确实不好用,另外实在vscode上开发的调试是真的麻烦,后面打算在ied上写,此外这个项目还有用户登录和上传模块没写,还有前端没写,前端我还得补一补


数据配置:

ini数据

#这是注释
[server]
#debug开发模式 reless 生产模式
AppMode=debug
HttpPort =:3000
#前面相当于是数据的键key后面是键值
[database]
DB=mysql
Dbhost=localhost
DbPort=3306
DbUser=ginblog
DbPass=admin123
DbNmae=ginname
配置文件数据接口
package utils
// 配置文件数据接口
import (
	"fmt"

	"gopkg.in/ini.v1"
)

var (
	AppMode  string
	HttpPort string
	DB       string
	Dbhost   string
	DbPort   string
	DbUser   string
	DbPass   string
	DbNmae   string
)
// 接收配置数据的容器
// 数据初始化
func init() {
	// ini/load 是init包中的一个方法用于获取配置文件的数据,返回一个file的指针和合格err
	f, err := ini.Load("config/config.ini")
	if err != nil {
		fmt.Println("配置文件读取错误请检查文件路径")
	}
	LoadServer(f)
	// 载入配置服务的数据
	Loadata(f)
	// 从ini文件中获取数据库配置信息的数据

}
func LoadServer(f *ini.File) {
	/*这里就是通过f这个指针去调用section这个方法方法里面写ini文件的区段,
	key这个就是去找区段里面的键值,如果没有返回的话通过函数must string函数返回默认值

	*/
	AppMode = f.Section("server").Key("AppMode").MustString("debug")
	HttpPort = f.Section("server").Key("HttpPort").MustString(":3000")
}
func Loadata(f *ini.File) {
	// 函数section获取ini文件的节,key函数获取参数里面的值,muststing函数是设置的默认值
	DB = f.Section("database").Key("DB").MustString("mysql")
	Dbhost = f.Section("database").Key("Dbhost").MustString("localhost")
	DbNmae = f.Section("database").Key("Dbname").MustString("ginname")
	DbPort = f.Section("database").Key("DbPort").MustString("3306")
	DbUser = f.Section("database").Key("DbUser").MustString("ginblog")
	DbPass = f.Section("database").Key("DbPass").MustString("admin123")
}
//将config里面的数据传过来

业务模块
数据库
package model
// 这里的gorm是v1版本
// 数据库连接接口
import (
	"aa/utils"
	"fmt"
	"time"

	_"github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
)

var db *gorm.DB
var err error

func Initdb() {
	// 使用utils里面的数据进行传参来进行路由配置
	// 使用gorm来操作数据库第一个参数是数据库的类型,第二个数据库的配置参数,这里通过fmt包的spriontf参数进行字符串拼接
	db ,err =gorm.Open(utils.DB,fmt.Sprintf(
		"%s:%s@tcp(%s:%s)/%s",
		utils.DbUser,
		utils.DbPass,
		utils.Dbhost,
		utils.DbPort,
		utils.DbNmae,
	 ))
if err !=nil {
	fmt.Println("数据库连接错误请检查参数")
}
db.SingularTable(true)
// gorm老版本在写入数据库默认会节键值加上复数,调用这个函数参数为true的话会关掉这个功能
// 不使用复数
//创建表,参数是结构体指针
db.AutoMigrate(&User{},&Category{},&Artucle{})

// 迁移数据

db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
db.DB().SetConnMaxLifetime(10*time.Second)
	}
	// db, err2 := sql.Open(utils.DB,fmt.Sprintf(
	// 	"%s:%s@tcp(%s:%s)/%s",
	// 	utils.DbUser,
	// 	utils.DbPass,
	// 	utils.Dbhost,
	// 	utils.DbPort,
	// 	utils.DbNmae,
	//  ))
	//  if err2 !=nil {
	// 	fmt.Println("连接数据库失败请检查参数")
	//  }
用户模块
package model

// 用户模块
import (
	"aa/utils/errmsg"
	"encoding/base64"
	"log"

	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/scrypt"
	// "github.com/ugorji/go/codec"
)

type User struct {
	gorm.Model
	Username string `gorm:"type:varchar(20);not null" json:"username"`
	Password string `gorm:"type:varchar(20);not null" json:"password"`
	Role     int    `gorm:"type:int" json:"role"`
}

// 查询用户有没有
func CheckUser(name string) (code int) {
	var users User
	db.Select("id").Where("username=?", name).First(&users)
	if users.ID > 0 {
		// id大于0说明用户存在
		return errmsg.ERROR_USERNAME //1001
	}
	return errmsg.SUCCSE
}

// 新增用户
func CreateUser(data *User) int {
	data.Password = Scryppw(data.Password)
	err2 := db.Create(&data).Error
	if err2 != nil {
		return errmsg.ERROR //500
	}
	return errmsg.SUCCSE
}

// 查询用户列表
func Getusers(pagesize int, pagenum int) []User {
	var users []User
	err2 := db.Limit(pagesize).Offset((pagenum - 1) * pagesize).Find(&users).Error
	if err2 != nil && err2 != gorm.ErrRecordNotFound {
		return nil
	}
	return users
}

// 删除用户
func Deluser(id int) int {
	var user User
	err2 := db.Where("id=?", id).Delete(&user).Error
	if err2 != nil {
		return errmsg.ERROR
	}
	return errmsg.SUCCSE
}
// 编辑用户
func Ususer(id int, data *User) int {
	var user User
	// 不能修改密码,限定在密码之外的
	var maps = make(map[string]interface{})
	maps["username"] = data.Username
	maps["role"] = data.Role
	err2 := db.Model(&user).Where("id=?", id).Update(maps).Error
	if err2 != nil {
		return errmsg.ERROR
	}
	return errmsg.SUCCSE
	// 从user{}这个模型传过去,位置是id,跟新的数据是maps
	//创建一个
}

// 密码加密
func Scryppw(password string) string {
	const Keyleng = 10
	salt := make([]byte, 8)
	salt = []byte{66, 89, 77, 12, 45, 52, 30, 19}                            //盐
	Hashpw, err2 := scrypt.Key([]byte(password), salt, 16384, 8, 1, Keyleng) //进行加盐
	if err2 != nil {
		log.Fatal(err2)
	}
	fpw := base64.StdEncoding.EncodeToString(Hashpw) //进行编码
	return fpw                                       //返回加密后的密码

}

文章分类模块
package model

import (
	"aa/utils/errmsg"

	"github.com/jinzhu/gorm"
)

// 分类模块

type Category struct {
	ID   uint   `gorm:"primary_key;auto_increment" json:"id"`
	Name string `gorm:"type:varchar(20);not null" json:"name"`
}
// 查询分类
func Checkcatgory(name string) (code int) {
	var cate Category
	db.Select("id").Where("name=?", name).First(&cate)
	if cate.ID > 0 {

		return errmsg.ERROR_CATEGORY 
	}
	return errmsg.SUCCSE
}

// 新增分类
func Createcategory(data *Category) int {
	err2 := db.Create(&data).Error
	if err2 != nil {
		return errmsg.ERROR //500
	}
	return errmsg.SUCCSE
}

// 查询分类列表
func Getcategory(pagesize int, pagenum int) []Category {
	var cate []Category
	err2 := db.Limit(pagesize).Offset((pagenum - 1) * pagesize).Find(&cate).Error
	if err2 != nil && err2 != gorm.ErrRecordNotFound {
		return nil
	}
	return cate
}

// 删除分类
func Delcategory(id int) int {
	var cate Category
	err2 := db.Where("id=?", id).Delete(&cate).Error
	if err2 != nil {
		return errmsg.ERROR
	}
	return errmsg.SUCCSE
}
// 编辑分类
func Uscategory(id int, data *Category) int {
	var cate Category
	
	var maps = make(map[string]interface{})
	maps["name"] = data.Name
	err2 := db.Model(&cate).Where("id=?", id).Update(maps).Error
	if err2 != nil {
		return errmsg.ERROR
	}
	return errmsg.SUCCSE
}


/*
gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw=
gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o=
gorm.io/driver/sqlite v1.5.3 h1:7/0dUgX28KAcopdfbRWWl68Rflh6osa4rDh+m51KL2g=
gorm.io/driver/sqlite v1.5.3/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw=
gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=

*/

文章模块
package model

// 文章模块
import (
	"aa/utils/errmsg"

	"github.com/jinzhu/gorm"
)

type Artucle struct {
	
	Category Category `gorm:"foreignkey:Cid;PRELOAD:ture"`
	gorm.Model
	Title   string `gorm:"type:varchar(100);not null" json:"title"`
	Cid     int    `gorm:"type:int;not null" json:"cid"`
	Desc    string `gorm:"type:varchar(100)" json:"desc"`
	Context string `gorm:"type:longtext" json:"context"`
	Img     string `gorm:"type:varchar(100)" json:"img"`
}

// 新增文章
func CreateArtucle(data *Artucle) int {
	err2 := db.Create(&data).Error
	if err2 != nil {
		return errmsg.ERROR //500
	}
	return errmsg.SUCCSE
}

// 查询文章列表
func GetArtucle(pagesize int, pagenum int) ([]Artucle, int) {
	var art []Artucle
	err2 := db.Preload("Category").Limit(pagesize).Offset((pagenum - 1) * pagesize).Find(&art).Error
	if err2 != nil && err2!=gorm.ErrRecordNotFound{
		return nil, errmsg.ERROR
	} 
	return art, errmsg.SUCCSE
}

// 删除文章
func DelArtucle(id int) int {
	var art Artucle
	err2 := db.Where("id=?", id).Delete(&art).Error
	if err2 != nil {
		return errmsg.ERROR
	}
	return errmsg.SUCCSE
}

// 编辑文章
func UsArtucle(id int, data *Artucle) int {
	var art Artucle
	var maps = make(map[string]interface{})
	maps["title"] = data.Title
	maps["cid"] = data.Cid
	maps["desc"] = data.Desc
	maps["context"] = data.Context
	maps["img"] = data.Img
	err2 := db.Model(&art).Where("id=?", id).Update(maps).Error
	if err2 != nil {
		return errmsg.ERROR
	}
	return errmsg.SUCCSE
	
}

// 查询单个文章
func GETartinfo(id int) (Artucle, int) {
	var art Artucle
	err2 := db.Preload("Category").Where("id=?", id).First(&art).Error
	if err2 != nil {
		return art, errmsg.ERROR_ARTNOT
	}
	return art, errmsg.SUCCSE
}

// 查询分类下所有文章
func GETcateallart(id int, pagesize int, pagenum int) ([]Artucle, int) {
	var cateart []Artucle
	err := db.Preload("Category").Limit(pagesize).Offset((pagenum-1)*pagesize).Where("id=?", id).Find(&cateart).Error
	if err != nil {
		return nil, errmsg.ERROR_CATE_NOT_EXIST
	}
	return cateart, errmsg.SUCCSE
}

api

分类api

package v1

import (
	"aa/model"
	"aa/utils/errmsg"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
)

// 接收从catgory模块传过来的的code
func Addcategory(c *gin.Context) {
	var data model.Category

	c.ShouldBindJSON(&data)
	r_code = model.Checkcatgory(data.Name)
	//  接收查询的返回值
	if r_code == errmsg.SUCCSE {
		// 成功的话将数据写入
		model.Createcategory(&data)
	}
	if r_code == errmsg.ERROR_CATEGORY {
		//1001,
		r_code = errmsg.ERROR_CATEGORY
	}
	c.JSON(http.StatusOK, gin.H{

		"status":  r_code,
		"data":    data,
		"message": errmsg.Geterrmsg(r_code),
	})

}

// 查询分类列表
func Getcategory(c *gin.Context) {
	//pagesize和pagenum接收来自前端的数据并通过atio方法转换成int型
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	pagenum, _ := strconv.Atoi(c.Query("pagenum"))
	if pagesize == 0 {
		pagesize = -1
		// 不查询的话等于-1
	}
	if pagenum == 0 {
		pagenum = -1
	}
	r_code = errmsg.SUCCSE
	data := model.Getcategory(pagesize, pagenum)
	c.JSON(http.StatusOK, gin.H{
		"status":  r_code,
		"data":    data,
		"message": errmsg.Geterrmsg(r_code),
	})
}

// 编辑分类
func Editcategory(c *gin.Context) {
	var data model.Category
	id, _ := strconv.Atoi(c.Param("id"))
	//  获取id
	c.ShouldBindJSON(&data)
	r_code = model.Checkcatgory(data.Name)
	//  查询是否重名
	if r_code != errmsg.ERROR {
		model.Uscategory(id, &data)
		// 不重名返回给ususer方法进行编辑处理
	}
	if r_code == errmsg.ERROR_CATEGORY {
		//1001,用户存在
		r_code = errmsg.ERROR_CATEGORY
	}
	c.JSON(http.StatusOK, gin.H{

		"status":  r_code,
		"message": errmsg.Geterrmsg(r_code),
	})

}

// 删除分类(软删除)
func Delcategory(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	// 将前端传过来的数据进行性格式转换
	r_code = model.Delcategory(id)
	// 节后数据库操作之后的值传递
	c.JSON(http.StatusOK, gin.H{
		"status":  r_code,
		"message": errmsg.Geterrmsg(r_code),
	})
}

userapi
package v1

import (
	"aa/model"
	"aa/utils/errmsg"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
)

// //查询用户是否存在
// func UserExist(c *gin.Context)  {

// }
// 添加用户
var r_code int

// 接收从user模块传过来的的code
func AddUser(c *gin.Context) {
	var data model.User

	c.ShouldBindJSON(&data)
	r_code = model.CheckUser(data.Username)
	//  接收查询的返回值
	if r_code == errmsg.SUCCSE {
		// 成功的话将数据写入
		model.CreateUser(&data)
	}
	if r_code == errmsg.ERROR_USERNAME {
		//1001,用户存在
		r_code = errmsg.ERROR_USERNAME
	}
	c.JSON(http.StatusOK, gin.H{

		"status":  r_code,
		"data":    data,
		"message": errmsg.Geterrmsg(r_code),
	})

}

//查询用户

// 查询用户列表
func GetUsers(c *gin.Context) {
	//pagesize和pagenum接收来自前端的数据并通过atio方法转换成int型
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	pagenum, _ := strconv.Atoi(c.Query("pagenum"))
	if pagesize == 0 {
		pagesize = -1
		// 不查询的话等于-1
	}
	if pagenum == 0 {
		pagenum = -1
	}
	r_code = errmsg.SUCCSE
	data := model.Getusers(pagesize, pagenum)
	c.JSON(http.StatusOK, gin.H{
		"status":  r_code,
		"data":    data,
		"message": errmsg.Geterrmsg(r_code),
	})
}

// 编辑用户
func Edituser(c *gin.Context) {
 var data model.User
 id, _ := strconv.Atoi(c.Param("id"))
//  获取id
 c.ShouldBindJSON(&data)
 r_code=model.CheckUser(data.Username)
//  查询是否重名
 if r_code!=errmsg.ERROR {
	model.Ususer(id,&data)
	// 不重名返回给ususer方法进行编辑处理
 }
 if r_code == errmsg.ERROR_USERNAME {
	//1001,用户存在
	r_code = errmsg.ERROR_USERNAME
}
c.JSON(http.StatusOK, gin.H{

	"status":  r_code,
	"message": errmsg.Geterrmsg(r_code),
})
}
// 删除用户(软删除)
func DelUser(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	// 将前端传过来的数据进行性格式转换
	r_code = model.Deluser(id)
	// 节后数据库操作之后的值传递
	c.JSON(http.StatusOK, gin.H{
		"status":  r_code,
		"message": errmsg.Geterrmsg(r_code),
	})
}

文章api
package v1

import (
	"aa/model"
	"aa/utils/errmsg"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
)

func Addartucle(c *gin.Context) {
	var data model.Artucle

	c.ShouldBindJSON(&data)
	r_code = model.CreateArtucle(&data)
	c.JSON(http.StatusOK, gin.H{

		"status":  r_code,
		"data":    data,
		"message": errmsg.Geterrmsg(r_code),
	})

}
// 查询分类下所有文章
func GETcateart(c *gin.Context)  {
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	pagenum, _ := strconv.Atoi(c.Query("pagesize"))
	id ,_:= strconv.Atoi(c.Param("id"))
	if pagesize == 0 {
		pagesize = -1
		// 不查询的话等于-1
	}
	if pagenum == 0 {
		pagenum = -1
	}
	data, r_code := model.GETcateallart(id,pagesize,pagenum)
	c.JSON(http.StatusOK,gin.H{
		"status":  r_code,
		"data":    data,
		"message": errmsg.Geterrmsg(r_code),
	})
}
// 查询单个文章
func GETartinfo(c *gin.Context)  {
	id ,_:= strconv.Atoi(c.Param("id"))
	data ,r_code :=model.GETartinfo(id)
	c.JSON(http.StatusOK,gin.H{
		"status":  r_code,
		"data":    data,
		"message": errmsg.Geterrmsg(r_code),
	})
}
// 查询文章列表
func Getartucle(c *gin.Context) {
	//pagesize和pagenum接收来自前端的数据并通过atio方法转换成int型
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	pagenum, _ := strconv.Atoi(c.Query("pagenum"))
	if pagesize == 0 {
		pagesize = -1
		// 不查询的话等于-1
	}
	if pagenum == 0 {
		pagenum = -1
	}

	data, r_code := model.GetArtucle(pagesize, pagenum)
	c.JSON(http.StatusOK, gin.H{
		"status":  r_code,
		"data":    data,
		"message": errmsg.Geterrmsg(r_code),
	})
}

// 编辑分类
func Editartucle(c *gin.Context) {
	var data model.Artucle
	id, _ := strconv.Atoi(c.Param("id"))
	//  获取id
	c.ShouldBindJSON(&data)
	r_code = model.UsArtucle(id, &data)
	c.JSON(http.StatusOK, gin.H{

		"status":  r_code,
		"message": errmsg.Geterrmsg(r_code),
	})

}

// 删除分类(软删除)
func Delartucle(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	// 将前端传过来的数据进行性格式转换
	r_code = model.DelArtucle(id)
	// 节后数据库操作之后的值传递
	c.JSON(http.StatusOK, gin.H{
		"status":  r_code,
		"message": errmsg.Geterrmsg(r_code),
	})
}

路由

package router

// 路由
import (
	v1 "aa/api/v1"
	"aa/utils"

	"github.com/gin-gonic/gin"
)

// 初始化路由
func InitRouter() {
	gin.SetMode(utils.AppMode)
	e := gin.Default()
	// 创建路由表
	router_1 := e.Group("api/v1")
	{
		// user接口
		router_1.POST("user/add", v1.AddUser)
		router_1.GET("user", v1.GetUsers)
		router_1.PUT("user/:id", v1.Edituser)
		router_1.DELETE("user/:id", v1.DelUser)
		// 分类接口
		router_1.POST("category/add", v1.Addcategory)
		router_1.GET("category", v1.Getcategory)
		router_1.PUT("category/:id", v1.Editcategory)
		router_1.DELETE("category/:id", v1.Delcategory)
		// 文章接口
		router_1.POST("artucle/add", v1.Addartucle)
		router_1.GET("artucle", v1.Getartucle)
		router_1.PUT("artucle/:id", v1.Editartucle)
		router_1.DELETE("artucle/:id", v1.Delartucle)
		router_1.GET("artucle/list", v1.GETcateart)
		router_1.GET("artucle/info/:id", v1.GETartinfo)

	}
	e.Run(utils.HttpPort)
	// 路由在这个端口上跑起来
}

error
package errmsg

// 错误信息
const (
	SUCCSE = 200
	ERROR  = 500
	// code =1000 用户模块错误
	ERROR_USERNAME     = 1001 //用户名被使用
	ERROR_PASSWORD     = 1002 //密码错误
	ERROR_USER_NOT     = 1003 //用户不存在
	ERROR_TOKEN_NOT    = 1004 //用户的输入的token不存在
	ERROR_TOKEN_NOTIME = 1005 //用户token超时
	ERROR_TOKEN_WRONG  = 1006 //TOKEN wrong
	ERROR_TOKEN_TYPE   = 1007 //TOKEN格式不对

		//code 3000 分类模块错误
	ERROR_CATEGORY=2001 //查询分类
	// code=2000 文章模块错误
	ERROR_ARTNOT=3001
	ERROR_CATE_NOT_EXIST=3002
)

// 返回错误信息列表
var Codemsg = map[int]string{
	SUCCSE:             "OK",
	ERROR:              "FATL",
	ERROR_USERNAME:     "用户已存在",
	ERROR_PASSWORD:     "密码错误",
	ERROR_USER_NOT:     "用户不存在",
	ERROR_TOKEN_NOT:    "TOKEN不存在",
	ERROR_TOKEN_NOTIME: "TOKEN超时",
	ERROR_TOKEN_WRONG:  "TOKEN错误",
	ERROR_TOKEN_TYPE:   "TOKEN格式不对",
	//分类
	ERROR_CATEGORY:"该分类已存在",
	ERROR_ARTNOT:"文章不存在",
	ERROR_CATE_NOT_EXIST:"分类不存在,查询不到文章",
}

// 返回错误信息
// 通过接收状态码,然后返回错误信息
func Geterrmsg(code int) string {
	return Codemsg[code]
}

posted @ 2023-11-03 00:20  kill比尔  阅读(25)  评论(0)    收藏  举报