diff --git a/skills/gin/README.md b/skills/gin/README.md index 5dd8fdc..182baf4 100644 --- a/skills/gin/README.md +++ b/skills/gin/README.md @@ -77,4 +77,40 @@ type Book struct { [GIN-debug] GET /api/books/:isbn --> main.main.func3 (3 handlers) [GIN-debug] PUT /api/books/:isbn --> main.main.func4 (3 handlers) [GIN-debug] DELETE /api/books/:isbn --> main.main.func5 (3 handlers) -``` \ No newline at end of file +``` + + +## 如何测试 + +创建书籍: + +```sh +curl -X POST http://localhost:8080/api/books -H "Content-Type: application/json" -d '{"title": "Go 语言", "author": "张三", "price": 39.99}' +``` + + +获取所有书籍: +```sh +curl http://localhost:8080/api/books +``` + +根据 ID 获取书籍: +```sh +curl http://localhost:8080/api/books/1 +``` + + +更新书籍: + +```sh +curl -X PUT http://localhost:8080/api/books/1 -H "Content-Type: application/json" -d '{"price": 49.99}' +``` + + +删除书籍: + +```sh +curl -X DELETE http://localhost:8080/api/books/1 +``` + +这样就完成了一个简单的使用 MySQL 的 Book CRUD 示例。你可以根据需要进一步扩展功能。 \ No newline at end of file diff --git a/skills/gin/main.go b/skills/gin/main.go index 2a5a6b3..2545e39 100644 --- a/skills/gin/main.go +++ b/skills/gin/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "log" "net/http" @@ -20,6 +21,10 @@ func setupDatabase() *gorm.DB { return db } +func Failed(ctx *gin.Context, err error) { + ctx.JSON(http.StatusBadRequest, gin.H{"code": 0, "msg": err.Error()}) +} + // 规定好风格: JSON Restful Api func main() { // gin Engine, 它包装了http server @@ -34,37 +39,79 @@ func main() { // 获取Book用户传达的参数 ins := new(Book) if err := ctx.ShouldBindJSON(ins); err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{"code": 0, "msg": err.Error()}) + Failed(ctx, err) return } // book, save if err := db.Save(ins).Error; err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{"code": 0, "msg": err.Error()}) + Failed(ctx, err) return } ctx.JSON(http.StatusOK, ins) }) - // 查询Book列表 -> []*Book book.GET("", func(ctx *gin.Context) { - + var books []Book + if err := db.Find(&books).Error; err != nil { + Failed(ctx, err) + return + } + ctx.JSON(http.StatusOK, books) }) - // 查询Book详情 book.GET("/:isbn", func(ctx *gin.Context) { - + var ins Book + id := ctx.Param("isbn") + if err := db.Where("isbn = ?", id).Take(&ins).Error; err != nil { + Failed(ctx, fmt.Errorf("Book not found")) + return + } + ctx.JSON(http.StatusOK, ins) }) - // 更新Book book.PUT("/:isbn", func(ctx *gin.Context) { + id := ctx.Param("isbn") + // 获取用户参数, 读取用户的更新参数 + req := BookSpec{} + if err := ctx.ShouldBindJSON(&req); err != nil { + Failed(ctx, err) + return + } + + // gorm更新是,如果字段为零值 就不更新该字段, is_sale 没办法更新为false + // 如果越到零值,也需要更新,则需要转化为 指针类型 + if err := db.Where("isbn = ?", id).Model(&Book{}).Updates(req).Error; err != nil { + Failed(ctx, err) + return + } + + // 针对有零值的字段独立更新 + // if err := db.Where("isbn = ?", id).Model(&Book{}).Update("is_sale", req.IsSale).Error; err != nil { + // Failed(ctx, err) + // return + // } + // // ...... + + // 再次查询出来 + var ins Book + if err := db.Where("isbn = ?", id).Take(&ins).Error; err != nil { + Failed(ctx, fmt.Errorf("Book not found")) + return + } + + // 查询出更新后的数据 + ctx.JSON(http.StatusOK, ins) }) - // 删除Book book.DELETE("/:isbn", func(ctx *gin.Context) { - + id := ctx.Param("isbn") + if err := db.Where("isbn = ?", id).Delete(&Book{}).Error; err != nil { + Failed(ctx, err) + return + } }) if err := server.Run("127.0.0.1:8080"); err != nil { @@ -75,10 +122,17 @@ func main() { // Book 结构体定义 type Book struct { // grom:"column:isbn;", 具体文档: https://gorm.io/docs/models.html#Fields-Tags - IsBN uint `json:"isbn" gorm:"primaryKey;column:isbn"` + IsBN uint `json:"isbn" gorm:"primaryKey;column:isbn"` + BookSpec +} + +type BookSpec struct { Title string `json:"title" gorm:"column:title;type:varchar(200)"` Author string `json:"author" gorm:"column:author;type:varchar(200);index"` Price float64 `json:"price" gorm:"column:price"` + // bool false + // nil 是零值, false + IsSale *bool `json:"is_sale" gorm:"column:is_sale"` } // 定义该对象映射到数据里 表的名称