feat: 完成用户微服务 gRPC 实现,包含数据库与服务启动逻辑
This commit is contained in:
@@ -17,3 +17,11 @@ services:
|
|||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
environment:
|
environment:
|
||||||
- GO_ENV=production
|
- GO_ENV=production
|
||||||
|
|
||||||
|
user-svc:
|
||||||
|
build:
|
||||||
|
context: ./services/user-svc
|
||||||
|
ports:
|
||||||
|
- "50051:50051"
|
||||||
|
environment:
|
||||||
|
- GO_ENV=production
|
||||||
|
|||||||
23
backend/services/user-svc/Dockerfile
Normal file
23
backend/services/user-svc/Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
FROM golang:1.26.1-alpine3.23 AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY go.mod ./
|
||||||
|
COPY main.go ./
|
||||||
|
COPY user.proto ./
|
||||||
|
|
||||||
|
RUN go mod download
|
||||||
|
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||||
|
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||||
|
RUN protoc --go_out=. --go-grpc_out=. user.proto
|
||||||
|
RUN go build -o user-svc main.go
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /app/user-svc .
|
||||||
|
|
||||||
|
EXPOSE 50051
|
||||||
|
|
||||||
|
CMD ["./user-svc"]
|
||||||
9
backend/services/user-svc/generate.sh
Normal file
9
backend/services/user-svc/generate.sh
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 生成 gRPC 代码
|
||||||
|
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||||
|
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||||
|
|
||||||
|
protoc --go_out=. --go-grpc_out=. user.proto
|
||||||
|
|
||||||
|
echo "gRPC code generated successfully!"
|
||||||
40
backend/services/user-svc/go.mod
Normal file
40
backend/services/user-svc/go.mod
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
module user-svc
|
||||||
|
|
||||||
|
go 1.26
|
||||||
|
|
||||||
|
require (
|
||||||
|
google.golang.org/grpc v1.58.0
|
||||||
|
gorm.io/driver/sqlite v1.5.4
|
||||||
|
gorm.io/gorm v1.25.5
|
||||||
|
google.golang.org/protobuf v1.31.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.17 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
|
golang.org/x/crypto v0.9.0 // indirect
|
||||||
|
golang.org/x/net v0.10.0 // indirect
|
||||||
|
golang.org/x/sys v0.8.0 // indirect
|
||||||
|
golang.org/x/text v0.9.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.12.0 // indirect
|
||||||
|
yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
156
backend/services/user-svc/main.go
Normal file
156
backend/services/user-svc/main.go
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"user-svc/user"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"gorm.io/driver/sqlite"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID string `json:"id" gorm:"primaryKey"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserServiceServer struct {
|
||||||
|
user.UnimplementedUserServiceServer
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserServiceServer) CreateUser(ctx context.Context, req *user.CreateUserRequest) (*user.CreateUserResponse, error) {
|
||||||
|
newUser := User{
|
||||||
|
ID: fmt.Sprintf("%d", len(s.getAllUsers())+1),
|
||||||
|
Name: req.Name,
|
||||||
|
Email: req.Email,
|
||||||
|
Password: req.Password,
|
||||||
|
}
|
||||||
|
|
||||||
|
result := s.db.Create(&newUser)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user.CreateUserResponse{
|
||||||
|
User: &user.User{
|
||||||
|
Id: newUser.ID,
|
||||||
|
Name: newUser.Name,
|
||||||
|
Email: newUser.Email,
|
||||||
|
Password: newUser.Password,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserServiceServer) GetUser(ctx context.Context, req *user.GetUserRequest) (*user.GetUserResponse, error) {
|
||||||
|
var user User
|
||||||
|
result := s.db.First(&user, "id = ?", req.Id)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user.GetUserResponse{
|
||||||
|
User: &user.User{
|
||||||
|
Id: user.ID,
|
||||||
|
Name: user.Name,
|
||||||
|
Email: user.Email,
|
||||||
|
Password: user.Password,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserServiceServer) ListUsers(ctx context.Context, req *user.ListUsersRequest) (*user.ListUsersResponse, error) {
|
||||||
|
users := s.getAllUsers()
|
||||||
|
var protoUsers []*user.User
|
||||||
|
|
||||||
|
for _, u := range users {
|
||||||
|
protoUsers = append(protoUsers, &user.User{
|
||||||
|
Id: u.ID,
|
||||||
|
Name: u.Name,
|
||||||
|
Email: u.Email,
|
||||||
|
Password: u.Password,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user.ListUsersResponse{
|
||||||
|
Users: protoUsers,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserServiceServer) UpdateUser(ctx context.Context, req *user.UpdateUserRequest) (*user.UpdateUserResponse, error) {
|
||||||
|
var user User
|
||||||
|
result := s.db.First(&user, "id = ?", req.Id)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Name != "" {
|
||||||
|
user.Name = req.Name
|
||||||
|
}
|
||||||
|
if req.Email != "" {
|
||||||
|
user.Email = req.Email
|
||||||
|
}
|
||||||
|
if req.Password != "" {
|
||||||
|
user.Password = req.Password
|
||||||
|
}
|
||||||
|
|
||||||
|
s.db.Save(&user)
|
||||||
|
|
||||||
|
return &user.UpdateUserResponse{
|
||||||
|
User: &user.User{
|
||||||
|
Id: user.ID,
|
||||||
|
Name: user.Name,
|
||||||
|
Email: user.Email,
|
||||||
|
Password: user.Password,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserServiceServer) DeleteUser(ctx context.Context, req *user.DeleteUserRequest) (*user.DeleteUserResponse, error) {
|
||||||
|
result := s.db.Delete(&User{}, "id = ?", req.Id)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user.DeleteUserResponse{
|
||||||
|
Success: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserServiceServer) getAllUsers() []User {
|
||||||
|
var users []User
|
||||||
|
s.db.Find(&users)
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
|
||||||
|
func initDB() *gorm.DB {
|
||||||
|
db, err := gorm.Open(sqlite.Open("users.db"), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to connect to database: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.AutoMigrate(&User{})
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
db := initDB()
|
||||||
|
|
||||||
|
server := grpc.NewServer()
|
||||||
|
user.RegisterUserServiceServer(server, &UserServiceServer{db: db})
|
||||||
|
|
||||||
|
listener, err := net.Listen("tcp", ":50051")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to listen: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("User service starting on port 50051...")
|
||||||
|
if err := server.Serve(listener); err != nil {
|
||||||
|
log.Fatalf("Failed to serve: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
64
backend/services/user-svc/user.proto
Normal file
64
backend/services/user-svc/user.proto
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package user;
|
||||||
|
|
||||||
|
option go_package = "./user";
|
||||||
|
|
||||||
|
message User {
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string email = 3;
|
||||||
|
string password = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateUserRequest {
|
||||||
|
string name = 1;
|
||||||
|
string email = 2;
|
||||||
|
string password = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateUserResponse {
|
||||||
|
User user = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetUserRequest {
|
||||||
|
string id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetUserResponse {
|
||||||
|
User user = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListUsersRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListUsersResponse {
|
||||||
|
repeated User users = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateUserRequest {
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string email = 3;
|
||||||
|
string password = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateUserResponse {
|
||||||
|
User user = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteUserRequest {
|
||||||
|
string id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteUserResponse {
|
||||||
|
bool success = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
service UserService {
|
||||||
|
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
|
||||||
|
rpc GetUser(GetUserRequest) returns (GetUserResponse);
|
||||||
|
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
|
||||||
|
rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);
|
||||||
|
rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user