feat: user base
This commit is contained in:
@@ -44,8 +44,6 @@ 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)
|
||||
|
||||
在仓库根目录执行:
|
||||
@@ -55,8 +53,6 @@ goctl rpc new order
|
||||
cd order
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2. 将 proto 移到 `proto/` 目录
|
||||
|
||||
`goctl rpc new` 默认把 proto 放在服务根目录(如 `order/order.proto`)。统一挪到 `proto/`:
|
||||
@@ -66,8 +62,6 @@ mkdir proto
|
||||
mv order.proto proto/
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 3. Zero 兼容 Nacos 等配置
|
||||
|
||||
编辑 `order/internal/config/config.go`:
|
||||
@@ -88,8 +82,6 @@ type NacosConf struct {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4. 配置服务名与监听端口
|
||||
|
||||
编辑 `order/etc/order.yaml`:
|
||||
@@ -104,8 +96,6 @@ Nacos:
|
||||
ConfigID: develop-admin
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 5. 构建 mod
|
||||
|
||||
编辑 `order/go.mod` 增加本地包 pkg.local
|
||||
@@ -126,11 +116,11 @@ replace pkg.local => ../pkg
|
||||
|
||||
```go
|
||||
"pkg.local/discovery"
|
||||
"pkg.local/log"
|
||||
"pkg.local/modelbase"
|
||||
"pkg.local/mysql"
|
||||
"pkg.local/redis"
|
||||
"pkg.local/validate"
|
||||
"pkg.local/utils"
|
||||
```
|
||||
|
||||
增加初始化
|
||||
@@ -138,135 +128,127 @@ replace pkg.local => ../pkg
|
||||
```go
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
var c config.Config
|
||||
conf.MustLoad(*configFile, &c)
|
||||
flag.Parse()
|
||||
var c config.Config
|
||||
conf.MustLoad(*configFile, &c)
|
||||
|
||||
// Nacos配置拉取初始化
|
||||
nacosParam := utils.NacosConfig{
|
||||
Hosts: c.Nacos.Hosts,
|
||||
NamespaceId: c.Nacos.NamespaceId,
|
||||
Group: c.Nacos.Group,
|
||||
ConfigID: c.Nacos.ConfigID,
|
||||
}
|
||||
utils.InitConfig(nacosParam)
|
||||
nacosParam := utils.NacosConfig{
|
||||
Hosts: c.Nacos.Hosts,
|
||||
NamespaceId: c.Nacos.NamespaceId,
|
||||
Group: c.Nacos.Group,
|
||||
ConfigID: c.Nacos.ConfigID,
|
||||
}
|
||||
utils.InitConfig(nacosParam)
|
||||
|
||||
// 日志配置
|
||||
logConf := logx.LogConf{
|
||||
ServiceName: utils.GetConfigString("log.serviceName"),
|
||||
Mode: utils.GetConfigString("log.mode"),
|
||||
Encoding: utils.GetConfigString("log.encoding"),
|
||||
Level: utils.GetConfigString("log.level"),
|
||||
Path: utils.GetConfigString("log.path"),
|
||||
KeepDays: utils.GetConfigInt("log.keepDays"),
|
||||
MaxSize: utils.GetConfigInt("log.maxSize"),
|
||||
MaxBackups: utils.GetConfigInt("log.maxBackups"),
|
||||
Compress: utils.GetConfigBool("log.compress"),
|
||||
}
|
||||
logx.SetUp(logConf)
|
||||
logx.AddWriter(logx.NewWriter(os.Stdout))
|
||||
logConf := logx.LogConf{
|
||||
ServiceName: utils.GetConfigString("log.serviceName"),
|
||||
Mode: utils.GetConfigString("log.mode"),
|
||||
Encoding: utils.GetConfigString("log.encoding"),
|
||||
Level: utils.GetConfigString("log.level"),
|
||||
Path: utils.GetConfigString("log.path"),
|
||||
KeepDays: utils.GetConfigInt("log.keepDays"),
|
||||
MaxSize: utils.GetConfigInt("log.maxSize"),
|
||||
MaxBackups: utils.GetConfigInt("log.maxBackups"),
|
||||
Compress: utils.GetConfigBool("log.compress"),
|
||||
}
|
||||
logx.SetUp(logConf)
|
||||
logx.AddWriter(logx.NewWriter(os.Stdout))
|
||||
|
||||
listenOn := utils.GetConfigString("base.listenOn")
|
||||
mode := utils.GetConfigString("base.mode")
|
||||
serviceName := utils.GetConfigString("base.name")
|
||||
registerIP := utils.GetConfigString("base.registerIP")
|
||||
listenOn := utils.GetConfigString("base.listenOn")
|
||||
mode := utils.GetConfigString("base.mode")
|
||||
serviceName := utils.GetConfigString("base.name")
|
||||
registerIP := utils.GetConfigString("base.registerIP")
|
||||
|
||||
// 初始化服务发现
|
||||
if err := discovery.Init(discovery.Config{
|
||||
Hosts: c.Nacos.Hosts,
|
||||
NamespaceId: c.Nacos.NamespaceId,
|
||||
Group: c.Nacos.Group,
|
||||
}); err != nil {
|
||||
logx.Errorf("nacos init: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := discovery.Init(discovery.Config{
|
||||
Hosts: c.Nacos.Hosts,
|
||||
NamespaceId: c.Nacos.NamespaceId,
|
||||
Group: c.Nacos.Group,
|
||||
}); err != nil {
|
||||
logx.Errorf("nacos init: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
port, err := listenPort(listenOn)
|
||||
if err != nil {
|
||||
logx.Errorf("parse ListenOn: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
port, err := listenPort(listenOn)
|
||||
if err != nil {
|
||||
logx.Errorf("parse ListenOn: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 注册服务
|
||||
if err := discovery.Register(discovery.Instance{
|
||||
ServiceName: serviceName,
|
||||
IP: registerIP,
|
||||
Port: port,
|
||||
Group: c.Nacos.Group,
|
||||
}); err != nil {
|
||||
logx.Errorf("nacos register: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := discovery.Register(discovery.Instance{
|
||||
ServiceName: serviceName,
|
||||
IP: registerIP,
|
||||
Port: port,
|
||||
Group: c.Nacos.Group,
|
||||
}); err != nil {
|
||||
logx.Errorf("nacos register: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := discovery.Deregister(); err != nil {
|
||||
logx.Errorf("nacos deregister: %v", err)
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if err := discovery.Deregister(); err != nil {
|
||||
logx.Errorf("nacos deregister: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 初始化MySQL
|
||||
db, err := mysql.New(mysql.Config{
|
||||
Host: utils.GetConfigString("mysql.host"),
|
||||
Port: utils.GetConfigInt("mysql.port"),
|
||||
User: utils.GetConfigString("mysql.user"),
|
||||
Password: utils.GetConfigString("mysql.password"),
|
||||
Database: utils.GetConfigString("mysql.database"),
|
||||
Charset: utils.GetConfigString("mysql.charset"),
|
||||
Prefix: utils.GetConfigString("mysql.prefix"),
|
||||
ReadHost: utils.GetConfigString("mysql_read.host"),
|
||||
ReadPort: utils.GetConfigInt("mysql_read.port"),
|
||||
ReadUser: utils.GetConfigString("mysql_read.user"),
|
||||
ReadPassword: utils.GetConfigString("mysql_read.password"),
|
||||
ReadDatabase: utils.GetConfigString("mysql_read.database"),
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("mysql init: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
db, err := mysql.New(mysql.Config{
|
||||
Host: utils.GetConfigString("mysql.host"),
|
||||
Port: utils.GetConfigInt("mysql.port"),
|
||||
User: utils.GetConfigString("mysql.user"),
|
||||
Password: utils.GetConfigString("mysql.password"),
|
||||
Database: utils.GetConfigString("mysql.database"),
|
||||
Charset: utils.GetConfigString("mysql.charset"),
|
||||
Prefix: utils.GetConfigString("mysql.prefix"),
|
||||
ReadHost: utils.GetConfigString("mysql_read.host"),
|
||||
ReadPort: utils.GetConfigInt("mysql_read.port"),
|
||||
ReadUser: utils.GetConfigString("mysql_read.user"),
|
||||
ReadPassword: utils.GetConfigString("mysql_read.password"),
|
||||
ReadDatabase: utils.GetConfigString("mysql_read.database"),
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("mysql init: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 初始化Redis
|
||||
if err := redis.Init(redis.Config{
|
||||
Host: utils.GetConfigString("redis.host"),
|
||||
Port: utils.GetConfigInt("redis.port"),
|
||||
Password: utils.GetConfigString("redis.password"),
|
||||
DB: utils.GetConfigInt("redis.db"),
|
||||
}); err != nil {
|
||||
logx.Errorf("redis init: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := redis.Init(redis.Config{
|
||||
Host: utils.GetConfigString("redis.host"),
|
||||
Port: utils.GetConfigInt("redis.port"),
|
||||
Password: utils.GetConfigString("redis.password"),
|
||||
DB: utils.GetConfigInt("redis.db"),
|
||||
}); err != nil {
|
||||
logx.Errorf("redis init: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
debug := utils.GetConfigBool("mysql.debug")
|
||||
modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug})
|
||||
debug := utils.GetConfigBool("mysql.debug")
|
||||
modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug})
|
||||
|
||||
// 修正语法错误,手动组装RPC配置
|
||||
rpcConf := zrpc.RpcServerConf{
|
||||
ListenOn: listenOn,
|
||||
}
|
||||
rpcConf.Mode = mode
|
||||
// 构建上下文
|
||||
ctx := svc.NewServiceContext(c, db)
|
||||
rpcConf := zrpc.RpcServerConf{
|
||||
ListenOn: listenOn,
|
||||
}
|
||||
rpcConf.Mode = mode
|
||||
|
||||
// 启动rpc服务,使用拼装好的rpcConf,不再使用本地空的c.RpcServerConf
|
||||
s := zrpc.MustNewServer(rpcConf, func(grpcServer *grpc.Server) {
|
||||
admin.RegisterAdminServer(grpcServer, server.NewAdminServer(ctx))
|
||||
if mode == service.DevMode || mode == service.TestMode {
|
||||
reflection.Register(grpcServer)
|
||||
}
|
||||
})
|
||||
defer s.Stop()
|
||||
ctx := svc.NewServiceContext(c, db)
|
||||
|
||||
s.AddUnaryInterceptors(validate.UnaryServerInterceptor(validate.MustNew()))
|
||||
s := zrpc.MustNewServer(rpcConf, func(grpcServer *grpc.Server) {
|
||||
order.RegisterOrderServer(grpcServer, server.NewOrderServer(ctx))
|
||||
if mode == service.DevMode || mode == service.TestMode {
|
||||
reflection.Register(grpcServer)
|
||||
}
|
||||
})
|
||||
defer s.Stop()
|
||||
|
||||
logx.Infof("Starting rpc server at %s...", listenOn)
|
||||
s.Start()
|
||||
s.AddUnaryInterceptors(validate.UnaryServerInterceptor(validate.MustNew()))
|
||||
|
||||
logx.Infof("Starting rpc server at %s...", 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)
|
||||
_, portStr, err := net.SplitHostPort(listenOn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strconv.ParseUint(portStr, 10, 64)
|
||||
}
|
||||
|
||||
```
|
||||
@@ -297,8 +279,6 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 7. 接入 Docker Compose
|
||||
|
||||
在 `deploy/docker-compose.dev.override.yml` 增加服务:
|
||||
@@ -320,30 +300,14 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
|
||||
- rnacos
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 8. 生成 ProtoSet 给 BFF
|
||||
|
||||
```bash
|
||||
|
||||
protoc --include_imports --proto_path=proto --descriptor_set_out=../bff/etc/order.pb order.proto
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 9. 在 BFF 配 Upstream(HTTP 路由写在 proto)
|
||||
|
||||
在对应 RPC 上声明 `google.api.http`(需 `import "google/api/annotations.proto";`):
|
||||
|
||||
```protobuf
|
||||
rpc Ping(Request) returns (Response) {
|
||||
option (google.api.http) = {
|
||||
post: "/admin/v3/order/ping"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
编辑 `bff/etc/bff.yaml`,在 **Upstreams** 增加一段(不必写 Mappings,gateway 会从 ProtoSet 里的 http option 注册路由):
|
||||
|
||||
```yaml
|
||||
@@ -355,7 +319,16 @@ rpc Ping(Request) returns (Response) {
|
||||
- etc/order.pb
|
||||
```
|
||||
|
||||
在对应 RPC 上声明 `google.api.http`(需 `import "google/api/annotations.proto";`):
|
||||
|
||||
```protobuf
|
||||
rpc Ping(Request) returns (Response) {
|
||||
option (google.api.http) = {
|
||||
post: "/admin/v3/order/ping"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 编写业务须知
|
||||
|
||||
@@ -366,8 +339,6 @@ rpc Ping(Request) returns (Response) {
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
### 命令 ①:生成服务端 pb / grpc
|
||||
|
||||
```bash
|
||||
@@ -379,8 +350,6 @@ goctl rpc protoc proto/order.proto --proto_path=. --proto_path=../pkg/third_part
|
||||
- 只改 **校验规则**(必填/长度/范围等)→ **只跑这条**
|
||||
- 增删改字段、增删 RPC → 也要跑(服务端描述符要更新)
|
||||
|
||||
|
||||
|
||||
### 命令 ②:生成 BFF ProtoSet
|
||||
|
||||
```bash
|
||||
@@ -393,8 +362,6 @@ protoc -I. -I../pkg/third_party --descriptor_set_out=../bff/etc/order.pb --inclu
|
||||
- 增删 **RPC**
|
||||
- 改 **google.api.http** 路由
|
||||
|
||||
|
||||
|
||||
### 命令 ③:goctl 生成/更新脚手架
|
||||
|
||||
```bash
|
||||
@@ -406,8 +373,6 @@ goctl -I. -I../pkg/third_party rpc protoc proto/order.proto --go_out=. --go-grpc
|
||||
- **新增 RPC**:需要生成 `internal/logic`、更新 `server` / `orderclient` 等
|
||||
- 注意:可能覆盖已改过的 `order.go` 等,生成后对比合并;也可用手写 logic/server 代替
|
||||
|
||||
|
||||
|
||||
## Proto 常用校验规则(protovalidate)
|
||||
|
||||
文档:[https://protovalidate.com/schemas/standard-rules/](https://protovalidate.com/schemas/standard-rules/)
|
||||
@@ -436,8 +401,6 @@ double price = 6 [(buf.validate.field).double = {gte: 0}];
|
||||
int32 period_validity = 16 [(buf.validate.field).int32 = {gte: 0}];
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 非必填数值(0 表示未传,跳过校验)
|
||||
|
||||
```protobuf
|
||||
@@ -463,24 +426,18 @@ uint32 sales_model = 4 [(buf.validate.field) = {
|
||||
}];
|
||||
```
|
||||
|
||||
|
||||
|
||||
### ID 必须大于 0
|
||||
|
||||
```protobuf
|
||||
int64 id = 1 [(buf.validate.field).int64 = {gt: 0}];
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 无规则字段
|
||||
|
||||
```protobuf
|
||||
uint32 number = 20; // 不做 protovalidate
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 删除字段编号(避免复用)
|
||||
|
||||
```protobuf
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
’
|
||||
|
||||
user.protouser"
|
||||
Request
|
||||
ping ( Rping"
|
||||
Response
|
||||
pong ( Rpong2-
|
||||
User%
|
||||
Ping
|
||||
Reference in New Issue
Block a user