go语言实战--基于Vue3+gin框架的实战Cetide网项目(讲解开发过程中的各种踩坑)

最近被要求学习go语言开发,也就做一个项目实战巩固一下,也分享一下关于gin框架的实战项目

(后续应该还是会继续学习Java,这一期还是做一个go+vue的)

经过一段时间的开发过后,感觉现在的开发效率要快不少了,争取一天半做出个大概吧,后续再加一些功能就完工

那么就开始go的后端初始化吧;

先创建一个项目:

注意点1:先创建go.mod(这里如果不创建mod就会报错

\testProject> go get -u github.com/gin-gonic/gin

go: go.mod file not found in current directory or any parent directory.

'go get' is no longer supported outside a module.

To build and install a command, use 'go install' with a version,

like 'go install example.com/cmd@latest'

For more information, see https://golang.org/doc/go-get-install-deprecation

or run 'go help get' or 'go help install'.)

创建go.mod文件并加上module 和go

这下再来安装一下gin框架,终端输入命令

Go 复制代码
go get -u github.com/gin-gonic/gin 

呐这样就安装成功了

注意点2:这里如果有人会出现压缩包损坏的情况记得要改变一下GOPROXY

这里虽然安装成功了,但没有被识别到,这里需要设置一下

点击setting

点开goModule,并启动go模块集成就可以了

呐,这样就好了

注意点3:如果安装了框架却没有被识别,点击setting并启动模块集成

前置工作差不多了,现在来初始化一下

初始化的话,先定义一下统一相应结果吧;创建一个response包并在包下创建result.go文件

这里可以定义一个统一返回结果的函数,再定义一个成功返回函数和失败返回函数

Go 复制代码
package response

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

func Result(context *gin.Context, httpStatus int, code int, msg string, data gin.H) {
	context.JSON(httpStatus, gin.H{
		"code": code,
		"msg":  msg,
		"data": data,
	})
}

func Success(context *gin.Context, msg string, data gin.H) {
	Result(context, http.StatusOK, 0, msg, data)
}

func Fail(context *gin.Context, msg string, data gin.H) {
	Result(context, http.StatusOK, 1, msg, data)
}

这里我是按照写java的习惯来定义的,也不一定很规范

定义好统一相应结果之后就可以开始定义连接数据库相关操作,这里专门创建一个go文件来连接

创建common包,并在包下创建database文件

这里用配置文件的方式吧,那就再创建一个config包,并在包下创建application.yml包

在config包下我们规定好开启端口号和数据库连接信息

Go 复制代码
server:
  port: 8082
datasource:
  driverName: mysql
  host: localhost
  port: 3306
  database: go_gin
  username: root
  password: 1234
  charset: utf8

注意点4:使用config组件来将配置文件统一管理,这需要我们下载viper

下载命令go get github.com/spf13/viper

然后,这里使用grom来进行数据库相关操作

注意点5:安装gorm: go get -u github.com/jinzhu/gorm

那么现在来编辑一下database.go文件吧

Go 复制代码
package common

import (
	"fmt"
	"github.com/jinzhu/gorm"
	"github.com/spf13/viper"
	"log"
)

// 初始化数据库
func InitDB() *gorm.DB {
	driverName := viper.GetString("datasource.driverName")
	host := viper.GetString("datasource.host")
	port := viper.GetString("datasource.port")
	database := viper.GetString("datasource.database")
	username := viper.GetString("datasource.username")
	password := viper.GetString("datasource.password")
	charset := viper.GetString("datasource.charset")
	args := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true",
		username, password, host, port, database, charset)
	db, err := gorm.Open(driverName, args)
	if err != nil {
		panic("数据库连接失败,err:" + err.Error())
	}
	log.Println("数据库连接成功")
	return db
}

// 定义方法来和获取数据库实例
func GetDB() *gorm.DB {
	return InitDB()
}

这里我们定义了两个函数,一个用来初始化数据库,一个用来获取数据库实例。

然后就可以来定义main.go文件了,在最外层创建main.go文件作为启动文件

注意点6:刚才使用了viper库来处理配置文件,这里需要初始化一下,需要定义一个函数

