文章目录
我的代码实现(包括6.824-2022分布式实验一、二)
直达gitee链接
https://gitee.com/zhou-xiujun/xun-go/tree/pet-store/
Go web 简单开发 demo
后端使用go语言,gin框架开发以及gorm操作数据库。
以一个宠物表的单表增删改查为例。
1、建立项目 pet-store
2、项目下建立static文件夹存储前端静态文件
为了简单,只用简单的 html 静态页面,并且不关注样式,只需要起到发送请求的作用。
在static文件夹下建立 hello.html 文件:
<html>
<head>
<title>
Hello! Static Website
</title>
</head>
<body>
<h2>Hello! Static Website</h2>
</body>
</html>
在static文件夹下建立 index.html 文件:
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Pet Management System</title><style>body{font-family: Arial, sans-serif;margin: 20px;}input, select, textarea{margin: 5px 0;}</style></head><body><h1>Pet Management System</h1><h2>Create Pet</h2><formid="createPetForm">
宠物的名字:
<inputtype="text"id="name"placeholder="Name"required><br>
宠物的生物学名称:
<inputtype="text"id="scientific_name"placeholder="Scientific Name"><br>
宠物的来源地:
<inputtype="text"id="origin"placeholder="Origin"><br>
宠物的出生日期:
<inputtype="datetime-local"id="birth_date"placeholder="Birth Date"><br>
宠物的平均寿命(年):
<inputtype="number"id="average_lifespan"placeholder="Average Lifespan (years)"><br>
宠物的颜色:
<inputtype="text"id="color"placeholder="Color"><br>
宠物是否患有疾病:
<selectid="has_disease"><optionvalue="">Has Disease?</option><optionvalue="true">Yes</option><optionvalue="false">No</option></select><br>
关联的疾病ID:
<inputtype="number"id="disease_id"placeholder="Disease ID"><br>
患病日期:
<inputtype="datetime-local"id="disease_date"placeholder="Disease Date"><br>
宠物的体重(公斤):
<inputtype="number"step="0.01"id="weight"placeholder="Weight (kg)"><br>
体重的更新时间:
<inputtype="datetime-local"id="weight_update_time"placeholder="Weight Update Time"><br>
宠物的价格:
<inputtype="number"step="0.01"id="price"placeholder="Price"><br>
宠物的购买日期:
<inputtype="datetime-local"id="purchase_date"placeholder="Purchase Date"><br>
购买宠物的商店名称:
<inputtype="text"id="purchase_store"placeholder="Purchase Store"><br>
宠物的食物信息:
<textareaid="food"placeholder="Food"></textarea><br>
其他额外信息:
<textareaid="additional_info"placeholder="Additional Info"></textarea><br><buttontype="button"onclick="createPet()">Create Pet</button></form><preid="createPetResult"></pre><h2>Get Pet By ID</h2><inputtype="number"id="get_pet_id"placeholder="Pet ID"><buttontype="button"onclick="getPet()">Get Pet</button><preid="petResult"></pre><h2>Get Pets By Name</h2><inputtype="text"id="get_pets_name"placeholder="Pet Name"><buttontype="button"onclick="getPetsByName()">Get Pets</button><preid="petsResult"></pre><h2>Update Pet</h2><formid="updatePetForm"><inputtype="number"id="update_pet_id"placeholder="Pet ID"required><br><inputtype="text"id="update_name"placeholder="Name"><br><inputtype="text"id="update_scientific_name"placeholder="Scientific Name"><br><inputtype="text"id="update_origin"placeholder="Origin"><br><inputtype="datetime-local"id="update_birth_date"placeholder="Birth Date"><br><inputtype="number"id="update_average_lifespan"placeholder="Average Lifespan (years)"><br><inputtype="text"id="update_color"placeholder="Color"><br><selectid="update_has_disease"><optionvalue="">Has Disease?</option><optionvalue="true">Yes</option><optionvalue="false">No</option></select><br><inputtype="number"id="update_disease_id"placeholder="Disease ID"><br><inputtype="datetime-local"id="update_disease_date"placeholder="Disease Date"><br><inputtype="number"step="0.01"id="update_weight"placeholder="Weight (kg)"><br><inputtype="datetime-local"id="update_weight_update_time"placeholder="Weight Update Time"><br><inputtype="number"step="0.01"id="update_price"placeholder="Price"><br><inputtype="datetime-local"id="update_purchase_date"placeholder="Purchase Date"><br><inputtype="text"id="update_purchase_store"placeholder="Purchase Store"><br><textareaid="update_food"placeholder="Food"></textarea><br><textareaid="update_additional_info"placeholder="Additional Info"></textarea><br><buttontype="button"onclick="updatePet()">Update Pet</button></form><preid="updatePetResult"></pre><h2>Delete Pet</h2><inputtype="number"id="delete_pet_id"placeholder="Pet ID"><buttontype="button"onclick="deletePet()">Delete Pet</button><preid="deleteResult"></pre><script>const baseURL ='http://localhost:8080';asyncfunctioncreatePet(){const pet ={name: document.getElementById('name').value,scientific_name: document.getElementById('scientific_name').value,origin: document.getElementById('origin').value ? document.getElementById('origin').value :"",birth_date: document.getElementById('birth_date').value ?newDate(document.getElementById('birth_date').value).toISOString():null,average_lifespan: document.getElementById('average_lifespan').value ?parseInt(document.getElementById('average_lifespan').value):0,color: document.getElementById('color').value ? document.getElementById('color').value :"",has_disease: document.getElementById('has_disease').value ===""?false: document.getElementById('has_disease').value ==="true",disease_id: document.getElementById('disease_id').value ?parseInt(document.getElementById('disease_id').value):0,disease_date: document.getElementById('disease_date').value ?newDate(document.getElementById('disease_date').value).toISOString():null,weight: document.getElementById('weight').value ?parseFloat(document.getElementById('weight').value):0,weight_update_time: document.getElementById('weight_update_time').value ?newDate(document.getElementById('weight_update_time').value).toISOString():null,price: document.getElementById('price').value ?parseFloat(document.getElementById('price').value):0,purchase_date: document.getElementById('purchase_date').value ?newDate(document.getElementById('purchase_date').value).toISOString():null,purchase_store: document.getElementById('purchase_store').value ? document.getElementById('purchase_store').value :"",food: document.getElementById('food').value ? document.getElementById('food').value :"",additional_info: document.getElementById('additional_info').value ? document.getElementById('additional_info').value :""};const response =awaitfetch(`${baseURL}/createPet`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(pet)});const data =await response.json();
document.getElementById('createPetResult').innerText =JSON.stringify(data,null,2);
console.log(data);}asyncfunctiongetPet(){const petId = document.getElementById('get_pet_id').value;const response =awaitfetch(`${baseURL}/getPetById/${petId}`);const data =await response.json();
document.getElementById('petResult').innerText =JSON.stringify(data,null,2);}asyncfunctiongetPetsByName(){const petName = document.getElementById('get_pets_name').value;const response =awaitfetch(`${baseURL}/getPetsByName/${petName}`);const data =await response.json();
document.getElementById('petsResult').innerText =JSON.stringify(data,null,2);}asyncfunctionupdatePet(){const petId = document.getElementById('update_pet_id').value;const pet ={name: document.getElementById('update_name').value,scientific_name: document.getElementById('update_scientific_name').value,origin: document.getElementById('update_origin').value ? document.getElementById('update_origin').value :"",birth_date: document.getElementById('update_birth_date').value ?newDate(document.getElementById('update_birth_date').value).toISOString():null,average_lifespan: document.getElementById('update_average_lifespan').value ?parseInt(document.getElementById('update_average_lifespan').value):0,color: document.getElementById('update_color').value ? document.getElementById('update_color').value :"",has_disease: document.getElementById('update_has_disease').value ===""?false: document.getElementById('update_has_disease').value ==="true",disease_id: document.getElementById('update_disease_id').value ?parseInt(document.getElementById('update_disease_id').value):0,disease_date: document.getElementById('update_disease_date').value ?newDate(document.getElementById('update_disease_date').value).toISOString():null,weight: document.getElementById('update_weight').value ?parseFloat(document.getElementById('update_weight').value):0,weight_update_time: document.getElementById('update_weight_update_time').value ?newDate(document.getElementById('update_weight_update_time').value).toISOString():null,price: document.getElementById('update_price').value ?parseFloat(document.getElementById('update_price').value):0,purchase_date: document.getElementById('update_purchase_date').value ?newDate(document.getElementById('update_purchase_date').value).toISOString():null,purchase_store: document.getElementById('update_purchase_store').value ? document.getElementById('update_purchase_store').value :"",food: document.getElementById('update_food').value ? document.getElementById('update_food').value :"",additional_info: document.getElementById('update_additional_info').value ? document.getElementById('update_additional_info').value :""};const response =awaitfetch(`${baseURL}/savePetById/${petId}`,{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(pet)});const data =await response.json();
document.getElementById('updatePetResult').innerText =JSON.stringify(data,null,2);
console.log(data);}asyncfunctiondeletePet(){const petId = document.getElementById('delete_pet_id').value;const response =awaitfetch(`${baseURL}/deletePetById/${petId}`,{method:'DELETE'});const data =await response.json();
document.getElementById('deleteResult').innerText =JSON.stringify(data,null,2);}</script></body></html>
3、建立数据库表
建立宠物信息表:
CREATE TABLE `pet` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自动递增的主键',
`name` varchar(100) COLLATE utf8mb4_0900_as_cs NOT NULL COMMENT '''宠物的名字''',
`scientific_name` varchar(150) COLLATE utf8mb4_0900_as_cs DEFAULT NULL COMMENT '''宠物的生物学名称''',
`origin` varchar(100) COLLATE utf8mb4_0900_as_cs DEFAULT NULL COMMENT '''宠物的来源地''',
`birth_date` date DEFAULT NULL COMMENT '''宠物的出生日期''',
`average_lifespan` bigint DEFAULT '0' COMMENT '''宠物的平均寿命(年)''',
`color` varchar(50) COLLATE utf8mb4_0900_as_cs DEFAULT NULL COMMENT '''宠物的颜色''',
`has_disease` tinyint(1) DEFAULT NULL COMMENT '''宠物是否患有疾病''',
`disease_id` bigint DEFAULT '0' COMMENT '''关联的疾病ID''',
`disease_date` date DEFAULT NULL COMMENT '''患病日期''',
`weight` decimal(5,2) DEFAULT NULL COMMENT '''宠物的体重(公斤)''',
`weight_update_time` datetime DEFAULT NULL COMMENT '''体重的更新时间''',
`price` decimal(10,2) DEFAULT NULL COMMENT '''宠物的价格''',
`purchase_date` date DEFAULT NULL COMMENT '''宠物的购买日期''',
`purchase_store` varchar(100) COLLATE utf8mb4_0900_as_cs DEFAULT NULL COMMENT '''购买宠物的商店名称''',
`food` text COLLATE utf8mb4_0900_as_cs COMMENT '''宠物的食物信息''',
`additional_info` text COLLATE utf8mb4_0900_as_cs COMMENT '''其他额外信息''',
`is_delete` tinyint(1) DEFAULT '0' COMMENT '''是否删除''',
`updated_at` datetime DEFAULT NULL COMMENT '''更新时间''',
`deleted_at` datetime DEFAULT NULL COMMENT '''删除时间''',
`created_at` datetime DEFAULT NULL COMMENT '''创建时间''',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) COMMENT '名字索引',
KEY `idx_scientific_name` (`scientific_name`) COMMENT '生物学名称索引',
KEY `idx_color` (`color`) COMMENT '颜色索引',
KEY `idx_pet_deleted_at` (`deleted_at`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_as_cs COMMENT='水生宠物信息表';
还有一个疾病信息表:
这个可以自行设计。。。
4、定义表对应的结构体
创建models文件夹,底下创建pet.go文件:
package models
import("time")// Pet 表示水生宠物的信息// 对于不需要的值,比如DeletedAt有时不需要传入,可以使用*time.Time或者加入gorm标签default:null// 建议使用后者// 对于前端传入的时间类型与time.Time之间转换的冲突问题type Pet struct{
ID int64`gorm:"primaryKey;autoIncrement;comment:'宠物的ID'" json:"id"`
Name string`gorm:"column:name;size:100;not null;comment:'宠物的名字'" json:"name"`
ScientificName string`gorm:"column:scientific_name;default:null;size:150;comment:'宠物的生物学名称'" json:"scientific_name"`
Origin string`gorm:"column:origin;size:100;default:null;comment:'宠物的来源地'" json:"origin"`
BirthDate time.Time `gorm:"column:birth_date;type:datetime;default:null;comment:'宠物的出生日期'" json:"birth_date"`
AverageLifespan uint`gorm:"column:average_lifespan;type:int;default:0;comment:'宠物的平均寿命(年)'" json:"average_lifespan"`
Color string`gorm:"column:color;size:50;default:null;comment:'宠物的颜色'" json:"color"`
HasDisease bool`gorm:"column:has_disease;type:tinyint(1);default:null;comment:'宠物是否患有疾病'" json:"has_disease"`
DiseaseID uint`gorm:"column:disease_id;type:int;default:0;comment:'关联的疾病ID'" json:"disease_id"`
DiseaseDate time.Time `gorm:"column:disease_date;type:datetime;default:null;comment:'患病日期'" json:"disease_date"`
Weight float64`gorm:"column:weight;type:decimal(5,2);default:null;comment:'宠物的体重(公斤)'" json:"weight"`
WeightUpdateTime time.Time `gorm:"column:weight_update_time;type:datetime;default:null;comment:'体重的更新时间'" json:"weight_update_time"`
Price float64`gorm:"column:price;type:decimal(10,2);default:null;comment:'宠物的价格'" json:"price"`
PurchaseDate time.Time `gorm:"column:purchase_date;type:datetime;default:null;comment:'宠物的购买日期'" json:"purchase_date"`
PurchaseStore string`gorm:"column:purchase_store;size:100;default:null;comment:'购买宠物的商店名称'" json:"purchase_store"`
Food string`gorm:"column:food;type:text;default:null;comment:'宠物的食物信息'" json:"food"`
AdditionalInfo string`gorm:"column:additional_info;type:text;default:null;comment:'其他额外信息'" json:"additional_info"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;comment:'创建时间'" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;comment:'更新时间'" json:"updated_at"`
DeletedAt time.Time `gorm:"column:deleted_at;type:datetime;default:null;comment:'删除时间'" json:"deleted_at"`
IsDelete bool`gorm:"column:is_delete;type:tinyint(1);default:0;comment:'是否删除'" json:"is_delete"`}// TableName 定义数据库表名func(Pet)TableName()string{return"pet"}
5、使用GORM的AutoMigrate功能匹配指定模型的结构
package database
import("gorm.io/gorm""xun-go/com/xun/pet-store/models")// Migrate 对数据库模式进行自动迁移// 该函数使用GORM的AutoMigrate功能来自动创建或更新数据库表,以匹配指定模型的结构。// 参数:// db *gorm.DB - 数据库连接实例,用于执行模式迁移操作。funcMigrate(db *gorm.DB){// 自动迁移Pet模型对应的数据库表,更新表结构以匹配当前模型定义
db.AutoMigrate(&models.Pet{})// 自动迁移Disease模型对应的数据库表,更新表结构以匹配当前模型定义
db.AutoMigrate(&models.Disease{})}
6、建立config文件夹,创建ConnectDB.go文件,用于连接数据库
package config
import("gorm.io/driver/mysql""gorm.io/gorm""log")var DB *gorm.DB
// ConnectDB 初始化并返回一个与数据库的连接。// 该函数使用GORM库来打开与MySQL数据库的连接,并配置相应的连接参数。// 如果连接失败,将记录错误并终止程序。// 返回值是一个指向gorm.DB类型的指针,用于后续的数据库操作。funcConnectDB()*gorm.DB {// 定义数据库的DSN(Data Source Name),包括用户名、密码、主机、端口和数据库名称等信息。
dsn :="username:password@tcp(127.0.0.1:3306)/pet_store?charset=utf8mb4&parseTime=True&loc=Local"// 声明一个错误变量,用于捕获打开数据库连接时可能出现的错误。var err error// 使用GORM的Open函数打开数据库连接,并配置GORM的行为。// 如果打开数据库连接失败,将记录错误信息并使用log.Fatal退出程序。
DB, err = gorm.Open(mysql.Open(dsn),&gorm.Config{})if err !=nil{
log.Fatal("Failed to connect to database:", err)}// 返回成功打开的数据库连接。return DB
}
7、创建controller
创建controllers文件夹,底下创建 PetController.go文件:
package controllers
import("fmt""github.com/gin-gonic/gin""gorm.io/gorm""net/http""strconv""time""xun-go/com/xun/pet-store/models")// PetController 定义了宠物控制器的结构体// 该控制器用于处理与宠物相关的业务逻辑和数据操作。//// 属性:// DB *gorm.DB - 数据库连接实例,用于执行数据库操作。type PetController struct{
DB *gorm.DB
}// NewPetController 创建一个新的PetController实例。// 这个函数接收一个gorm.DB类型的参数db,用于初始化PetController内的DB字段。// 返回一个指向PetController实例的指针。funcNewPetController(db *gorm.DB)*PetController {// 返回一个新的PetController实例,其中DB字段被初始化为传入的db参数。return&PetController{DB: db}}// CreatePet 通过HTTP POST请求创建一个新的宠物记录。// 请求体中应包含新宠物的所有相关信息。// 参数:// c *gin.Context: Gin框架的上下文对象,用于处理HTTP请求和响应。func(pc *PetController)CreatePet(c *gin.Context){var pet models.Pet
// 解析请求体中的JSON数据,并将其映射到pet变量中。// 如果解析失败,将返回HTTP 400错误(Bad Request)。if err := c.ShouldBindJSON(&pet); err !=nil{
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 将新宠物添加到数据库中。// 如果添加失败,将返回HTTP 500错误(Internal Server Error)。if err := pc.DB.Create(&pet).Error; err !=nil{
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}
c.JSON(http.StatusCreated, pet)}// TestCreate 测试创建函数func(pc *PetController)TestCreate(){
pet := models.Pet{
Name:"Test Pet",
Color:"Black",
Price:100.00,
Weight:10.00,
BirthDate: time.Now(),
DiseaseDate: time.Now(),
WeightUpdateTime: time.Now(),
PurchaseDate: time.Now(),
PurchaseStore:"Test Store",
Origin:"Test Origin",
ScientificName:"Test Scientific Name",
AdditionalInfo:"Test Additional Info",
AverageLifespan:10,
HasDisease:false,}if err := pc.DB.Create(&pet).Error; err !=nil{return}}// GetPetById 根据ID获取宠物信息。// 该方法处理GET请求,路径为/createPet/{petId},其中{petId}为宠物的唯一标识。// 请求成功时,返回具体的宠物信息;失败时,返回相应的错误信息。func(pc *PetController)GetPetById(c *gin.Context){// 从请求路径中提取petId
id := c.Param("id")var pet models.Pet
// 根据petId从数据库中查询未被删除的宠物信息if err := pc.DB.Where("is_delete = 0").First(&pet, id).Error; err !=nil{// 如果查询出错,返回错误信息
c.JSON(http.StatusNotFound, gin.H{"error":"Pet not found"})
fmt.Println("GetPet: "+ err.Error())return}// 如果查询成功,返回宠物信息
c.JSON(http.StatusOK, pet)}// GetPetsByName 根据名字查询宠物func(pc *PetController)GetPetsByName(c *gin.Context){
name := c.Param("name")// 声明一个切片,用于存储查询结果
pets :=make([]models.Pet,0)// 使用Find方法查询所有名字为$name$的宠物if err := pc.DB.Where("is_delete = 0").Where("name = ?", name).Find(&pets).Error; err !=nil{
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}// 如果没有找到任何记录iflen(pets)==0{
c.JSON(http.StatusNotFound, gin.H{"error":"No pets found with the given name"})return}
c.JSON(http.StatusOK, pets)}// GetAllPets 获取所有宠物func(pc *PetController)GetAllPets(c *gin.Context){var pets []models.Pet
if err := pc.DB.Find(&pets).Error; err !=nil{
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}
c.JSON(http.StatusOK, pets)}// UpdatePet handles updating an existing pet.// 对于时间为null的会解析报错//func (pc *PetController) UpdatePet(c *gin.Context) {// id := c.Param("id")// var pet models.Pet//// // 设置pet对象的ID字段// pet.ID, _ = strconv.ParseInt(id, 10, 64)// if err := c.ShouldBindJSON(&pet); err != nil {// c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})// fmt.Println("ShouldBindJSON:" + err.Error())// return// }// if err := pc.DB.Save(&pet).Error; err != nil {// c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})// fmt.Println("Save:" + err.Error())// return// }// c.JSON(http.StatusOK, pet)//}// UpdatePet 更新宠物信息// 此方法接收HTTP PUT或PATCH请求,并更新数据库中特定ID的宠物信息。func(pc *PetController)UpdatePet(c *gin.Context){// 获取URL中的宠物ID参数
id := c.Param("id")var updates map[string]interface{}// 解析请求体中的JSON数据到updates map中if err := c.ShouldBindJSON(&updates); err !=nil{// 如果解析失败,返回错误信息并终止函数执行
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
fmt.Println("ShouldBindJSON:"+ err.Error())return}// 将字符串ID转换为int64类型
parsedID, err := strconv.ParseInt(id,10,64)if err !=nil{// 如果转换失败,返回错误信息并终止函数执行
c.JSON(http.StatusBadRequest, gin.H{"error":"Invalid ID"})return}// 删除updates中的'id'键值对,因为ID不应该被更新delete(updates,"id")// 清理updates,移除所有空值或nil值的键值对for key, value :=range updates {if value ==nil|| value ==""{delete(updates, key)}}// 使用gorm更新数据库中的宠物信息if err := pc.DB.Where("is_delete = 0").Model(&models.Pet{ID: parsedID}).Updates(updates).Error; err !=nil{// 如果更新失败,返回错误信息并终止函数执行
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
fmt.Println("Updates:"+ err.Error())return}// 从数据库中获取更新后的宠物信息var pet models.Pet
if err := pc.DB.Where("is_delete = 0").First(&pet, parsedID).Error; err !=nil{
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}// 返回更新后的宠物信息
c.JSON(http.StatusOK, pet)}// DeletePet 通过ID删除宠物记录// 该方法处理HTTP DELETE请求,路径参数中包含宠物的ID。func(pc *PetController)DeletePet(c *gin.Context){
id := c.Param("id")// 物理删除if err := pc.DB.Delete(&models.Pet{}, id).Error; err !=nil{
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}
c.JSON(http.StatusOK, gin.H{"message":"Pet deleted successfully"})}// SoftDeletePet 执行软删除操作func(pc *PetController)SoftDeletePet(c *gin.Context){
id := c.Param("id")// 使用Updates方法更新is_delete字段为1if err := pc.DB.Model(&models.Pet{}).Where("id = ?", id).Update("is_delete",1).Error; err !=nil{
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}
c.JSON(http.StatusOK, gin.H{"message":"Pet soft deleted successfully"})}
8、创建路由 routes
创建routes文件夹,底下创建 routes.go:
package routes
import("github.com/gin-gonic/gin""gorm.io/gorm""net/http""xun-go/com/xun/pet-store/controllers")// RegisterRoutes 注册应用程序的所有路由// 参数://// r - Gin引擎实例,用于注册路由// db - GORM数据库连接实例,提供数据访问能力funcRegisterRoutes(r *gin.Engine, db *gorm.DB){// 创建PetController实例,传入数据库连接
petController := controllers.NewPetController(db)// 设置静态文件目录
r.LoadHTMLGlob("com/xun/pet-store/static/*")// 配置路由// GET "/hello" - 渲染并返回"hello.html"页面
r.GET("/hello",func(c *gin.Context){
c.HTML(http.StatusOK,"hello.html", gin.H{"title":"hello",})})// GET "/index" - 渲染并返回"index.html"页面
r.GET("/index",func(c *gin.Context){
c.HTML(http.StatusOK,"index.html", gin.H{"title":"index",})})// 配置 CRUD 路由
r.POST("/createPet", petController.CreatePet)
r.GET("/getPetById/:id", petController.GetPetById)
r.GET("/getPetsByName/:name", petController.GetPetsByName)
r.PUT("/savePetById/:id", petController.UpdatePet)
r.DELETE("/deletePetById/:id", petController.SoftDeletePet)}
解释:
r.POST("/createPet", petController.CreatePet)
这一行代码做了以下几件事:
- 定义了一个路由:“/createPet” 这个 URL 路径被绑定到一个特定的处理函数上。这意味着当有 HTTP POST 请求发送到这个路径时,Gin 框架会调用相应的处理函数。
- 指定了处理函数:petController.CreatePet 是一个处理函数,它将被调用来处理所有针对 /createPet 路径的 POST 请求。这个函数通常位于 petController 类型的一个实例中,它是一个实现了创建宠物逻辑的函数。 - petController 可能是一个实现了多个与宠物相关的操作的控制器对象,如创建、读取、更新和删除(CRUD)操作。- CreatePet 方法应该接受一个 *gin.Context 参数,这是 Gin 中每个请求的标准上下文对象,包含了请求和响应的信息,以及一些辅助方法来处理请求和构建响应。
- 处理请求:当一个 POST 请求到达 /createPet 路径时,Gin 会调用 petController.CreatePet 函数,并将 *gin.Context 对象作为参数传递。在这个函数中,你可以从请求中读取数据(例如,从请求体中解析 JSON 数据),执行业务逻辑(例如,创建一个新的宠物记录),然后使用 Context 对象构建和发送响应。
- 另外,还可以利用 Gin 的中间件系统:Gin 提供了强大的中间件支持,可以在处理请求之前或之后执行额外的操作,比如身份验证、日志记录、错误处理等。这些中间件可以被添加到整个应用、一组路由或单个路由上。
总的来说,r.POST 这一行代码是在设置一个具体的路由和处理函数,使得应用程序能够响应特定类型的 HTTP 请求,并执行相应的业务逻辑。
9、最后,编写main方法
在pet-store目录下创建main.go:
package main
import("github.com/gin-gonic/gin""log""xun-go/com/xun/pet-store/config""xun-go/com/xun/pet-store/database""xun-go/com/xun/pet-store/routes")funcmain(){// 初始化Gin框架,默认配置包含了logger和recovery中间件
r := gin.Default()// 连接到数据库,这里假设config.ConnectDB()是数据库连接的封装函数
db := config.ConnectDB()// 执行数据库迁移,这里假设database.Migrate()是用于同步数据库模型到实际数据库的函数
database.Migrate(config.DB)// 测试代码,用于插入数据到数据库// petController := controllers.NewPetController(db)// petController.TestCreate()// 注册路由,将Gin引擎和数据库连接传递给RegisterRoutes函数// 这里会设置所有API的路由和对应的处理函数
routes.RegisterRoutes(r, db)// 启动HTTP服务,监听8080端口// 如果启动过程中出现错误,将错误信息输出到标准错误流并终止程序if err := r.Run(":8080"); err !=nil{
log.Fatal(err)}}
这段代码的主要功能如下:
- 初始化Gin框架并配置默认的中间件。
- 建立数据库连接。
- 进行数据库迁移,确保数据库结构与代码中的模型一致。
- 注册所有应用程序的路由。
- 启动HTTP服务器,监听8080端口,处理所有传入的HTTP请求。
踩坑经历
- 前后端时间类型转换错误
{"error": "parsing time \"2024-07-06T23:16\" as \"2006-01-02T15:04:05Z07:00
前端类型是:
<inputtype="datetime-local"id="birth_date"placeholder="Birth Date">
后端类型是:
time.Time
解决办法:
birth_date: document.getElementById('birth_date').value ? new Date(document.getElementById('birth_date').value).toISOString() : null,
在前端进行转换。
- 查询数据库时,is_delete字段的数据库bit类型转换结构体bool错误
sql: Scan error on column index 17, name "is_delete": sql/driver: couldn't convert "\x00" into typebool
解决办法:
将数据库表的is_delete字段类型改为 tinyint(1)
其他内容(6.824-2022分布式实验)
Lab1:MapReduce
实验一链接
Lab2:Raft
实验二Raft链接
Lab2A:Leader Election
lab2A链接
Lab2B:日志复制
lab2B链接
Lab2C :持久化机制 persistence
lab2C链接
Lab2D:日志压缩 log compaction
lab2D链接
我的代码实现
直达gitee链接
https://gitee.com/zhou-xiujun/xun-go/tree/pet-store/
版权归原作者 xunznux 所有, 如有侵权,请联系我们删除。