first commit

This commit is contained in:
zzw
2026-08-05 17:37:32 +08:00
commit 38be479cef
72 changed files with 15670 additions and 0 deletions
+344
View File
@@ -0,0 +1,344 @@
## 如何加一个新服务
以加 `order` 为例(对标现有 `product`)。
### 0. 安装 goctl
```bash
go install github.com/zeromicro/go-zero/tools/goctl@latest
goctl --version
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
```
### 1. 创建 RPC 服务(goctl
在仓库根目录执行:
```bash
goctl rpc new order
cd order
```
### 2. 将 proto 移到 `proto/` 目录
`goctl rpc new` 默认把 proto 放在服务根目录(如 `order/order.proto`)。统一挪到 `proto/`
```bash
mkdir proto
mv order.proto proto/
```
### 4. 配置 Zero 兼容 Nacos
编辑 `order/internal/config/config.go`
```go
package config
import "github.com/zeromicro/go-zero/zrpc"
type Config struct {
zrpc.RpcServerConf
Nacos NacosConf
}
type NacosConf struct {
Hosts []string
NamespaceId string `json:",optional"`
Group string `json:",optional"`
RegisterIP string `json:",optional"`
}
```
### 5. 配置服务名与监听端口
`order/etc/order.yaml`
```yaml
Name: order-service # 注册到 Nacos 的 serviceNameBFF Upstream.Target 必须与此一致
ListenOn: 0.0.0.0:10200
Nacos:
Hosts:
- rnacos:8848
NamespaceId: test
Group: LONE_SERVICES
RegisterIP: order # Docker Compose 里的服务名 / 主机名
Mysql:
Host: mysql
Port: 3306
User: root
Password: "123123"
Database: dms-order
Charset: utf8mb4
Prefix:
```
### 3. 构建 mod
编辑 `order/go.mod`
```go
go 1.24.3
require (
github.com/zeromicro/go-zero v1.10.2
google.golang.org/grpc v1.80.0
google.golang.org/protobuf v1.36.11
)
```
```bash
go mod tidy
```
编辑 `order/go.mod` 增加本地包 pkg.local
```go
require (
github.com/zeromicro/go-zero v1.10.2
google.golang.org/grpc v1.80.0
google.golang.org/protobuf v1.36.11
pkg.local v0.0.0
)
replace pkg.local => ../pkg
```
### 6. 服务注册
编辑 `order/order.go`
```go
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
if err := discovery.Init(discovery.Config{
Hosts: c.Nacos.Hosts,
NamespaceId: c.Nacos.NamespaceId,
Group: c.Nacos.Group,
}); err != nil {
log.Fatalf("nacos init: %v", err)
}
registerIP := c.Nacos.RegisterIP
port, err := listenPort(c.ListenOn)
if err != nil {
log.Fatalf("parse ListenOn: %v", err)
}
if err := discovery.Register(discovery.Instance{
ServiceName: c.Name,
IP: registerIP,
Port: port,
Group: c.Nacos.Group,
}); err != nil {
log.Fatalf("nacos register: %v", err)
}
defer func() {
if err := discovery.Deregister(); err != nil {
log.Printf("nacos deregister: %v", err)
}
}()
ctx := svc.NewServiceContext(c)
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
order.RegisterOrderServer(grpcServer, server.NewOrderServer(ctx))
if c.Mode == service.DevMode || c.Mode == service.TestMode {
reflection.Register(grpcServer)
}
})
defer s.Stop()
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
s.Start()
}
func listenPort(listenOn string) (uint64, error) {
_, portStr, err := net.SplitHostPort(listenOn)
if err != nil {
return 0, err
}
return strconv.ParseUint(portStr, 10, 64)
}
```
编辑 `order/order.go`:增加本地包
```go
import (
"pkg.local/discovery"
)
```
再次执行
```bash
go mod tidy
```
### 8. 接入 Docker Compose
`deploy/docker-compose.override.yml` 增加服务:
```yaml
order:
image: golang:1.24.3
volumes:
- ..:/src
- go-mod-cache:/go/pkg/mod
working_dir: /src/order
command: go run . -f etc/order.yaml
ports:
- "10200:10200"
environment:
NACOS_SERVER_ADDR: rnacos:8848
depends_on:
- rnacos
```
### 9. 生成 ProtoSet 给 BFF
```bash
protoc --include_imports --proto_path=proto --descriptor_set_out=../bff/etc/order.pb order.proto
```
### 10. 在 BFF 配 Upstream + Mapping
编辑 `bff/etc/bff.yaml`,增加一段(go-zero gateway **每个 RPC 都要写 Mapping**):
```yaml
- Name: order
Grpc:
Target: order-service # 必须等于 order.yaml 的 Name
Timeout: 5000
ProtoSets:
- etc/order.pb
Mappings:
- Method: post
Path: /admin/v3/order/ping
RpcPath: order.Order/Ping
```
### 11. 加接口需要
只改业务逻辑(`internal/logic/`)不必跑 goctl。
`proto/order.proto`(新增/改名 RPC、改字段等)后,按文末「三条命令何时用」处理;
若 HTTP 路径有变,再改第 10 步的 Mapping。
---
### 命令 ①:生成服务端 pb / grpc
```bash
protoc -I. -I../pkg/third_party --go_out=. --go-grpc_out=. proto/order.proto
```
**什么时候跑:**
- 只改 **校验规则**(必填/长度/范围等)→ **只跑这条**
- 增删改字段、增删 RPC → 也要跑(服务端描述符要更新)
### 命令 ②:生成 BFF ProtoSet
```bash
protoc -I. -I../pkg/third_party --descriptor_set_out=../bff/etc/product.pb --include_imports proto/order.proto
```
**什么时候跑:**
- 增删改 **字段**BFF gateway 编解码需要)
- 增删 **RPC**
### 命令 ③:goctl 生成/更新脚手架
```bash
goctl rpc protoc proto/order.proto --go_out=. --go-grpc_out=. --zrpc_out=.
```
**什么时候跑:**
- **新增 RPC**:需要生成 `internal/logic`、更新 `server` / `productclient`
- 注意:可能覆盖已改过的 `product.go` 等,生成后对比合并;也可用手写 logic/server 代替
## Proto 常用校验规则(protovalidate
文档:https://protovalidate.com/schemas/standard-rules/
依赖:`import "buf/validate/validate.proto";`,服务启动挂 `pkg.local/validate` 拦截器。
### 必填字符串
```protobuf
string name = 1 [(buf.validate.field).string = {min_len: 1, max_len: 256}];
```
`min_len: 1` 表示不能为空串。
### 可选字符串(仅限长度)
```protobuf
string subhead = 2 [(buf.validate.field).string = {max_len: 255}];
```
空串可通过;有内容时限制最大长度。
### 必填数值(含 0 合法)
```protobuf
double price = 6 [(buf.validate.field).double = {gte: 0}];
int32 period_validity = 16 [(buf.validate.field).int32 = {gte: 0}];
```
### 非必填数值(0 表示未传,跳过校验)
```protobuf
double store_price = 7 [(buf.validate.field) = {
ignore: IGNORE_IF_ZERO_VALUE,
double: {gte: 0}
}];
```
有值时仍要求 `>= 0`;未传/为 0 不校验。
### 枚举 / 固定取值(0 表示未传)
```protobuf
uint32 type = 19 [(buf.validate.field) = {
ignore: IGNORE_IF_ZERO_VALUE,
uint32: {in: [1, 2, 3]}
}];
uint32 sales_model = 4 [(buf.validate.field) = {
ignore: IGNORE_IF_ZERO_VALUE,
uint32: {in: [1, 2]}
}];
```
### ID 必须大于 0
```protobuf
int64 id = 1 [(buf.validate.field).int64 = {gt: 0}];
```
### 无规则字段
```protobuf
uint32 number = 20; // 不做 protovalidate
```
### 删除字段编号(避免复用)
```protobuf
// reserved 2;
```
业务条件校验(如「普通商品必须带齐价格」)仍写在 `internal/logic`,不要全塞进 proto。