Go 复制代码
func InitConfig() {
	workDir, _ := os.Getwd()
	viper.SetConfigName("application")
	viper.SetConfigType("yml")
	viper.AddConfigPath(workDir + "/config")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}

这里来解释一下吧,

1.workDir, _ := os.Getwd():获取当前工作目录,os.Getwd()返回当前进程的工作目录路径,下划线_忽略可能的错误。

2.viper.SetConfigName("application"):设置配置文件的名称为application,不包括文件扩展名。

3.viper.SetConfigType("yml"):设置配置文件的类型为yaml,意味着Viper将解析.yml或.yaml格式的配置文件。

4.viper.AddConfigPath(workDir + "/config"):添加配置文件的搜索路径,这里是当前工作目录下的config子目录。

5.err := viper.ReadInConfig():尝试读取配置文件。如果找到并成功读取,err将为nil;否则,err将包含错误信息。

这个函数确保了在当前工作目录的config子目录下查找名为application.yml或application.yaml的配置文件,并在遇到错误时停止程序执行。

这样就初始化了,

再调用一下common包下初始化数据库的方法即可完成连接

Go 复制代码
package main

import (
	"github.com/jinzhu/gorm"
	"github.com/spf13/viper"
	"main/common"
	"os"
)

func main() {
	InitConfig()
	db := common.GetDB()
	defer func(db *gorm.DB) {
		err := db.Close()
		if err != nil {
			panic(err)
		}
	}(db)
}
func InitConfig() {
	workDir, _ := os.Getwd()
	viper.SetConfigName("application")
	viper.SetConfigType("yml")
	viper.AddConfigPath(workDir + "/config")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}

啊忒,缺少导入数据库驱动

注意点7:速速安装一个go get -u github.com/go-sql-driver/mysql

ok,安装之后放在main.go文件下吧

复制代码
_ "github.com/go-sql-driver/mysql"

注意这里的下划线_,它表示导入包仅用于注册驱动,而不需要直接使用包内的任何函数或类型

这样就行了,右击启动!

启动成功!

那么,麻烦的一步也就解决了,

下面就可以开始麻烦的部分了,

先定义模块所需结构体:

创建model包,其下三包,entity,dto,vo

然后在entity包下创建user.go

Go 复制代码
package entity

import "github.com/jinzhu/gorm"

type User struct {
	gorm.Model
	Name     string `gorm:"size:20;not null;unique"`
	Password string `gorm:"size:255;not null"`
	Mobile   string `gorm:"size:11;not null;unique"`
	Email    string `gorm:"size:50;not null;unique"`
}

代码如上

在main方法处添加方法AutoMigrate(检查模型结构(这里是entity.User),并根据结构体字段创建或更新相应的数据库表结构)

那么数据库和表结构都已经完成了,就可以开始编写接口了

编写路由包router

并创建routes.go文件,在文件中定义函数

Go 复制代码
package router

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

func CollectionRoute(r *gin.Engine) *gin.Engine {
	r.POST("/user/register",)
	r.POST("/user/login",)
	r.GET("/user/info",)
	
	return r
}

先不写具体方法,定义下来

然后回到main.go函数

通过 gin.Default() 初始化了一个默认的 Gin 路由器实例。然后,调用了 router.CollectionRoute(r) 函数,集中定义一组相关的路由规则

然后获取config文件下的服务断开接着run开启即可。

那么main.go文件中要写的也就是这些了,

接下来开始定义接口

创建controller包,并创建UserController.go文件,就在其中编写一个注册功能吧

Go 复制代码
package controller

import (
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/bcrypt"
	"log"
	"main/common"
	"main/model/entity"
	"main/response"
	"net/http"
	"net/mail"
)

