补充book api crud
This commit is contained in:
parent
79ad21efd0
commit
4cb4207d41
51
book/v1/README.md
Normal file
51
book/v1/README.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# 演示
|
||||||
|
|
||||||
|
## 启动
|
||||||
|
|
||||||
|
```sh
|
||||||
|
➜ go run v1/main.go
|
||||||
|
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
|
||||||
|
|
||||||
|
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
|
||||||
|
- using env: export GIN_MODE=release
|
||||||
|
- using code: gin.SetMode(gin.ReleaseMode)
|
||||||
|
|
||||||
|
[GIN-debug] GET /api/books --> main.(*BookApiHandler).ListBook-fm (3 handlers)
|
||||||
|
[GIN-debug] POST /api/books --> main.(*BookApiHandler).CreateBook-fm (3 handlers)
|
||||||
|
[GIN-debug] GET /api/books/:bn --> main.(*BookApiHandler).GetBook-fm (3 handlers)
|
||||||
|
[GIN-debug] PUT /api/books/:bn --> main.(*BookApiHandler).UpdateBook-fm (3 handlers)
|
||||||
|
[GIN-debug] DELETE /api/books/:bn --> main.(*BookApiHandler).DeleteBook-fm (3 handlers)
|
||||||
|
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
|
||||||
|
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
|
||||||
|
[GIN-debug] Listening and serving HTTP on :8080
|
||||||
|
```
|
||||||
|
|
||||||
|
## CRUD 示例
|
||||||
|
|
||||||
|
- 创建书籍:
|
||||||
|
```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 '{"title": "Go 语言进阶", "author": "张三", "price": 49.99}'
|
||||||
|
```
|
||||||
|
|
||||||
|
- 删除书籍:
|
||||||
|
```sh
|
||||||
|
curl -X DELETE http://localhost:8080/api/books/1
|
||||||
|
```
|
||||||
|
|
||||||
|
这样就完成了一个简单的使用 MySQL 的 Book CRUD 示例。你可以根据需要进一步扩展功能。
|
118
book/v1/main.go
118
book/v1/main.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -10,10 +11,21 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type BookSet struct {
|
||||||
|
// 总共多少个
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
// book清单
|
||||||
|
Items []*Book `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
type Book struct {
|
type Book struct {
|
||||||
// 对象Id
|
// 对象Id
|
||||||
ID uint `json:"id" gorm:"primaryKey;column:id"`
|
Id uint `json:"id" gorm:"primaryKey;column:id"`
|
||||||
|
|
||||||
|
BookSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookSpec struct {
|
||||||
// type 用于要使用gorm 来自动创建和更新表的时候 才需要定义
|
// type 用于要使用gorm 来自动创建和更新表的时候 才需要定义
|
||||||
Title string `json:"title" gorm:"column:title;type:varchar(200)" validate:"required"`
|
Title string `json:"title" gorm:"column:title;type:varchar(200)" validate:"required"`
|
||||||
Author string `json:"author" gorm:"column:author;type:varchar(200);index" validate:"required"`
|
Author string `json:"author" gorm:"column:author;type:varchar(200);index" validate:"required"`
|
||||||
@ -31,13 +43,13 @@ func (b *Book) TableName() string {
|
|||||||
// 初始化数据库
|
// 初始化数据库
|
||||||
func setupDatabase() *gorm.DB {
|
func setupDatabase() *gorm.DB {
|
||||||
// 变量更新
|
// 变量更新
|
||||||
dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
|
dsn := "root:123456@tcp(127.0.0.1:3306)/go18?charset=utf8mb4&parseTime=True&loc=Local"
|
||||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("failed to connect database")
|
panic("failed to connect database")
|
||||||
}
|
}
|
||||||
db.AutoMigrate(&Book{}) // 自动迁移
|
db.AutoMigrate(&Book{}) // 自动迁移
|
||||||
return db
|
return db.Debug()
|
||||||
}
|
}
|
||||||
|
|
||||||
var db = setupDatabase()
|
var db = setupDatabase()
|
||||||
@ -49,22 +61,41 @@ type BookApiHandler struct {
|
|||||||
|
|
||||||
// 实现后端分页的
|
// 实现后端分页的
|
||||||
func (h *BookApiHandler) ListBook(ctx *gin.Context) {
|
func (h *BookApiHandler) ListBook(ctx *gin.Context) {
|
||||||
|
set := &BookSet{}
|
||||||
|
|
||||||
|
// 给默认值
|
||||||
|
pn, ps := 1, 20
|
||||||
// /api/books?page_number=1&page_size=20
|
// /api/books?page_number=1&page_size=20
|
||||||
pageNumber := ctx.Query("page_number")
|
pageNumber := ctx.Query("page_number")
|
||||||
pn, err := strconv.ParseInt(pageNumber, 10, 64)
|
if pageNumber != "" {
|
||||||
if err != nil {
|
pnInt, err := strconv.ParseInt(pageNumber, 10, 64)
|
||||||
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
if err != nil {
|
||||||
return
|
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
||||||
}
|
return
|
||||||
pageSize := ctx.Query("page_size")
|
}
|
||||||
ps, err := strconv.ParseInt(pageSize, 10, 64)
|
pn = int(pnInt)
|
||||||
if err != nil {
|
|
||||||
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
pageSize := ctx.Query("page_size")
|
||||||
bookList := []Book{}
|
if pageSize != "" {
|
||||||
|
psInt, err := strconv.ParseInt(pageSize, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ps = int(psInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
query := db.Model(&Book{})
|
||||||
|
// 关键字过滤
|
||||||
|
kws := ctx.Query("keywords")
|
||||||
|
if kws != "" {
|
||||||
|
// where title like %kws%
|
||||||
|
query = query.Where("title LIKE ?", "%"+kws+"%x")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他过滤条件
|
||||||
|
|
||||||
// select * from books
|
// select * from books
|
||||||
// 通过sql的offset limte 来实现分页
|
// 通过sql的offset limte 来实现分页
|
||||||
// offset (page_number -1) * page_size, limit page_size
|
// offset (page_number -1) * page_size, limit page_size
|
||||||
@ -72,14 +103,13 @@ func (h *BookApiHandler) ListBook(ctx *gin.Context) {
|
|||||||
// 3 offset 40, 20
|
// 3 offset 40, 20
|
||||||
// 4 offset 3 * 20, 20
|
// 4 offset 3 * 20, 20
|
||||||
offset := (pn - 1) * ps
|
offset := (pn - 1) * ps
|
||||||
if err := db.Offset(int(offset)).Limit(int(ps)).Find(&bookList).Error; err != nil {
|
if err := query.Count(&set.Total).Offset(int(offset)).Limit(int(ps)).Find(&set.Items).Error; err != nil {
|
||||||
ctx.JSON(500, gin.H{"code": 500, "message": err.Error()})
|
ctx.JSON(500, gin.H{"code": 500, "message": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取总数, 总共多少个, 总共有多少页
|
// 获取总数, 总共多少个, 总共有多少页
|
||||||
ctx.JSON(200, bookList)
|
ctx.JSON(200, set)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *BookApiHandler) CreateBook(ctx *gin.Context) {
|
func (h *BookApiHandler) CreateBook(ctx *gin.Context) {
|
||||||
@ -95,7 +125,7 @@ func (h *BookApiHandler) CreateBook(ctx *gin.Context) {
|
|||||||
// ctx.GetHeader("Authincation")
|
// ctx.GetHeader("Authincation")
|
||||||
|
|
||||||
// new(Book)
|
// new(Book)
|
||||||
bookInstance := &Book{}
|
bookSpecInstance := &BookSpec{}
|
||||||
// // 通过JSON的 Struct Tag
|
// // 通过JSON的 Struct Tag
|
||||||
// // bookInstance.Title = "Go语言"
|
// // bookInstance.Title = "Go语言"
|
||||||
// if err := json.Unmarshal(payload, bookInstance); err != nil {
|
// if err := json.Unmarshal(payload, bookInstance); err != nil {
|
||||||
@ -103,11 +133,23 @@ func (h *BookApiHandler) CreateBook(ctx *gin.Context) {
|
|||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
// 获取到bookInstance
|
// 获取到bookInstance
|
||||||
if err := ctx.BindJSON(bookInstance); err != nil {
|
// 参数是不是为空
|
||||||
|
if err := ctx.BindJSON(bookSpecInstance); err != nil {
|
||||||
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 有没有能够检查某个字段是否是必须填
|
||||||
|
// Gin 集成 validator这个库, 通过 struct tag validate 来表示这个字段是否允许为空
|
||||||
|
// validate:"required"
|
||||||
|
// 在数据Bind的时候,这个逻辑会自动运行
|
||||||
|
// if bookSpecInstance.Author == "" {
|
||||||
|
// ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
bookInstance := &Book{BookSpec: *bookSpecInstance}
|
||||||
|
|
||||||
// 数据入库(Grom), 补充自增Id的值
|
// 数据入库(Grom), 补充自增Id的值
|
||||||
if err := db.Save(bookInstance).Error; err != nil {
|
if err := db.Save(bookInstance).Error; err != nil {
|
||||||
ctx.JSON(400, gin.H{"code": 500, "message": err.Error()})
|
ctx.JSON(400, gin.H{"code": 500, "message": err.Error()})
|
||||||
@ -115,48 +157,52 @@ func (h *BookApiHandler) CreateBook(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 返回响应
|
// 返回响应
|
||||||
ctx.JSON(200, bookInstance)
|
ctx.JSON(http.StatusCreated, bookInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *BookApiHandler) GetBook(ctx *gin.Context) {
|
func (h *BookApiHandler) GetBook(ctx *gin.Context) {
|
||||||
// URI
|
bookInstance := &Book{}
|
||||||
bnStr := ctx.Param("bn")
|
// 需要从数据库中获取一个对象
|
||||||
bn, err := strconv.ParseInt(bnStr, 10, 64)
|
if err := db.Where("id = ?", ctx.Param("bn")).Take(bookInstance).Error; err != nil {
|
||||||
if err != nil {
|
ctx.JSON(400, gin.H{"code": 500, "message": err.Error()})
|
||||||
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println(bn)
|
|
||||||
|
ctx.JSON(200, bookInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *BookApiHandler) UpdateBook(ctx *gin.Context) {
|
func (h *BookApiHandler) UpdateBook(ctx *gin.Context) {
|
||||||
// URI
|
|
||||||
bnStr := ctx.Param("bn")
|
bnStr := ctx.Param("bn")
|
||||||
bn, err := strconv.ParseInt(bnStr, 10, 64)
|
bn, err := strconv.ParseInt(bnStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println(bn)
|
|
||||||
|
|
||||||
// 读取body里面的参数
|
// 读取body里面的参数
|
||||||
bookInstance := &Book{}
|
bookInstance := &Book{
|
||||||
|
Id: uint(bn),
|
||||||
|
}
|
||||||
// 获取到bookInstance
|
// 获取到bookInstance
|
||||||
if err := ctx.BindJSON(bookInstance); err != nil {
|
if err := ctx.BindJSON(&bookInstance.BookSpec); err != nil {
|
||||||
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := db.Where("id = ?", bookInstance.Id).Updates(bookInstance).Error; err != nil {
|
||||||
|
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, bookInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *BookApiHandler) DeleteBook(ctx *gin.Context) {
|
func (h *BookApiHandler) DeleteBook(ctx *gin.Context) {
|
||||||
// URI
|
if err := db.Where("id = ?", ctx.Param("bn")).Delete(&Book{}).Error; err != nil {
|
||||||
bnStr := ctx.Param("bn")
|
|
||||||
bn, err := strconv.ParseInt(bnStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println(bn)
|
ctx.JSON(http.StatusNoContent, "ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user