写点什么

再来一篇,Go+Vue 前后端分离设计实践

作者:海风极客
  • 2023-04-30
    河北
  • 本文字数:3807 字

    阅读完需:约 12 分钟

再来一篇,Go+Vue前后端分离设计实践

在之前我曾写过一篇文章《手把手教你搭建Spring Boot+Vue前后端分离》,讲述了如何使用当下流行的 Java 后端框架 Spring Boot 和前端框架 Vue 来进行前后端分离设计,以及什么是前后端分离、跨越问题和设计流程等等,当时还是一名妥妥的 Javaer,可是时过境迁,现在的我已然是一名十分活跃的 Gopher,成为 Gopher 一段时间之后再回头看 Java 的代码,有三个问题甚是不解:


  • 怎么会有 try...catch...这种东西?

  • 为什么每一行末尾一定要加分号...

  • 我的指针呢!?


哈哈开个玩笑,下面我们回归正题。


本次这篇文章可以称为是上一篇文章的姊妹篇,使用更加简洁的 Go 语言和它的 Gin 框架来设计后端,进行一次 Go+Vue 前后端分离实践,希望能够对 Go 语言的初学者起到良好的参考作用。



这个是更新后的架构图,当然网络上可能会有更加详细的,大家可以先进行大致的了解。

1 为什么要进行前后端分离设计

答:一切都是为了解耦合!


前后端分离设计是一种软件开发方式,它将前端和后端设计为两个独立的模块,分别由不同的团队进行开发和维护。这种设计模式可以带来一些好处,包括:


  1. 提高代码质量:前后端分离可以使开发人员专注于实现业务逻辑,从而提高代码质量和可维护性。

  2. 减少耦合性:前后端分离可以减少代码之间的耦合性,从而减少后期维护的难度。

  3. 更好的测试和部署:前后端分离可以使得测试和部署更加容易,因为前后端代码是独立的。

  4. 提高性能:前后端分离可以加速页面加载速度,因为前端性能瓶颈通常出现在后端。


当然,前后端分离设计也存在一些挑战和限制,例如:


  1. 开发成本:前后端分离需要更多的开发人员和技术支持,因此可能会增加开发成本。

  2. 部署复杂性:前后端分离需要更多的配置和管理工作,因此可能会增加部署复杂性。

  3. 维护成本:前后端分离可能会增加维护成本,因为需要更多的人员来维护不同的代码版本和平台。

2 Go+Vue 前后端分离

Go+Vue 前后端分离也十分类似于 Spring Boot+Vue 前后端分离,因为他们本质上都是属于前后端分离设计,而且都有一个相同的约定,那就是 Rustful 的 API 风格和 JSON 数据格式进行数据传输,因此对于前端来说都是一样的接口,所以本次使用相同的前端代码,使用 Go 的 Gin 框架来重构后端代码,总体上也可分为以下大致几步:



Go 后端需要的依赖如下:


github.com/gin-gonic/gin v1.9.0github.com/go-sql-driver/mysql v1.7.1github.com/spf13/cast v1.5.0
复制代码

3 部分源码分享

3.1 加载配置

首先进行对 MySQL 连接驱动的初始化操作


config.go


