补充mvc
This commit is contained in:
parent
39ab7d59a0
commit
df9ff23c81
186
book/api/book.go
Normal file
186
book/api/book.go
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gitlab.com/go-course-project/go17/book/config"
|
||||||
|
"gitlab.com/go-course-project/go17/book/model"
|
||||||
|
"gitlab.com/go-course-project/go17/book/response"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 构造函数, 用户初始化这个结构体
|
||||||
|
func NewBookHandler() *BookApiHandler {
|
||||||
|
return &BookApiHandler{
|
||||||
|
db: config.Get().MySQL.DB(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 面向对象
|
||||||
|
// BookApiHandler 他来实现接口的功能
|
||||||
|
type BookApiHandler struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提供注册功能, 提供一个Group
|
||||||
|
// book := server.Group("/api/books")
|
||||||
|
func (h *BookApiHandler) Registry(r *gin.Engine) {
|
||||||
|
book := r.Group("/api/books")
|
||||||
|
book.POST("", h.CreateBook)
|
||||||
|
book.GET("", h.ListBook)
|
||||||
|
book.GET("/:isbn", h.GetBook)
|
||||||
|
book.PUT("/:isbn", h.UpdateBook)
|
||||||
|
book.DELETE("/:isbn", h.DeleteBook)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置业务路有, Book类型的资源的 一套简单的CRUD
|
||||||
|
// 创建Book -> Book
|
||||||
|
// POST, Body
|
||||||
|
func (h *BookApiHandler) CreateBook(ctx *gin.Context) {
|
||||||
|
// 获取Book用户传达的参数
|
||||||
|
ins := new(model.Book)
|
||||||
|
if err := ctx.ShouldBindJSON(ins); err != nil {
|
||||||
|
response.Failed(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// book, save
|
||||||
|
if err := h.db.Save(ins).Error; err != nil {
|
||||||
|
response.Failed(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Success(ctx, ins)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询Book列表 -> []*Book
|
||||||
|
// SELECT * FROM `books`
|
||||||
|
func (h *BookApiHandler) ListBook(ctx *gin.Context) {
|
||||||
|
var books []model.Book
|
||||||
|
if err := h.db.Find(&books).Error; err != nil {
|
||||||
|
response.Failed(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(http.StatusOK, books)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询Book详情
|
||||||
|
func (h *BookApiHandler) GetBook(ctx *gin.Context) {
|
||||||
|
var ins model.Book
|
||||||
|
id := ctx.Param("isbn")
|
||||||
|
|
||||||
|
if err := h.db.Where("isbn = ?", id).Take(&ins).Error; err != nil {
|
||||||
|
response.Failed(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(http.StatusOK, ins)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新Book
|
||||||
|
func (h *BookApiHandler) UpdateBook(ctx *gin.Context) {
|
||||||
|
var ins model.Book
|
||||||
|
id := ctx.Param("isbn")
|
||||||
|
if err := h.db.Where("isbn = ?", id).Take(&ins).Error; err != nil {
|
||||||
|
response.Failed(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(http.StatusOK, ins)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除Book
|
||||||
|
func (h *BookApiHandler) DeleteBook(ctx *gin.Context) {
|
||||||
|
id := ctx.Param("isbn")
|
||||||
|
if err := h.db.Where("isbn = ?", id).Delete(model.Book{}).Error; err != nil {
|
||||||
|
response.Failed(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Registry(r *gin.Engine) {
|
||||||
|
// // 配置业务路有, 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
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
1
book/api/comment.go
Normal file
1
book/api/comment.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package api
|
1
book/api/user.go
Normal file
1
book/api/user.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package api
|
114
book/main.go
114
book/main.go
@ -3,17 +3,13 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"gitlab.com/go-course-project/go17/book/api"
|
||||||
"gitlab.com/go-course-project/go17/book/config"
|
"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
|
// 规定好风格: JSON Restful Api
|
||||||
func main() {
|
func main() {
|
||||||
// 从配置文件中加载配置
|
// 从配置文件中加载配置
|
||||||
@ -26,120 +22,14 @@ func main() {
|
|||||||
fmt.Printf("加载配置错误: %s\n", err)
|
fmt.Printf("加载配置错误: %s\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 访问加载后的配置
|
// 访问加载后的配置
|
||||||
conf := config.Get()
|
conf := config.Get()
|
||||||
|
|
||||||
// gin Engine, 它包装了http server
|
// gin Engine, 它包装了http server
|
||||||
server := gin.Default()
|
server := gin.Default()
|
||||||
|
api.NewBookHandler().Registry(server)
|
||||||
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 {
|
if err := server.Run(conf.App.Address()); err != nil {
|
||||||
log.Println(err)
|
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"
|
|
||||||
}
|
|
||||||
|
22
book/model/book.go
Normal file
22
book/model/book.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
}
|
1
book/model/comment.go
Normal file
1
book/model/comment.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package model
|
1
book/model/user.go
Normal file
1
book/model/user.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package model
|
47
book/response/README.md
Normal file
47
book/response/README.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# api 接口响应
|
||||||
|
|
||||||
|
接口要区分 成功/失败
|
||||||
|
|
||||||
|
## 经典
|
||||||
|
|
||||||
|
成功和响应 使用一套机制
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"data": <Book>,
|
||||||
|
"message": ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
成功:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"data": any,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
失败
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 10000,
|
||||||
|
"message": ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 根据贴合HTTP协议语义
|
||||||
|
|
||||||
|
通过 HTTP Code来定义 API接口返回是否成功
|
||||||
|
|
||||||
|
200
|
||||||
|
成功: 直接返回业务数据,不是再包装一层
|
||||||
|
```json
|
||||||
|
<Book>
|
||||||
|
```
|
||||||
|
|
||||||
|
失败之间返回失败信息, 400/401/403/500
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 10000,
|
||||||
|
"message": ""
|
||||||
|
}
|
||||||
|
```
|
15
book/response/response.go
Normal file
15
book/response/response.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Failed(ctx *gin.Context, err error) {
|
||||||
|
ctx.JSON(http.StatusBadRequest, gin.H{"code": 0, "msg": err.Error()})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Success(ctx *gin.Context, data any) {
|
||||||
|
ctx.JSON(http.StatusOK, data)
|
||||||
|
}
|
@ -18,6 +18,7 @@ func setupDatabase() *gorm.DB {
|
|||||||
panic("failed to connect database")
|
panic("failed to connect database")
|
||||||
}
|
}
|
||||||
db.AutoMigrate(&Book{}) // 自动迁移
|
db.AutoMigrate(&Book{}) // 自动迁移
|
||||||
|
|
||||||
return db.Debug()
|
return db.Debug()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user