在一些前后端不分离的Web架构中,我们通常需要在后端将一些数据渲染到HTML文档中,从而实现动态的网页(网页的布局和样式大致一样,但展示的内容并不一样)效果。
我们这里说的模板可以理解为事先定义好的HTML文档文件,模板渲染的作用机制可以简单理解为文本替换操作–使用相应的数据去替换HTML文档中事先准备好的标记。
个人觉得类似于jsp技术,可能功能上没有jsp那么强大。
GO标准库之http/template
Gin是一个用Go语言编写的web框架。它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍。
Gin框架介绍及使用
gorm是一个使用Go语言编写的ORM框架。它文档齐全,对开发者友好,支持主流数据库。
GORM入门指南
GORM的CRUD指南
该项目将实现一个Bubble小清单,通过界面上的按钮,可以实现对待办事项的增删改查。
前端采用的是vue框架,由于还没有学习到,所以不详细分析。后端数据库采用mysql,使用grom框架来间接操作数据库。
其中关于路由的操作使用了REST风格,关于REST风格可以看这个:阮一峰 理解RESTful架构
应该能勉强称之为小型的MVC架构。
以上分析纯属扯淡,重点看下面的代码。
mysql.go
先来初始化连接数据库。
package dao
import (
"github.com/jinzhu/gorm"
)
// DB 为了方便初始化一个全局变量
var (
DB *gorm.DB
)
func InitMysql() (err error) {
//连接数据库并返回一个数据库对象
DB, err = gorm.Open("mysql", "root:123456@(127.0.0.1:3306)/bubble?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
return
}
return DB.DB().Ping() //测试数据库的连通性
}
// Close 关闭数据库的连接,在main函数中可以以defer调用
func Close() {
_ = DB.Close()
}
todo.go
然后使用dao包中提供的dao.DB对象对数据进行具体的CRUD。
package models
import (
"gin_littleProject/dao"
)
//Todo Model
type Todo struct {
ID int `json:"id"`
Title string `json:"title"`
Status bool `json:"status"`
}
/*
Todo 增删改查操作都放在这里
*/
//CreateATodo 创建todo
func CreateATodo(todo *Todo) (err error) {
err = dao.DB.Create(&todo).Error
return
}
// GetTodoList 返回数据表
func GetTodoList() (todoList []*Todo, err error) {
if err = dao.DB.Find(&todoList).Error; err != nil {
return nil, err
}
return
}
// GetTodoById 通过ID查找某条数据并返回
func GetTodoById(id string) (todo *Todo, err error) {
todo = new(Todo)
if err = dao.DB.Where("id=?", id).First(todo).Error; err != nil {
return nil, err
}
return
}
// UpdateATodo 更新某一条数据
func UpdateATodo(todo *Todo)(err error) {
err = dao.DB.Save(todo).Error
return
}
// DeleteATodo 根据ID删除某一条数据
func DeleteATodo(id string) (err error) {
err = dao.DB.Where("id=?", id).Delete(&Todo{}).Error
return
}
controller.go
接着使用控制器实现主要的逻辑。
package controller
import (
"gin_littleProject/models"
"github.com/gin-gonic/gin"
"net/http"
)
// IndexHander 回调函数,向客户端返回一个HTML页面
func IndexHander(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
}
// CreateATodo 回调函数,在服务端数据库创建一个todo
func CreateATodo(c *gin.Context) {
//1.从请求中把数据拿出来
var todo models.Todo
c.BindJSON(&todo) //把json中的数据拷贝到todo结构体
//2.存入数据库
err := models.CreateATodo(&todo)
//3.向客户端返回响应
if err != nil {
c.JSON(http.StatusOK, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, todo)
}
}
// GetToList 回调函数,向客户端发送数据表
func GetToList(c *gin.Context) {
//查询todo这个表里面的所有数据
todoList, err := models.GetTodoList()
//向客户端返回响应
if err != nil {
c.JSON(http.StatusOK, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, todoList)
}
}
// UpdateATodo 回调函数,更新服务端数据库的一条数据
func UpdateATodo(c *gin.Context) {
//根据id获得参数
id, ok := c.Params.Get("id")
if !ok {
c.JSON(http.StatusOK, gin.H{"error" : "无效的id"})
return
}
todo, err := models.GetTodoById(id)
if err != nil {
c.JSON(http.StatusOK, gin.H{"error": err.Error()})
return
}
//将json中的数据拷贝到todo结构体
c.BindJSON(&todo)
//更新
if err = models.UpdateATodo(todo); err != nil {
c.JSON(http.StatusOK, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, todo)
}
}
// DeleteATodo 回调函数,删除服务端数据库的一条数据
func DeleteATodo(c *gin.Context) {
//根据id获得参数
id, ok := c.Params.Get("id")
if !ok {
c.JSON(http.StatusOK, gin.H{"error" : "无效的id"})
return
}
if err := models.DeleteATodo(id); err != nil {
c.JSON(http.StatusOK, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, gin.H{id:"deleted"})
}
}
routers.go
接下来实现一些路由操作。
package routers
import (
"gin_littleProject/controller"
"github.com/gin-gonic/gin"
)
func SetupRouter() *gin.Engine {
r := gin.Default()
//加载静态文件
r.Static("/static", "static")
//加载HTML页面
r.LoadHTMLFiles("templates/index.html")
r.GET("/index", controller.IndexHander)
//创建路由组
v1Group := r.Group("v1")
{
//使用REST风格,用HTTP协议中的4个请求方法代表不同的动作。
//待办事项
//添加
v1Group.POST("/todo", controller.CreateATodo)
//查看所有的待办事项
v1Group.GET("/todo", controller.GetToList)
//修改某一个待办事项
v1Group.PUT("/todo/:id", controller.UpdateATodo)
//删除某一个待办事项
v1Group.DELETE("/todo/:id",controller.DeleteATodo)
}
//向主函数返回一个*gin.Engine指针
return r
}
main.go
最后是main函数
package main
import (
"gin_littleProject/dao"
"gin_littleProject/models"
"gin_littleProject/routers"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//创建数据库
//CREATE DATABASE BUBBLE
err := dao.InitMysql()
if err != nil {
panic(err)
}
//程序退出就关闭数据库连接
defer dao.Close()
//模型绑定
dao.DB.AutoMigrate(&models.Todo{})
//注册路由
r := routers.SetupRouter()
r.Run(":9090")
}
最后不要忘记go mod tidy
。
所有源码都在七米老师的github上:
https://github.com/Q1mi/bubble