var Db *sql.DB
const ( DbDriver = "mysql" DbUserName = "root" DbPasswd = "12345" DbHost = "127.0.0.1" DbPort = 3306 DbName = "test")
func InitDB() { var err error Db, err = sql.Open(DbDriver, fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", DbUserName, DbPasswd, DbHost, DbPort, DbName)) if err != nil { panic(err) } Db.SetConnMaxLifetime(100 * time.Second) Db.SetMaxOpenConns(10) Db.SetMaxIdleConns(16)}
复制代码

3.2 数据模型

因为 Go 语言非常的简介,因此我们就将数据模型和对数据模型的数据库操作放在一个文件中


student.go


type Student struct {  Id   int32  `json:"id"`  Name string `json:"name"`  Age  int8   `json:"age"`}
var DefaultStudentDb *StudentDb
func NewStudentDb() *StudentDb { return &StudentDb{TbName: "student", Db: config.Db}}
type StudentDb struct { TbName string Db *sql.DB}
func (s *StudentDb) Save(student Student) error { stmt, err := s.Db.Prepare(fmt.Sprintf("INSERT INTO %s(name,age) VALUES(?,?)", s.TbName)) if err != nil { return err } if _, err = stmt.Exec(student.Name, student.Age); err != nil { return err } return nil}
func (s *StudentDb) GetAll() ([]Student, error) { students := make([]Student, 0) rows, err := s.Db.Query(fmt.Sprintf("SELECT id,name,age from %s", s.TbName)) if err != nil { return nil, err } for rows.Next() { var student Student if err := rows.Scan(&student.Id, &student.Name, &student.Age); err != nil { return nil, err } students = append(students, student) } return students, nil}
func (s *StudentDb) GetOne(id int32) (Student, error) { var student Student rows, err := s.Db.Query(fmt.Sprintf("SELECT id,name,age from %s WHERE id=%d", s.TbName, id)) if err != nil { return student, err } if rows.Next() { if err := rows.Scan(&student.Id, &student.Name, &student.Age); err != nil { return student, err } } return student, nil}
func (s *StudentDb) Remove(id int32) error { stmt, err := s.Db.Prepare(fmt.Sprintf("DELETE FROM %s WHERE id=%d", s.TbName, id)) if err != nil { return err } if _, err := stmt.Exec(); err != nil { return err } return nil}
func (s *StudentDb) Update(student Student) error { stmt, err := s.Db.Prepare(fmt.Sprintf("UPDATE %s SET name=?,age=? WHERE id=?", s.TbName)) if err != nil { return err } if _, err := stmt.Exec(student.Name, student.Age, student.Id); err != nil { return err } return nil}
复制代码

3.3 API 设计

基于 Gin 框架的 HTTP Rustful API 设计


student.go


func Update(c *gin.Context) {  student := model.Student{}  if err := c.BindJSON(&student); err != nil {    fmt.Println(err)    c.JSON(http.StatusInternalServerError, -1)    return  }  if err := model.DefaultStudentDb.Update(student); err != nil {    c.JSON(http.StatusInternalServerError, -1)    return  }  c.JSON(http.StatusOK, 1)}
func Remove(c *gin.Context) { id := c.Param("id") if err := model.DefaultStudentDb.Remove(cast.ToInt32(id)); err != nil { c.JSON(http.StatusInternalServerError, -1) return } c.JSON(http.StatusOK, 1)}
func FindById(c *gin.Context) { id := c.Param("id") student, err := model.DefaultStudentDb.GetOne(cast.ToInt32(id)) if err != nil { c.JSON(http.StatusInternalServerError, -1) return } c.JSON(http.StatusOK, student)}
func FindAll(c *gin.Context) { students, err := model.DefaultStudentDb.GetAll() if err != nil { c.JSON(http.StatusInternalServerError, -1) return } c.JSON(http.StatusOK, students)}
func Save(c *gin.Context) { student := model.Student{} if err := c.BindJSON(&student); err != nil { c.JSON(http.StatusInternalServerError, -1) return } if err := model.DefaultStudentDb.Save(student); err != nil { c.JSON(http.StatusInternalServerError, -1) return } c.JSON(http.StatusOK, 1)}
复制代码


router.go


const (  Port = 8081)
func RunHttp() error { r := gin.Default() r.Use(CorsConfig()) router := r.Group("/student") { router.POST("/save", Save) router.GET("/findAll", FindAll) router.GET("/findById/:id", FindById) router.POST("/update", Update) router.DELETE("/remove/:id", Remove) } return r.Run(fmt.Sprintf("127.0.0.1:%d", Port))}
//解决跨域func CorsConfig() gin.HandlerFunc { return func(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名 c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE") c.Header("Access-Control-Allow-Headers", "*") c.Header("Access-Control-Expose-Headers", "*") c.Header("Access-Control-Allow-Credentials", "true") c.Writer.Header().Set("Access-Control-Max-Age", "86400") if c.Request.Method == http.MethodOptions { c.AbortWithStatus(200) } else { c.Next() } }}
复制代码

3.4 启动文件

main.go


package main
import ( "back_go/config" "back_go/model" "back_go/web")
func main() { config.InitDB() model.DefaultStudentDb = model.NewStudentDb() web.RunHttp()}
复制代码

4 总结和注意点

大家如果看过上一篇文章《手把手教你搭建Spring Boot+Vue前后端分离》的话相信你会感觉到 Go 相比 Java 在编码层面确实简洁了不少,也正是因此我才一点点的喜欢上 Go 语言,但是 Java 强大的生态体系是很难撼动的,就比如在使用 Spring Boot 搭建后端服务的时候,针对配置文件的读取、ORM 框架的整合等等,Go 语言的相关框架的整合确实不是十分的方便,当然如果要实现非常简单的代码,没有框架就是最好的框架。


在 Go 后端项目的配置方面,config.go 文件中可以配置数据库相关信息,router.go 文件中可以配置 HTTP 启动端口号相关信息,当然也可以写到相关的配置文件中,由 Viper 等工具进行解析。

5 代码获取方式

关于代码获取方式目前已经上传到 GitHub,大家可以关注公众号【扯编程的淡】回复关键字【前后端】获取:



发布于: 刚刚阅读数: 3
用户头像

海风极客

关注

做兴趣使然的Hero 2021-01-14 加入

Just do it.

评论

发布
暂无评论
再来一篇,Go+Vue前后端分离设计实践_三周年连更_海风极客_InfoQ写作社区