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]
}

浙公网安备 33010602011771号