From fda31d91728f450e0b0a69da21b0e9e66b6ad85c Mon Sep 17 00:00:00 2001 From: yumaojun03 <719118794@qq.com> Date: Sat, 16 Nov 2024 18:11:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E9=85=8D=E7=BD=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E9=85=8D=E7=BD=AE=E7=A8=8B=E5=BA=8F=E5=90=AF=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- book/application.yaml | 10 +++ book/config/README.md | 2 - book/config/application.yaml | 2 +- book/config/config.go | 44 +++++++++++- book/main.go | 127 ++++++++++++++++++++++++++++++++++- 5 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 book/application.yaml diff --git a/book/application.yaml b/book/application.yaml new file mode 100644 index 0000000..b1c172b --- /dev/null +++ b/book/application.yaml @@ -0,0 +1,10 @@ +app: + host: 127.0.0.1 + port: 8080 +mysql: + host: 127.0.0.1 + port: 3306 + database: test + username: "root" + password: "123456" + debug: false \ No newline at end of file diff --git a/book/config/README.md b/book/config/README.md index f99a66f..8328d05 100644 --- a/book/config/README.md +++ b/book/config/README.md @@ -1,8 +1,6 @@ # 程序配置管理 - - ## 测试验证包 要考虑测序的是否如预期运行 diff --git a/book/config/application.yaml b/book/config/application.yaml index de6ecff..fb3cc1c 100644 --- a/book/config/application.yaml +++ b/book/config/application.yaml @@ -1,6 +1,6 @@ app: host: localhost - port: 8090 + port: 8080 mysql: host: 127.0.0.1 port: 3306 diff --git a/book/config/config.go b/book/config/config.go index 047f859..c98df80 100644 --- a/book/config/config.go +++ b/book/config/config.go @@ -1,6 +1,13 @@ package config -import "encoding/json" +import ( + "encoding/json" + "fmt" + "sync" + + "gorm.io/driver/mysql" + "gorm.io/gorm" +) // 定义程序配置 // dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local" @@ -31,6 +38,10 @@ type App struct { Port int `json:"port"` } +func (c *App) Address() string { + return fmt.Sprintf("%s:%d", c.Host, c.Port) +} + // mysql: // // host: 127.0.0.1 @@ -46,4 +57,35 @@ type MySQL struct { Username string `json:"username"` Password string `json:"password"` Debug bool `json:"debug"` + + db *gorm.DB + lock sync.Mutex +} + +// 初始化数据库, 能过与数据库交互的 连接池对象: db +// 复用, 只要有就用 之前的,没有才初始化新的db对象 +func (c *MySQL) DB() *gorm.DB { + c.lock.Lock() + defer c.lock.Unlock() + + if c.db == nil { + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", + c.Username, + c.Password, + c.Host, + c.Port, + c.Database, + ) + db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + panic("failed to connect database") + } + + if c.Debug { + db = db.Debug() + } + c.db = db + } + + return c.db } diff --git a/book/main.go b/book/main.go index 2378180..d339f46 100644 --- a/book/main.go +++ b/book/main.go @@ -2,11 +2,19 @@ package main import ( "fmt" + "log" + "net/http" "os" + "github.com/gin-gonic/gin" "gitlab.com/go-course-project/go17/book/config" ) +func Failed(ctx *gin.Context, err error) { + ctx.JSON(http.StatusBadRequest, gin.H{"code": 0, "msg": err.Error()}) +} + +// 规定好风格: JSON Restful Api func main() { // 从配置文件中加载配置 // 加载配置 @@ -14,9 +22,124 @@ func main() { if path == "" { path = "application.yaml" } - config.LoadConfigFromYaml(path) + if err := config.LoadConfigFromYaml(path); err != nil { + fmt.Printf("加载配置错误: %s\n", err) + os.Exit(1) + } // 访问加载后的配置 conf := config.Get() - fmt.Println(conf) + + // gin Engine, 它包装了http server + server := gin.Default() + + db := conf.MySQL.DB() + // 配置业务路有, Book类型的资源的 一套简单的CRUD + // 创建Book -> Book + // POST, Body + book := server.Group("/api/books") + book.POST("", func(ctx *gin.Context) { + // 获取Book用户传达的参数 + ins := new(Book) + if err := ctx.ShouldBindJSON(ins); err != nil { + Failed(ctx, err) + return + } + + // book, save + if err := db.Save(ins).Error; err != nil { + Failed(ctx, err) + return + } + + ctx.JSON(http.StatusOK, ins) + }) + // 查询Book列表 -> []*Book + // SELECT * FROM `books` + 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(conf.App.Address()); err != nil { + log.Println(err) + } +} + +// Book 结构体定义 +type Book struct { + // grom:"column:isbn;", 具体文档: https://gorm.io/docs/models.html#Fields-Tags + 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"` +} + +// 定义该对象映射到数据里 表的名称 +func (t *Book) TableName() string { + return "books" }