go 不一样的grpc入门示例
发布于 2022-10-30 17:19:52阅读 1773
之所以说不一样,是因为在这里你看不到.proto文件,当然也无需生成任何代码
之所以这么神奇是我用了buf,它托管了我的.proto文件,并且自动生成了相关代码,详情请移步:https://www.cuiwei.net/p/1679512807
服务端极简示例
下面的示例提供了一个AdminLogin服务
server.go
package main
import (
	"context"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
	"google.golang.org/grpc"
	"net"
)
type blogService struct {
	*blogv1.UnimplementedBlogServiceServer
}
func (s *blogService) AdminLogin(ctx context.Context, in *blogv1.AdminLoginRequest) (*blogv1.AdminLoginResponse, error) {
	return &blogv1.AdminLoginResponse{
		Id:       1,
		Username: "aa",
		Token:    "xx",
	}, nil
}
func main() {
	lis, _ := net.Listen("tcp", ":9087")
	gRPCServer := grpc.NewServer()
	blogv1.RegisterBlogServiceServer(gRPCServer, &blogService{})
	gRPCServer.Serve(lis)
}
客户端极简示例
下面的客户端示例也可以说是一个测试用例,执行TestBlogServerLogin方法可以验证AdminLogin服务的可用性
server_test.go
package main
import (
	"context"
	"fmt"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"testing"
)
var conn *grpc.ClientConn
var client blogv1.BlogServiceClient
func init() {
	//conn, err = grpc.Dial(":9087", grpc.WithInsecure()) //过时的
	conn, _ = grpc.Dial(":9087", grpc.WithTransportCredentials(insecure.NewCredentials()))
	client = blogv1.NewBlogServiceClient(conn)
}
func TestBlogServiceLogin(t *testing.T) {
	resp, err := client.AdminLogin(context.Background(), &blogv1.AdminLoginRequest{
		Username: "admin22",
		Password: "123",
	})
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(resp)
}
目录结构
如上,服务端和客户端都是一个文件,实际项目中肯定不这样。如何拆分呢,这对新手来说可能是个问题。我这里抛砖引玉,下面只说服务端
将上文的server.go改名为main.go,并把里面的&blogService{}移出去,移到两个目录,分别是services,api目录。services/BlogService.go定义了全部的服务,具体实现在api目录
将上文的server_test.go移到为services/blog_service_test.go
最终等到的目录结构如下
.
├── README.md
├── api
│   ├── admin.go
│   └── article.go
├── go.mod
├── go.sum
├── main.go
└── services
    ├── BlogService.go
    └── blog_service_test.go
最后是关键文件的代码
main.go
package main
import (
	"demo/grpc/services"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
	"google.golang.org/grpc"
	"net"
)
func main() {
	lis, _ := net.Listen("tcp", ":9087")
	gRPCServer := grpc.NewServer()
	blogv1.RegisterBlogServiceServer(gRPCServer, services.BlogService)
	gRPCServer.Serve(lis)
}
services/BlogService.go
package services
import (
	"context"
	"demo/grpc/api"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
)
var BlogService = &blogService{}
//func NewBlogService() *blogService {
//	return &blogService{}
//}
type blogService struct {
	*blogv1.UnimplementedBlogServiceServer //解决"missing mustEmbedUnimplementedBlogServiceServer method"的问题
}
//func (s *blogService) mustEmbedUnimplementedBlogServiceServer() {
//	//为了解决"missing mustEmbedUnimplementedBlogServiceServer method"的问题,但我测试时不好使
//}
func (s *blogService) AdminLogin(ctx context.Context, in *blogv1.AdminLoginRequest) (*blogv1.AdminLoginResponse, error) {
	return api.AdminLogin(ctx, in)
}
//这里只定义一个管理员的,其他的,像文章也都可以定义到这里,最终在api目录的实现再分开
api/admin.go
package api
import (
	"context"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
)
func AdminLogin(ctx context.Context, in *blogv1.AdminLoginRequest) (*blogv1.AdminLoginResponse, error) {
	return &blogv1.AdminLoginResponse{
		Id:       1,
		Username: "aa",
		Token:    "xx",
	}, nil
}
看,是不是清晰多了~
