Micro用于构建和管理分布式系统,是一个工具集,其中go-micro框架是对分布式系统的高度抽象,提供分布式系统开发的核心库,可插拔的架构,按需使用
简单示例
编写protobuf文件:
syntax = "proto3";
option go_package = ".;proto";
service Cap {
rpc SayHello(SayRequest) returns (SayResponse) {}
}
message SayRequest {
string message = 1;
}
message SayResponse {
string answer = 1;
}
生成代码:
$ protoc -I ./ --go_out=./proto --micro_out=./proto ./proto/hello.proto
编写服务端:
type CapServer struct{}
func (c *CapServer) SayHello(ctx context.Context, req *proto.SayRequest, resp *proto.SayResponse) error {
resp.Answer = "hello: " + req.Message
return nil
}
func main() {
service := micro.NewService(micro.Name("test.server")) // 创建新服务
service.Init() // 初始化方法
_ = proto.RegisterCapHandler(service.Server(), new(CapServer)) // 注册服务
if err := service.Run(); err != nil {
fmt.Println(err)
}
}
客户端:
func main() {
service := micro.NewService(micro.Name("test.client"))
service.Init()
client := proto.NewCapService("test.server", service.Client())
res, err := client.SayHello(context.TODO(), &proto.SayRequest{Message: "test"})
if err != nil {
fmt.Println(err)
}
fmt.Println(res.Answer)
}
目录搭建
使用docker的micro容器,创建一个micro目录:
$ sudo docker run --rm -v $(pwd):$(pwd) -w $(pwd) micro/micro new user
编写一个用户信息的服务
首先定义一个protobuf文件:
syntax = "proto3";
package go.micro.service.user;
option go_package = ".;proto";
service User {
rpc Register(UserRegisterRequest) returns (UserRegisterResponse) {}
rpc Login(UserLoginRequest) returns (UserLoginResponse) {}
rpc GetUserInfo(UserInfoRequest) returns (UserInfoResponse) {}
}
message UserInfoRequest {
string user_name = 1;
}
message UserInfoResponse {
int64 user_id = 1;
string user_name = 2;
string first_name = 3;
}
message UserRegisterRequest {
string user_name = 1;
string first_name = 2;
string password = 3;
}
message UserRegisterResponse {
string message = 1;
}
message UserLoginRequest {
string user_name = 1;
string password = 2;
}
message UserLoginResponse {
bool success = 1;
}
编译该文件:
$ protoc -I ./ --go_out=./ --micro_out=./ user.proto
目录结构:
├── domain
│ ├── model
│ │ └── user.go
│ ├── repository
│ │ └── user_repository.go
│ └── service
│ └── user_data_service.go
├── go.mod
├── go.sum
├── handler
│ └── user.go
├── main.go
├── micro.mu
└── proto
└── user
├── user.pb.go
├── user.pb.micro.go
└── user.proto
核心逻辑
domain/model/user.go
定义用户结构:
package model
type User struct {
ID int64 `gorm:"primary_key;not_null;auto_increment"`
UserName string `gorm:"unique_index;not_null"`
FirstName string
HashPassword string
}
domain/repository/user_repository.go
这部分代码包括创建数据库,初始化数据库表,增删改查用户信息
package repository
import (
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
"user/domain/model"
)
type IUserRepository interface {
InitTable() error // 初始化数据库表
FindUserByName(string) (*model.User, error)
FindUserByID(int64) (*model.User, error)
CreateUser(*model.User) (int64, error)
DeleteUserByID(int64) error
UpdateUser(*model.User) error
FindAll() ([]model.User, error)
}
func NewUserRepository(db *gorm.DB) IUserRepository {
return &UserRepository{db: db}
}
type UserRepository struct {
db *gorm.DB
}
func (u *UserRepository) FindAll() ([]model.User, error) {
userAll := make([]model.User, 0)
return userAll, u.db.Find(&userAll).Error
}
// InitTable 初始化表
func (u *UserRepository) InitTable() error {
if u.db.HasTable("users") {
return nil
}
return u.db.CreateTable(&model.User{}).Error
}
func (u *UserRepository) FindUserByName(name string) (*model.User, error) {
user := &model.User{}
return user, u.db.Where("username = ?", name).Find(user).Error
}
func (u *UserRepository) FindUserByID(userID int64) (*model.User, error) {
user := &model.User{}
return user, u.db.First(user, userID).Error
}
func (u *UserRepository) CreateUser(user *model.User) (int64, error) {
return user.ID, u.db.Create(user).Error
}
func (u *UserRepository) DeleteUserByID(userID int64) error {
return u.db.Where("id = ?", userID).Delete(&model.User{}).Error
}
func (u *UserRepository) UpdateUser(user *model.User) error {
return u.db.Model(user).Update(&user).Error
}
domain/service/user_data_service.go
这部分代码包含业务逻辑,对用户数据进行操作
package service
import (
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt"
"user/domain/model"
"user/domain/repository"
)
type IUserDataService interface {
AddUser(*model.User) (int64, error)
DeleteUser(int64) error
UpdateUser(*model.User, bool) error
FindUserByName(string) (*model.User, error)
CheckPwd(string, string) (bool, error)
}
func NewUserDataService(userRepository repository.IUserRepository) IUserDataService {
return &UserDataService{UserRepository: userRepository}
}
func GeneratePassword(userPassword string) ([]byte, error) {
return bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost)
}
func ValidatePassword(userPassword string, hashed string) (bool, error) {
if err := bcrypt.CompareHashAndPassword([]byte(hashed), []byte(userPassword)); err != nil {
return false, errors.New("wrong password")
}
return true, nil
}
type UserDataService struct {
UserRepository repository.IUserRepository
}
func (u *UserDataService) AddUser(user *model.User) (int64, error) {
pwdByte, err := GeneratePassword(user.HashPassword)
if err != nil {
return user.ID, err
}
user.HashPassword = string(pwdByte)
return u.UserRepository.CreateUser(user)
}
func (u *UserDataService) DeleteUser(userID int64) error {
return u.UserRepository.DeleteUserByID(userID)
}
func (u *UserDataService) UpdateUser(user *model.User, isChangedPwd bool) error {
if isChangedPwd {
pwdByte, err := GeneratePassword(user.HashPassword)
if err != nil {
return err
}
user.HashPassword = string(pwdByte)
}
return u.UserRepository.UpdateUser(user)
}
func (u *UserDataService) FindUserByName(userName string) (*model.User, error) {
return u.UserRepository.FindUserByName(userName)
}
func (u *UserDataService) CheckPwd(userName string, pwd string) (bool, error) {
user, err := u.UserRepository.FindUserByName(userName)
if err != nil {
return false, err
}
return ValidatePassword(pwd, user.HashPassword)
}
程序入口:
package main
import (
"github.com/jinzhu/gorm"
"go-micro.dev/v4"
"log"
"user/domain/repository"
srv "user/domain/service"
"user/handler"
proto "user/proto/user"
)
func main() {
service := micro.NewService(
micro.Name("go.micro.service.user"),
micro.Version("latest"))
service.Init()
db, err := gorm.Open("mysql", "micro:123456@/micro?charset=utf8")
if err != nil {
log.Fatalln(err)
}
defer db.Close()
resp := repository.NewUserRepository(db)
resp.InitTable()
db.SingularTable(true)
userDataService := srv.NewUserDataService(repository.NewUserRepository(db))
err = proto.RegisterUserHandler(service.Server(), &handler.User{UserDataService: userDataService})
if err != nil {
log.Fatalln(err)
}
if err = service.Run(); err != nil {
log.Fatalln(err)
}
}
镜像打包
编写dockerfile打包应用
DockerFile常用命令:
-
FROM: 定制镜像基于FROM的镜像,后续操作都基于该镜像
-
RUN: 用于执行后面跟着的命令行命令
-
COPY,ADD: 复制指令,从文件或者目录到容器里制定路径
-
CMD,ENTRYPOINT: 用于运行程序
-
ENV: 设置环境变量,在后续指令中,就可以使用这个环境变量
-
EXPOSE: 声明端口
-
WORKDIR: 指定工作目录
-
USER: 于指定执行后续命令的用户和用户组
将源程序进行交叉编译为linux平台上的可执行程序:
$ CGO_ENABLE=0 GOOS=linux GOARCH=amd64 go build -o user *.go
编写Dockerfile:
FROM alpine
ADD user /user
ENTRYPOINT ["/user"]
使用以下命令配合Dockerfile即可进行打包:
$ sudo docker build -t user:latest .
使用该命令即可运行:
$ sudo docker run --rm -d user
标签:string,err,micro,user,error,go,Go,model
From: https://www.cnblogs.com/N3ptune/p/17019320.html