func Register(context *gin.Context) {
	db := common.GetDB()

	//获取参数
	username := context.PostForm("username")
	password := context.PostForm("password")
	mobile := context.PostForm("mobile")
	email := context.PostForm("email")
	if len(username) < 5 || len(username) > 16 {
		response.Fail(context, "用户名长度在5-16之间", nil)
		return
	}
	if len(password) < 5 || len(password) > 16 {
		response.Fail(context, "密码长度在5-16之间", nil)
		return
	}
	if len(mobile) != 11 {
		response.Fail(context, "手机号长度为11位", nil)
		return
	}
	_, err := mail.ParseAddress(email)
	if err != nil {
		response.Fail(context, "邮箱格式不正确", nil)
		return
	}
	//判断手机号是否存在
	if isMobileExist(db, mobile) {
		response.Fail(context, "手机号已存在", nil)
		return
	}
	if isEmailExist(db, email) {
		response.Fail(context, "邮箱已存在", nil)
		return
	}
	if isUserNameExist(db, username) {
		response.Fail(context, "用户名已存在", nil)
		return
	}
	//都不存在则创建用户
	//密码加密
	hashPwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		response.Result(context, http.StatusInternalServerError, 500, "密码加密失败", nil)
		return
	}
	//创建用户
	user := entity.User{
		Name:     username,
		Password: string(hashPwd),
		Mobile:   mobile,
		Email:    email,
	}
	db.Create(&user)
	//返回结果
	if user.ID != 0 {
		response.Success(context, "注册成功", nil)
		return
	} else {
		response.Fail(context, "注册失败", nil)
		return
	}

}

func isMobileExist(db *gorm.DB, mobile string) bool {
	var user entity.User
	db.Where("mobile = ?", mobile).First(&user)
	if user.ID != 0 {
		log.Println("手机号已存在")
		return true
	}
	return false
}

func isEmailExist(db *gorm.DB, email string) bool {
	var user entity.User
	db.Where("email = ?", email).First(&user)
	if user.ID != 0 {
		log.Println("邮箱已存在")
		return true
	}
	return false
}

func isUserNameExist(db *gorm.DB, username string) bool {
	var user entity.User
	db.Where("name = ?", username).First(&user)
	if user.ID != 0 {
		log.Println("用户名已存在")
		return true
	}
	return false
}

这里的代码不太难就不细说了,主要也就是从上下文获取到前端传来的表单信息

先对表单的格式进行校验,然后查询数据库看关键字段是否已经被注册,若没有则执行注册

写好之后将其添加到routes中即可

那么来测试一下吧,在main.go处打开程序,并打开postman进行检验

这样就注册成功了

后端这块差不多都是这个流程

这里我就先不往后crud了,

题外话:

讲个前后端混合的,这里以我之前做的基于前端2048小游戏为例子吧

我们先在项目目录下创建包templates和static,

这里static包下创建js包,css包,images包分别用来存放前端的资源,然后将现有的index.html文件,css文件,js文件和images文件放入对应的包中

就像这样:

这样就OK了,然后在main.go文件中加载一下

Go 复制代码
func main() {
	InitConfig()
	db := common.GetDB()
	defer func(db *gorm.DB) {
		err := db.Close()
		if err != nil {
			panic(err)
		}
	}(db)
	db.AutoMigrate(&entity.User{})

	r := gin.Default()
	r.Static("/static", "./static")
	r.LoadHTMLGlob("templates/*")

	r = router.CollectionRoute(r)

	port := viper.GetString("server.port")
	panic(r.Run(":" + port))
}
func InitConfig() {
	workDir, _ := os.Getwd()
	viper.SetConfigName("application")
	viper.SetConfigType("yml")
	viper.AddConfigPath(workDir + "/config")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}

OK,此时回到routes.go文件中添加

复制代码
r.GET("/user/game", controller.Game)

在UserController文件下添加方法:

复制代码
func Game(context *gin.Context) {
    context.HTML(http.StatusOK, "index.html", gin.H{
       "msg": "这就是CeTide的游戏!",
    })
}

这样就可以了,打开main.go!

浏览器访问目标地址

那么基于js制作的2048小游戏就成功呈现在浏览器上了,(需要2048小游戏源码的可以去资源处下载)

emmm,这一章就分享这些吧

相关推荐
Scott9999HH1 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社2 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海2 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖3 小时前
JDK 26 新特性详解
java·开发语言
马优晨4 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区6 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大6 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai6 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜7 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa7 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio