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 get -u github.com/gin-gonic/gin 

呐这样就安装成功了

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

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

点击setting

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

呐,这样就好了

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

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

初始化的话,先定义一下统一相应结果吧;创建一个response包并在包下创建result.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包下我们规定好开启端口号和数据库连接信息

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文件吧

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库来处理配置文件,这里需要初始化一下,需要定义一个函数

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包下初始化数据库的方法即可完成连接

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

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文件,在文件中定义函数

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文件,就在其中编写一个注册功能吧

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文件中加载一下

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,这一章就分享这些吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/691301.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

你可以直接和数据库对话了!DB-GPT 用LLM定义数据库下一代交互方式,数据库领域的GPT、开启数据3.0 时代

✨点击这里✨&#xff1a;&#x1f680;原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 你可以直接和数据库对话了&#xff01;DB-GPT 用LLM定义数据库下一代交互方式&#xff0c;数据库领…

如何理解与学习数学分析——第二部分——数学分析中的基本概念——第6章——级数

第2 部分&#xff1a;数学分析中的基本概念 (Concepts in Analysis) 6. 级数(Series) 本章从等比级数(geometric series)开始&#xff0c;研究可以使用公式计算无限和的条件。它讨论了部分和与级数收敛的符号、图形表示和定义&#xff0c;并将它们应用于调和级数。它介绍了级…

EKF在LiFePO4电池SOC估算中不好用?一问带你破解EKF应用难题

磷酸铁锂电池因为平台区的存在&#xff0c;导致使用戴维南模型EKF的方法时&#xff0c;无法准确进行SOC准确预估。所以最近搜索了大量关于磷酸铁锂电池SOC预估的论文、期刊&#xff0c;但我被海量忽略客观事实、仅为了毕业的硕士论文给震惊到了。很多论文为了掩饰平台区的存在&…

Live800:深度解析,客户服务如何塑造品牌形象

在当今竞争激烈的市场环境中&#xff0c;品牌形象对于企业的成功至关重要。而客户服务作为品牌与消费者之间最直接的互动方式&#xff0c;不仅影响着消费者的购买决策&#xff0c;更在塑造品牌形象方面发挥着不可替代的作用。本文将深度解析客户服务如何塑造品牌形象&#xff0…

python文件:py,ipynb, pyi, pyc, pyd, pyo都是什么文件?

1、Python文件类型介绍 &#x1f4c1; 1.1 .py 文件&#xff1a;源代码基础 .py 文件是 Python 最基本的源代码文件格式&#xff0c;用于存储纯文本形式的 Python 代码。它是开发者编写程序的主要场所&#xff0c;包含函数、类、变量定义以及执行逻辑。Python 解释器直接读取…

C++ OpenCV 图像分类魔法:探索神奇的模型与代码

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

React hooks动态配置侧边栏

React hooks根据不同需求 还有不同的角色 动态的去配置侧边栏 需求&#xff1a; 点击某个按钮是一套侧边栏 &#xff0c;不同角色&#xff08;比如管理员之类的权限高一点&#xff09;比普通用户多个侧边栏 然后点击另一个按钮是另一套侧边栏 此时&#xff0c;就需要动态的去…

解决微信小程序分享按钮不可用

问题描述 在微信小程序中点击胶囊按钮上的三个点&#xff0c;在弹出的对话框中的【分享给好友】【分享到朋友圈】按钮都属于不可用的状态&#xff0c;显示未设置。 问题截图 解决方案 在每个需要此功能的页面都需要添加此代码&#xff0c;否则就不能进行使用。 // vue3时&l…

基础乐理入门

基础概念 乐音&#xff1a;音高&#xff08;频率&#xff09;固定&#xff0c;振动规则的音。钢琴等乐器发出的是乐音&#xff0c;听起来悦耳、柔和。噪音&#xff1a;振动不规则&#xff0c;音高也不明显的音。风声、雨声、机器轰鸣声是噪音&#xff0c;大多数打击乐器&#…

在UI界面中实现3d人物展示

简要原理(设置双摄像机): 为需要展示的3D人物单独设置一个摄像机(只设置为渲染人物层级),主要摄像机的方向与人物方向一致,但摄像机需要需要旋转180,设置的角度自行进行微调创建一个Render Texture类型的组件用于存储摄像机渲染的内容UI上设置需要展示的图片区域,图片…

