补充controller
This commit is contained in:
parent
df9ff23c81
commit
3ca5fb7eca
@ -2,9 +2,11 @@ package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/go-course-project/go17/book/config"
|
||||
"gitlab.com/go-course-project/go17/book/controller"
|
||||
"gitlab.com/go-course-project/go17/book/model"
|
||||
"gitlab.com/go-course-project/go17/book/response"
|
||||
"gorm.io/gorm"
|
||||
@ -14,6 +16,7 @@ import (
|
||||
func NewBookHandler() *BookApiHandler {
|
||||
return &BookApiHandler{
|
||||
db: config.Get().MySQL.DB(),
|
||||
svc: controller.NewBookController(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +24,8 @@ func NewBookHandler() *BookApiHandler {
|
||||
// BookApiHandler 他来实现接口的功能
|
||||
type BookApiHandler struct {
|
||||
db *gorm.DB
|
||||
|
||||
svc *controller.BookController
|
||||
}
|
||||
|
||||
// 提供注册功能, 提供一个Group
|
||||
@ -39,14 +44,14 @@ func (h *BookApiHandler) Registry(r *gin.Engine) {
|
||||
// POST, Body
|
||||
func (h *BookApiHandler) CreateBook(ctx *gin.Context) {
|
||||
// 获取Book用户传达的参数
|
||||
ins := new(model.Book)
|
||||
if err := ctx.ShouldBindJSON(ins); err != nil {
|
||||
req := new(model.BookSpec)
|
||||
if err := ctx.ShouldBindJSON(req); err != nil {
|
||||
response.Failed(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
// book, save
|
||||
if err := h.db.Save(ins).Error; err != nil {
|
||||
ins, err := h.svc.CreateBook(ctx.Request.Context(), req)
|
||||
if err != nil {
|
||||
response.Failed(ctx, err)
|
||||
return
|
||||
}
|
||||
@ -67,13 +72,22 @@ func (h *BookApiHandler) ListBook(ctx *gin.Context) {
|
||||
|
||||
// 查询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 {
|
||||
strId := ctx.Param("isbn")
|
||||
id, err := strconv.ParseInt(strId, 10, 64)
|
||||
if err != nil {
|
||||
response.Failed(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 传递HTTP请求的上下文
|
||||
ins, err := h.svc.GetBook(ctx.Request.Context(), &controller.GetBookRequest{
|
||||
Isbn: id,
|
||||
})
|
||||
if err != nil {
|
||||
response.Failed(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, ins)
|
||||
}
|
||||
|
||||
|
@ -1 +1,37 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/go-course-project/go17/book/config"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 构造函数, 用户初始化这个结构体
|
||||
func NewCommentApiHandler() *CommentApiHandler {
|
||||
return &CommentApiHandler{
|
||||
db: config.Get().MySQL.DB(),
|
||||
}
|
||||
}
|
||||
|
||||
// 面向对象
|
||||
// BookApiHandler 他来实现接口的功能
|
||||
type CommentApiHandler struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (h *CommentApiHandler) AddComment(ctx *gin.Context) {
|
||||
// book id, user a, comment
|
||||
|
||||
// book id
|
||||
// 判断book id 是不是合法, 到底有没有这本book
|
||||
// 1. NewBookHandler().GetBook(ctx)
|
||||
// 2. 把这个逻辑再写一套
|
||||
// if err := h.db.Where("isbn = ?", id).Take(&ins).Error; err != nil {
|
||||
// response.Failed(ctx, err)
|
||||
// return
|
||||
// }
|
||||
|
||||
// 你需要什么?
|
||||
// 你需要一个 功能(业务处理逻辑): GetBook() (<Book>, error)
|
||||
// controller.GetBook()
|
||||
}
|
||||
|
@ -1 +1,9 @@
|
||||
# 业务层 (业务处理逻辑)
|
||||
|
||||
|
||||
|
||||
## 和谐业务层:
|
||||
|
||||
+ 复杂的业务逻辑处理(controller之间相互调用)
|
||||
+ 这个内部功能(公共功能) 不需要提供接口, 需要被其他多个业务模块引用
|
||||
+ 复杂的业务是需要有单元测试
|
62
book/controller/book.go
Normal file
62
book/controller/book.go
Normal file
@ -0,0 +1,62 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitlab.com/go-course-project/go17/book/config"
|
||||
"gitlab.com/go-course-project/go17/book/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 构造函数, 用户初始化这个结构体
|
||||
func NewBookController() *BookController {
|
||||
return &BookController{
|
||||
db: config.Get().MySQL.DB(),
|
||||
}
|
||||
}
|
||||
|
||||
type BookController struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
type GetBookRequest struct {
|
||||
Isbn int64
|
||||
// ...
|
||||
// TraceId string
|
||||
}
|
||||
|
||||
// 怎么定义你的Controller的参数
|
||||
// 怎么定义你BookController的接口(interface)
|
||||
// 函数名称 + 参数 + 返回 + 异常
|
||||
// 参数 一定要 注意 兼容性
|
||||
// 1.参数类型,个数
|
||||
// 怎么设计一个 具有良好兼容性的接口, 个数,类型
|
||||
// 采用一个请求类型 作为参数, 变更请求结构体, 不会变更类型,有更好的兼容性
|
||||
// 1. 非功能性的需求, 要添加TraceID, 请求支持取消
|
||||
// go context.Context 既能存储数据,也能做Gorouteine的取消
|
||||
// 这个跟接口是无关的,是纯业务处理
|
||||
func (c *BookController) GetBook(ctx context.Context, req *GetBookRequest) (*model.Book, error) {
|
||||
ins := &model.Book{}
|
||||
|
||||
if err := c.db.WithContext(ctx).Where("isbn = ?", req.Isbn).Take(ins).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ins, nil
|
||||
}
|
||||
|
||||
// 这一层做强教育,避免内部相互调用是,处理未校验的情况
|
||||
func (c *BookController) CreateBook(ctx context.Context, req *model.BookSpec) (*model.Book, error) {
|
||||
if err := req.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// book, save
|
||||
ins := &model.Book{
|
||||
BookSpec: *req,
|
||||
}
|
||||
if err := c.db.Save(ins).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ins, nil
|
||||
}
|
42
book/controller/book_test.go
Normal file
42
book/controller/book_test.go
Normal file
@ -0,0 +1,42 @@
|
||||
package controller_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"gitlab.com/go-course-project/go17/book/controller"
|
||||
"gitlab.com/go-course-project/go17/book/model"
|
||||
)
|
||||
|
||||
func TestGetBook(t *testing.T) {
|
||||
book := controller.NewBookController()
|
||||
ins, err := book.GetBook(context.Background(), &controller.GetBookRequest{
|
||||
Isbn: 5,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(ins)
|
||||
}
|
||||
|
||||
// INSERT INTO `books` (`title`,`author`,`price`,`is_sale`) VALUES ('Go语言','will',10,NULL)
|
||||
//
|
||||
// {
|
||||
// "isbn": 5,
|
||||
// "title": "Go语言",
|
||||
// "author": "will",
|
||||
// "price": 10,
|
||||
// "is_sale": null
|
||||
// }
|
||||
func TestCreateBook(t *testing.T) {
|
||||
book := controller.NewBookController()
|
||||
ins, err := book.CreateBook(context.Background(), &model.BookSpec{
|
||||
Author: "will",
|
||||
Price: 10,
|
||||
Title: "Go语言",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(ins)
|
||||
}
|
39
book/controller/comment.go
Normal file
39
book/controller/comment.go
Normal file
@ -0,0 +1,39 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/go-course-project/go17/book/config"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 构造函数, 用户初始化这个结构体
|
||||
func NewCommentController() *CommentController {
|
||||
return &CommentController{
|
||||
db: config.Get().MySQL.DB(),
|
||||
book: NewBookController(),
|
||||
}
|
||||
}
|
||||
|
||||
type CommentController struct {
|
||||
db *gorm.DB
|
||||
book *BookController
|
||||
}
|
||||
|
||||
func (h *CommentController) AddComment(ctx *gin.Context) {
|
||||
// book id, user a, comment
|
||||
|
||||
// book id
|
||||
// 判断book id 是不是合法, 到底有没有这本book
|
||||
// 1. NewBookHandler().GetBook(ctx)
|
||||
// 2. 把这个逻辑再写一套
|
||||
// if err := h.db.Where("isbn = ?", id).Take(&ins).Error; err != nil {
|
||||
// response.Failed(ctx, err)
|
||||
// return
|
||||
// }
|
||||
|
||||
// 你需要什么?
|
||||
// 你需要一个 功能(业务处理逻辑): GetBook() (<Book>, error)
|
||||
// controller.GetBook()
|
||||
|
||||
// h.book.GetBook(ctx, isbn)
|
||||
}
|
@ -1,5 +1,16 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/infraboard/mcube/v2/tools/pretty"
|
||||
)
|
||||
|
||||
var (
|
||||
v = validator.New()
|
||||
)
|
||||
|
||||
// Book 结构体定义
|
||||
type Book struct {
|
||||
// grom:"column:isbn;", 具体文档: https://gorm.io/docs/models.html#Fields-Tags
|
||||
@ -7,15 +18,37 @@ type Book struct {
|
||||
BookSpec
|
||||
}
|
||||
|
||||
// ret, err := json.MarshalIndent(e, "", jsonIndent)
|
||||
//
|
||||
// if err != nil {
|
||||
// return fmt.Sprintf("%+v", e)
|
||||
// }
|
||||
//
|
||||
// return string(ret)
|
||||
func (b *Book) String() string {
|
||||
// 我提炼出来功能代码工具
|
||||
return pretty.ToJSON(b)
|
||||
}
|
||||
|
||||
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"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// 怎么校验 struct 参数
|
||||
func (r *BookSpec) Validate() error {
|
||||
if r.Author == "" {
|
||||
return fmt.Errorf("author 不能为空")
|
||||
}
|
||||
|
||||
// 通用的校验逻辑,比如是否为空,可以考虑使用validate包
|
||||
return v.Struct(r)
|
||||
}
|
||||
|
||||
// 定义该对象映射到数据里 表的名称
|
||||
func (t *Book) TableName() string {
|
||||
return "books"
|
||||
|
4
go.mod
4
go.mod
@ -4,6 +4,8 @@ go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-playground/validator/v10 v10.20.0
|
||||
github.com/infraboard/mcube/v2 v2.0.44
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gorm v1.25.12
|
||||
@ -18,7 +20,6 @@ require (
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
@ -38,4 +39,5 @@ require (
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
10
go.sum
10
go.sum
@ -27,9 +27,11 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/infraboard/mcube/v2 v2.0.44 h1:dspnLDspWpz5r6YgFTOmIlWE4kjog0082luhvd8AUds=
|
||||
github.com/infraboard/mcube/v2 v2.0.44/go.mod h1:UkjuO7zbehNNvAsA1kZMB2ztaZlDY9XmTfBnNnilzB4=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
@ -82,8 +84,6 @@ golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
@ -98,3 +98,5 @@ gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
Loading…
x
Reference in New Issue
Block a user