go18/book/v4/apps/book/README.md

322 lines
9.4 KiB
Markdown
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.

# Book 业务分区
## 定义Book业务逻辑
业务功能: CRUD
1. 创建书籍(录入)
2. Book列表查询
3. Book详情查询
4. Book更新
5. Book删除
通过Go语言的里面的接口 来定义描述业务功能
```go
// book.Service, Book的业务定义
type Service interface {
// 1. 创建书籍(录入)
CreateBook(context.Context, *CreateBookRequest) (*Book, error)
// 2. Book列表查询
QueryBook(context.Context, *QueryBookRequest) (*types.Set[*Book], error)
// 3. Book详情查询
DescribeBook(context.Context, *DescribeBookRequest) (*Book, error)
// 4. Book更新
UpdateBook(context.Context, *UpdateBookRequest) (*Book, error)
// 5. Book删除
DeleteBook(context.Context, *DeleteBookRequest) error
}
```
## 业务的具体实现(TDD Test Drive Develop)
1. BookServiceImpl
```go
// CreateBook implements book.Service.
func (b *BookServiceImpl) CreateBook(context.Context, *book.CreateBookRequest) (*book.Book, error) {
panic("unimplemented")
}
// DeleteBook implements book.Service.
func (b *BookServiceImpl) DeleteBook(context.Context, *book.DeleteBookRequest) error {
panic("unimplemented")
}
// DescribeBook implements book.Service.
func (b *BookServiceImpl) DescribeBook(context.Context, *book.DescribeBookRequest) (*book.Book, error) {
panic("unimplemented")
}
// QueryBook implements book.Service.
func (b *BookServiceImpl) QueryBook(context.Context, *book.QueryBookRequest) (*types.Set[*book.Book], error) {
panic("unimplemented")
}
// UpdateBook implements book.Service.
func (b *BookServiceImpl) UpdateBook(context.Context, *book.UpdateBookRequest) (*book.Book, error) {
panic("unimplemented")
}
```
## 编写单元测试
```go
func TestCreateBook(t *testing.T) {
req := book.NewCreateBookRequest()
req.SetIsSale(true)
req.Title = "Go语言V4"
req.Author = "will"
req.Price = 10
ins, err := svc.CreateBook(ctx, req)
if err != nil {
t.Fatal(err)
}
t.Log(ins)
}
```
## 业务对象注册(ioc controller)
手动维护
```sh
pkg gloab
bookContrller = xxx
commentContrller = xx
...
```
通过容器来维护对象
```go
// Book业务的具体实现
type BookServiceImpl struct {
ioc.ObjectImpl
}
// 返回对象的名称, 因此我需要 服务名称
// 当前的MySQLBookServiceImpl 是 service book.APP_NAME 的 一个具体实现
// 当前的MongoDBBookServiceImpl 是 service book.APP_NAME 的 一个具体实现
func (s *BookServiceImpl) Name() string {
return book.APP_NAME
}
func init() {
ioc.Controller().Registry(&BookServiceImpl{})
}
```
## 面向接口
对象取处理, 断言他满足业务接口,然后我们以接口的方式来使用
```go
func GetService() Service {
return ioc.Controller().Get(APP_NAME).(Service)
}
const (
APP_NAME = "book"
)
```
第三方模块,可以依赖 接口进行开发
```go
// AddComment implements comment.Service.
func (c *CommentServiceImpl) AddComment(ctx context.Context, in *comment.AddCommentRequest) (*comment.Comment, error) {
// 能不能 直接Book Service的具体实现
// (&impl.BookServiceImpl{}).DescribeBook(ctx, nil)
// 依赖接口,面向接口编程, 不依赖具体实现
book.GetService().DescribeBook(ctx, nil)
panic("unimplemented")
}
```
## 开发API
接口是需求, 对业务进行设计, 可以选择把这些能力 以那种接口的访问对外提供服务
1. 不对外提供接口,仅仅作为其他的业务的依赖
2. (API)对外提供 HTTP接口, RESTful接口
3. (API)对内提供 RPC接口(JSON RPC/GRPC/thrift)
1. 开发业务功能
```go
func (h *BookApiHandler) createBook(ctx *gin.Context) {
req := book.NewCreateBookRequest()
if err := ctx.BindJSON(req); err != nil {
response.Failed(ctx, err)
return
}
ins, err := h.svc.CreateBook(ctx.Request.Context(), req)
if err != nil {
response.Failed(ctx, err)
return
}
// 返回响应
response.Success(ctx, ins)
}
```
2. 注册路由
```go
type BookApiHandler struct {
ioc.ObjectImpl
// 业务依赖
svc book.Service
}
func (h *BookApiHandler) Name() string {
return "books"
}
// 对象的初始化, 初始化对象的一些熟悉 &BookApiHandler{}
// 构造函数
// 当你这个对象初始化的时候,直接把的处理函数(ApiHandler注册给Server)
func (h *BookApiHandler) Init() error {
h.svc = book.GetService()
r := ioc_gin.ObjectRouter(h)
r.GET("", h.queryBook)
r.POST("", h.createBook)
return nil
}
func init() {
ioc.Api().Registry(&BookApiHandler{})
}
```
## 业务注册
每写完一个业务,就需要在 注册到ioc(注册表)
```go
// 业务加载区, 选择性的价值的业务处理对象
import (
// Api Impl
_ "122.51.31.227/go-course/go18/book/v4/apps/book/api"
// Service Impl
_ "122.51.31.227/go-course/go18/book/v4/apps/book/impl"
_ "122.51.31.227/go-course/go18/book/v4/apps/comment/impl"
)
```
## 启动服务
```go
import (
"github.com/infraboard/mcube/v2/ioc/server/cmd"
// 业务对象
_ "122.51.31.227/go-course/go18/book/v4/apps"
)
func main() {
// ioc框架 加载对象, 注入对象, 配置对象
// server.Gin.Run()
// application.Get().AppName
// http.Get().Host
// server.DefaultConfig.ConfigFile.Enabled = true
// server.DefaultConfig.ConfigFile.Path = "application.toml"
// server.Run(context.Background())
// 不能指定配置文件逻辑
// 使用者来说,体验不佳
// ioc 直接提供server, 直接run就行了
// mcube 包含 一个 gin Engine
// CLI, start 指令 -f 指定配置文件
cmd.Start()
}
```
```toml
[app]
name = "simple_api"
description = "app desc"
address = "localhost"
encrypt_key = "defualt app encrypt key"
[datasource]
provider = "mysql"
host = "127.0.0.1"
port = 3306
database = "go18"
username = "root"
password = "123456"
auto_migrate = false
debug = false
[http]
host = "127.0.0.1"
port = 8010
path_prefix = "api"
[comment]
max_comment_per_book = 200
```
```sh
➜ v4 git:(main) ✗ go run main.go -f application.toml start
[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)
2025-05-25T15:59:33+08:00 INFO config/gin/framework.go:41 > enable gin recovery component:GIN_WEBFRAMEWORK
200
[GIN-debug] GET /api/simple_api/v1/books --> 122.51.31.227/go-course/go18/book/v4/apps/book/api.(*BookApiHandler).queryBook-fm (4 handlers)
[GIN-debug] POST /api/simple_api/v1/books --> 122.51.31.227/go-course/go18/book/v4/apps/book/api.(*BookApiHandler).createBook-fm (4 handlers)
2025-05-25T15:59:33+08:00 INFO ioc/server/server.go:74 > loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1] component:SERVER
2025-05-25T15:59:33+08:00 INFO ioc/server/server.go:75 > loaded controllers: [comment.v1 book.v1] component:SERVER
2025-05-25T15:59:33+08:00 INFO ioc/server/server.go:76 > loaded apis: [books.v1] component:SERVER
2025-05-25T15:59:33+08:00 INFO ioc/server/server.go:77 > loaded defaults: [] component:SERVER
2025-05-25T15:59:33+08:00 INFO config/http/http.go:144 > HTTP服务启动成功, 监听地址: 127.0.0.1:8010 component:HTTP
```
## 总结
业务分区框架, 我们专注于业务对象的开发, mcube相对于一个工具箱承接其他非业务的公共功能
## 其他非功能需求
工具箱 提供很多工具,开箱即用, 比如health check, 比如metrics
```go
// 健康检查
_ "github.com/infraboard/mcube/v2/ioc/apps/health/gin"
// metrics
_ "github.com/infraboard/mcube/v2/ioc/apps/metric/gin"
```
[metric.v1 books.v1 health.v1] metric, health 使用注入的对象
```sh
➜ v4 git:(main) ✗ go run main.go -f application.toml start
[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)
2025-05-25T16:06:42+08:00 INFO config/gin/framework.go:41 > enable gin recovery component:GIN_WEBFRAMEWORK
200
[GIN-debug] GET /metrics/ --> github.com/infraboard/mcube/v2/ioc/apps/metric/gin.(*ginHandler).Registry.func1 (5 handlers)
2025-05-25T16:06:42+08:00 INFO metric/gin/metric.go:89 > Get the Metric using http://127.0.0.1:8010/metrics component:METRIC
[GIN-debug] GET /api/simple_api/v1/books --> 122.51.31.227/go-course/go18/book/v4/apps/book/api.(*BookApiHandler).queryBook-fm (5 handlers)
[GIN-debug] POST /api/simple_api/v1/books --> 122.51.31.227/go-course/go18/book/v4/apps/book/api.(*BookApiHandler).createBook-fm (5 handlers)
[GIN-debug] GET /healthz/ --> github.com/infraboard/mcube/v2/ioc/apps/health/gin.(*HealthChecker).HealthHandleFunc-fm (5 handlers)
2025-05-25T16:06:42+08:00 INFO health/gin/check.go:55 > Get the Health using http://127.0.0.1:8010/healthz component:HEALTH_CHECK
2025-05-25T16:06:42+08:00 INFO ioc/server/server.go:74 > loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1] component:SERVER
2025-05-25T16:06:42+08:00 INFO ioc/server/server.go:75 > loaded controllers: [comment.v1 book.v1] component:SERVER
2025-05-25T16:06:42+08:00 INFO ioc/server/server.go:76 > loaded apis: [metric.v1 books.v1 health.v1] component:SERVER
2025-05-25T16:06:42+08:00 INFO ioc/server/server.go:77 > loaded defaults: [] component:SERVER
2025-05-25T16:06:42+08:00 INFO config/http/http.go:144 > HTTP服务启动成功, 监听地址: 127.0.0.1:8010 component:HTTP
```