台湾合泰原装BS66F360 封装LQFP-44 电容触摸按键 AD+LED增强型触控

BS66F360是一款由Holtek Semiconductor Inc.生产的微控制器&#xff08;microcontroller&#xff09;&#xff0c;具有触摸检测和LED驱动功能。其应用领域广泛&#xff0c;包括但不限于以下几个方面&#xff1a; 1. 触摸按键应用&#xff1a;BS66F360内置了触摸按键检测功能&am…

【MySQL】聊聊MySQL常见的SQL语句阻塞场景

在平时的业务中&#xff0c;可能一个简单的SQL语句也执行很慢&#xff0c;这种情况其实大多数都是要么没有使用索引&#xff0c;要么出现锁竞争造成执行阻塞。本篇主要来介绍具体的场景 CREATE TABLE t ( id int(11) NOT NULL, c int(11) DEFAULT NULL, PRIMARY KEY (id) ) ENG…

17.调用游戏本身的hp减伤害函数实现秒杀游戏角色

上一个内容&#xff1a;16.在目标进程构建CALL执行代码 16.在目标进程构建CALL执行代码在它的代码上进行的更改&#xff0c;它的callData变量中的代码不完善一个完整的函数是有return的&#xff0c;处理器执行到return会返回如果执行不到会继续往下走&#xff0c;直到执行不下…

像素着色技术在AI绘画中的革新作用

摘要&#xff1a;随着人工智能技术的不断进步&#xff0c;AI绘画已成为艺术和技术领域中的一个热门话题。本文将探讨像素着色技术在AI绘画中的应用及其对创作过程的影响&#xff0c;揭示这一技术如何推动艺术创作的革新。 引言&#xff1a; 传统的绘画方法要求艺术家具备高超的…

Nextjs学习教程

一.手动创建项目 建议看这个中文网站文档,这个里面的案例配置都是手动的,也可以往下看我这个博客一步步操作 1.在目录下执行下面命令,初始化package.json文件 npm init -y2.安装react相关包以及next包 yarn add next react react-dom // 或者 npm install --save next react…

kafka的leader和follower

leader和follower kafka的leader和follower是相对于分区有意义的&#xff0c;不是相对于broker。 因为每个分区都有leader和follower, leader负责读写数据。 follower负责复制leader的数据保存到自己的日志数据中&#xff0c;并在leader挂掉后重新选举出leader。 kafka会再…

【Unity】 HTFramework框架(五十一)代码片段执行器

更新日期&#xff1a;2024年6月8日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 Code Snippet Executer 代码片段执行器使用 Code Snippet Executer打开 Code Snippet Executer动态执行&#xff08;代码片段&#xff09;静态执行&#x…

从 Android 恢复已删除的备份录

本文介绍了几种在 Android 上恢复丢失和删除的短信的方法。这些方法都不能保证一定成功&#xff0c;但您可能能够恢复一些短信或其中存储的文件。 首先要尝试什么 首先&#xff0c;尝试保留数据。如果你刚刚删除了信息&#xff0c;请立即将手机置于飞行模式&#xff0c;方法是…

CSAPP Lab02——Bomb Lab完成思路详解

看见的看不见的 瞬间的永恒的 青草长啊大雪飘扬 ——月亮之上 完整代码见&#xff1a;CSAPP/bomb at main SnowLegend-star/CSAPP (github.com) 01 字符串比较 简单的把输入的字符串和地址“0x402400”内早已存储的字符串相比较。如果两个字符串相等则函数返回&#xff0c;否…

比亚迪正式签约国际皮划艇联合会和中国皮划艇协会,助推龙舟入奥新阶段

6月5日&#xff0c;比亚迪与国际皮划艇联合会、中国皮划艇协会在深圳共同签署合作协议&#xff0c;国际皮划艇联合会主席托马斯科涅茨科&#xff0c;国际皮划艇联合会秘书长理查德派蒂特&#xff0c;中国皮划艇协会秘书长张茵&#xff0c;比亚迪品牌及公关处总经理李云飞&#…