go18/book/v1/main.go
2025-05-06 11:25:55 +08:00

234 lines
5.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"net/http"
"os"
"strconv"
"github.com/gin-gonic/gin"
"github.com/infraboard/mcube/v2/types"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type BookSet struct {
// 总共多少个
Total int64 `json:"total"`
// book清单
Items []*Book `json:"items"`
}
type Book struct {
// 对象Id
Id uint `json:"id" gorm:"primaryKey;column:id"`
BookSpec
}
type BookSpec struct {
// type 用于要使用gorm 来自动创建和更新表的时候 才需要定义
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"`
Price float64 `json:"price" gorm:"column:price" validate:"required"`
// bool false
// nil 是零值, false
IsSale *bool `json:"is_sale" gorm:"column:is_sale"`
}
// books
func (b *Book) TableName() string {
return "books"
}
// 初始化数据库
func setupDatabase() *gorm.DB {
// 变量更新
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{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&Book{}) // 自动迁移
return db.Debug()
}
var db = setupDatabase()
var h = &BookApiHandler{}
type BookApiHandler struct {
}
// 实现后端分页的
func (h *BookApiHandler) ListBook(ctx *gin.Context) {
set := &BookSet{}
// List<*Book>
// *Set[T]
types.New[*Book]()
// 给默认值
pn, ps := 1, 20
// /api/books?page_number=1&page_size=20
pageNumber := ctx.Query("page_number")
if pageNumber != "" {
pnInt, err := strconv.ParseInt(pageNumber, 10, 64)
if err != nil {
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
return
}
pn = int(pnInt)
}
pageSize := ctx.Query("page_size")
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
// 通过sql的offset limte 来实现分页
// offset (page_number -1) * page_size, limit page_size
// 2 offset 20, 20
// 3 offset 40, 20
// 4 offset 3 * 20, 20
offset := (pn - 1) * ps
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()})
return
}
// 获取总数, 总共多少个, 总共有多少页
ctx.JSON(200, set)
}
func (h *BookApiHandler) CreateBook(ctx *gin.Context) {
// payload, err := io.ReadAll(ctx.Request.Body)
// if err != nil {
// ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
// return
// }
// defer ctx.Request.Body.Close()
// // {"title": "Go语言"}
// c.Request.Header.Get(key)
// ctx.GetHeader("Authincation")
// new(Book)
bookSpecInstance := &BookSpec{}
// // 通过JSON的 Struct Tag
// // bookInstance.Title = "Go语言"
// if err := json.Unmarshal(payload, bookInstance); err != nil {
// ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
// return
// }
// 获取到bookInstance
// 参数是不是为空
if err := ctx.BindJSON(bookSpecInstance); err != nil {
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
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的值
if err := db.Save(bookInstance).Error; err != nil {
ctx.JSON(400, gin.H{"code": 500, "message": err.Error()})
return
}
// 返回响应
ctx.JSON(http.StatusCreated, bookInstance)
}
func (h *BookApiHandler) GetBook(ctx *gin.Context) {
bookInstance := &Book{}
// 需要从数据库中获取一个对象
if err := db.Where("id = ?", ctx.Param("bn")).Take(bookInstance).Error; err != nil {
ctx.JSON(400, gin.H{"code": 500, "message": err.Error()})
return
}
ctx.JSON(200, bookInstance)
}
func (h *BookApiHandler) UpdateBook(ctx *gin.Context) {
bnStr := ctx.Param("bn")
bn, err := strconv.ParseInt(bnStr, 10, 64)
if err != nil {
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
return
}
// 读取body里面的参数
bookInstance := &Book{
Id: uint(bn),
}
// 获取到bookInstance
if err := ctx.BindJSON(&bookInstance.BookSpec); err != nil {
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
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) {
if err := db.Where("id = ?", ctx.Param("bn")).Delete(&Book{}).Error; err != nil {
ctx.JSON(400, gin.H{"code": 400, "message": err.Error()})
return
}
ctx.JSON(http.StatusNoContent, "ok")
}
func main() {
server := gin.Default()
// Book Restful API
// List of books
server.GET("/api/books", h.ListBook)
// Create new book
// Body: HTTP Entity
server.POST("/api/books", h.CreateBook)
// Get book by book number
server.GET("/api/books/:bn", h.GetBook)
// Update book
server.PUT("/api/books/:bn", h.UpdateBook)
// Delete book
server.DELETE("/api/books/:bn", h.DeleteBook)
if err := server.Run(":8080"); err != nil {
fmt.Println(err)
os.Exit(1)
}
}