go run internal/cmd/manager/main.go ./config.yaml
执行:go run -mod=mod entgo.io/ent/cmd/ent init User
,生成相关文件
修改schema目录中的内容后,执行
go generate ./path_to_ent/ent
即可生成相关文件
package main
import (
"context"
"fmt"
"go_test/internal/config"
"go_test/pkg/ent"
"log"
_ "github.com/go-sql-driver/mysql"
)
var mysqlConfig = config.MysqlConfig{
Username: "root",
Password: "123456",
Host: "192.168.0.100",
Port: "3340",
DBName: "dev",
}
func main() {
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s",
mysqlConfig.Username,
mysqlConfig.Password,
mysqlConfig.Host,
mysqlConfig.Port,
mysqlConfig.DBName,
)
client, err := ent.Open("mysql", dsn)
if err != nil {
log.Fatalf("failed opening connection to mysql: %v", err)
}
defer client.Close()
// Run the auto migration tool.
if err := client.Schema.Create(context.Background()); err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}
log.Println("Successfully Migrated!")
}
运行此main.go即可将变更迁移至数据库
bash脚本:
# Substitute BIN for your bin directory.
# Substitute VERSION for the current released version.
BIN="/usr/local/bin" && \
VERSION="1.11.0" && \
curl -sSL \
"https://github.com/bufbuild/buf/releases/download/v${VERSION}/buf-$(uname -s)-$(uname -m)" \
-o "${BIN}/buf" && \
chmod +x "${BIN}/buf"
文档:https://docs.buf.build/tour/introduction
下载go相关代码生成插件:https://docs.buf.build/tour/generate-go-code
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
export PATH="$PATH:$(go env GOPATH)/bin"
编写 buf.gen.yaml:
version: v1
plugins:
- name: go
out: ./
opt:
- paths=source_relative
- name: go-grpc
out: ./
opt:
- paths=source_relative
+ - name: grpc-gateway
+ out: ./
+ opt:
+ - paths=source_relative
+ - generate_unbound_methods=true
放置proto目录及文件,如:
api/
├── buf.gen.yaml
├── buf.work.yaml
└── student_apis
├── buf.yaml
└── student
├── rpc.proto
└── student.proto
其中buf.yaml内容如下,它是使用buf init命令生成的:
version: v1
breaking:
use:
- FILE
lint:
use:
- DEFAULT
+ deps:
+ - buf.build/googleapis/googleapis
student.proto:
syntax = "proto3";
package student;
option go_package = "go_test/student";
message Student {
int32 stu_id = 1;
string name = 2;
int32 age = 3;
}
message GetStudentRequest {
int32 stu_id = 1;
}
message GetStudentResponse {
int32 status = 1;
string msg = 2;
Student data = 3;
}
rpc.proto:
syntax = "proto3";
package student;
option go_package = "go_test/student";
import "student/student.proto";
import "google/api/annotations.proto";
service StudentSvc {
rpc GetStudent(GetStudentRequest) returns (GetStudentResponse) {
option (google.api.http) = {
get: "/student"
};
}
}
这里会依赖 annotations.proto
,需要进入student_apis/
,执行buf mod update
,生成一个 buf.lock
文件,即可使用
然后在外层添加 buf.gen.yaml
和 buf.work.yaml
,内容如下:
(grpc-gateway相关protoc插件下载参考:https://github.com/grpc-ecosystem/grpc-gateway)
# buf.gen.yaml
version: v1
plugins:
- name: go
out: .
opt:
- paths=source_relative
- name: go-grpc
out: .
opt:
- paths=source_relative
- name: grpc-gateway
out: .
opt:
- paths=source_relative
- generate_unbound_methods=true
- name: openapiv2
out: .
# buf.work.yaml
version: v1
directories:
- student_apis
最后在api
目录下执行:
buf generate
即可生成 student
和 grpc-gateway
相关的pb文件和swagger文件:
api/student
├── rpc_grpc.pb.go
├── rpc.pb.go
├── rpc.pb.gw.go
├── rpc.swagger.json
├── student.pb.go
└── student.swagger.json
package student
import (
"context"
student_pb "go_test/api/student"
)
type service struct {
}
func New() *service {
return &service{}
}
func (s *service) GetStudent(
ctx context.Context,
req *student_pb.GetStudentRequest,
) (*student_pb.GetStudentResponse, error) {
return &student_pb.GetStudentResponse{
Status: 0,
Msg: "OK",
Data: &student_pb.Student{},
}, nil
}
参考链接:https://github.com/grpc-ecosystem/grpc-gateway
package main
import (
"context"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/spf13/viper"
"google.golang.org/grpc"
student_pb "go_test/api/student"
student_svc "go_test/internal/service/student"
_ "github.com/go-sql-driver/mysql"
)
type endPointFunction func(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error)
var endPointFunctions = []endPointFunction{
student_pb.RegisterStudentSvcHandlerFromEndpoint,
}
func run(conf *config.Config) error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// grpc服务
grpcServer := grpc.NewServer()
grpcServerAddr := "localhost:10001"
lis, err := net.Listen("tcp", grpcServerAddr)
if err != nil {
logger.Fatalf("bind err: %v", err)
}
student_pb.RegisterStudentSvcServer(grpcServer, student_svc.New(logger, entClient))
teacher_pb.RegisterTeacherSvcServer(grpcServer, teacher_svc.New(logger, entClient))
// grpc启动
go grpcServer.Serve(lis)
logger.Infoln("grpcServer started")
// Register gRPC server endpoint
// Note: Make sure the gRPC server is running properly and accessible
// 配置grpc-gateway对各服务的转发规则
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
for _, endPointFunc := range endPointFunctions {
endPointFunc(ctx, mux, grpcServerAddr, opts)
}
// Start HTTP server (and proxy calls to gRPC server endpoint)
// 启动grpc-gateway服务
return http.ListenAndServe(fmt.Sprintf(":10000", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(conf); err != nil {
glog.Fatal(err)
}
}
这样即可运行后端程序
第三方库viper:"github.com/spf13/viper"
func loadConfigFile(filePath string) *config.Config {
viper.SetConfigType("yaml")
viper.SetConfigFile(filePath)
// 读取配置文件
err := viper.ReadInConfig()
if err != nil {
log.Fatalf("read config err: %v\n", err)
}
logger.Infoln("read config ok")
conf := &config.Config{}
viper.Unmarshal(conf)
logger.Infoln(conf)
return conf
}
相关配置文件:
mysql:
username: "root"
password: "123456"
host: "192.168.0.100"
port: "3340"
db_name: "dev"
映射到的结构体:
type Config struct {
MySQL MysqlConfig `mapstructure:"mysql"`
}
type MysqlConfig struct {
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Host string `mapstructure:"host"`
Port string `mapstructure:"port"`
DBName string `mapstructure:"db_name"`
}
第三方库:"github.com/sirupsen/logrus"
配置:
var logger *logrus.Logger
func init() {
logger = logrus.New()
logger.SetFormatter(&logrus.TextFormatter{
ForceQuote: true, //键值对加引号
TimestampFormat: "2006-01-02 15:04:05", //时间格式
FullTimestamp: true,
})
}