kratos micro service framework mall actual user Service-1
Note: kratos, proto, wire and other command tools have been installed here. It is recommended to take a look at the official file To avoid execution failure
A brief introduction to kratos framework
Please read the official file
Create mall micro Service - User Service
- Enter the local go path directory, create a new directory and enter the shop directory
- After entering the shop directory, execute the kratos new user command
- Enter the user directory and execute the go mod download command to pull the project dependencies
- visit http://127.0.0.1:8000/helloworld/kratos See the response below to prove that your framework installation is successful
{ "message": "Hello kratos" }
Some preparatory work
Modify the api/helloworld directory to api/user
Delete API / user / V1 / greeter pb. go,api/user/v1/greeter_grpc.pb_.go ,api/user/v1/greeter_http.pb_.go
Modify or delete API / user / V1 / greeter The proto file is user Proto file, modified as follows:
Please learn the basic syntax of proto by yourself. At present, the service here only provides a service interface for creating users, which will be added step by step later
syntax = "proto3"; package user.v1; import "google/protobuf/empty.proto"; option go_package = "user/api/user/v1;v1"; service User{ rpc CreateUser(CreateUserInfo) returns (UserInfoResponse); // Create user } // User information message UserInfoResponse{ int64 id = 1; string password = 2; string mobile = 3; string nickName = 4; uint64 birthday = 5; string gender = 6; int32 role = 7; } // Create fields required by users message CreateUserInfo{ string nickName = 1; string password = 2; string mobile = 3; }
Newly generated user Interface information defined by proto
- Enter the root directory user and execute the make api command
- See the following files in the user/api/user/v1 / directory
user.proto user.pb.go user_grpc.pb.go user_http.pb.go
Modify profile
Modify user / config / config Yaml file
Modify the configuration corresponding to the database under data according to your local configuration
New user / configs / registry Yaml file
consul: address: 127.0.0.1:8500 scheme: http
Modify the user/internal/conf/conf.proto file and add a new one at the bottom of the file
message Registry { message Consul { string address = 1; string scheme = 2; } Consul consul = 1; }
Newly generated conf.pb Go file
Enter the project root directory and execute the command make configAdd consumer service tool
The docker tool is used here
docker run -d -p 8500:8500 -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8600:8600/udp consul consul agent -dev -client=0.0.0.0
Browser access http://127.0.0.1:8500/ Verify that the installation was successful
Modify startup program
1. Modify user / CMD / user / main Go file* * * var ( // Name is the name of the compiled software. Name = "shop.user.service" // Version is the version of the compiled software. Version string // flagconf is the config flag. flagconf string id, _ = os.Hostname() ) * * * func newApp(logger log.Logger, gs *grpc.Server, rr registry.Registrar) *kratos.App { return kratos.New( kratos.ID(id), kratos.Name(Name), kratos.Version(Version), kratos.Metadata(map[string]string{}), kratos.Logger(logger), kratos.Server( gs, ), kratos.Registrar(rr), ) } func main() { * * * var rc conf.Registry if err := c.Scan(&rc); err != nil { panic(err) } app, cleanup, err := initApp(bc.Server, &rc, bc.Data, logger) * * * }
2. Modify user / CMD / wire Go file
func initApp(*conf.Server, *conf.Registry, *conf.Data, log.Logger) (*kratos.App, func(), error) { panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp)) }
- Modify the root user/makefile file
stay go generate ./... Add code below wire: cd cmd/user/ && wire
*Represents unmodified code
- Modify the root user/makefile file
Modify the file in the user/internal/data / directory
Modify data The contents of the go file are as follows:
gorm is introduced here, and ent is not used
package data import ( "github.com/go-kratos/kratos/v2/log" "github.com/google/wire" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" "gorm.io/gorm/schema" slog "log" "os" "time" "user/internal/conf" ) // ProviderSet is data providers. var ProviderSet = wire.NewSet(NewData, NewDB, NewUserRepo) type Data struct { db *gorm.DB } // NewData . func NewData(c *conf.Data, logger log.Logger, db *gorm.DB) (*Data, func(), error) { cleanup := func() { log.NewHelper(logger).Info("closing the data resources") } return &Data{db: db}, cleanup, nil } // NewDB . func NewDB(c *conf.Data) *gorm.DB { // Terminal print and input sql execution record newLogger := logger.New( slog.New(os.Stdout, "\r\n", slog.LstdFlags), // io writer logger.Config{ SlowThreshold: time.Second, // Slow query SQL threshold Colorful: true, // Disable color printing //IgnoreRecordNotFoundError: false, LogLevel: logger.Info, // Log lever }, ) db, err := gorm.Open(mysql.Open(c.Database.Source), &gorm.Config{ Logger: newLogger, NamingStrategy: schema.NamingStrategy{ SingularTable: true, // Whether to add s to the table name }, }) if err != nil { panic("failed to connect database") } return db }
Modify or delete user / internal / data / greeter Go is user Go contents are as follows:
package data import ( "context" "crypto/sha512" "fmt" "github.com/anaskhan96/go-password-encoder" "github.com/go-kratos/kratos/v2/log" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "user/internal/biz" ) type userRepo struct { data *Data log *log.Helper } // NewUserRepo . func NewUserRepo(data *Data, logger log.Logger) biz.UserRepo { return &userRepo{ data: data, log: log.NewHelper(logger), } } // CreateUser . func (r *userRepo) CreateUser(ctx context.Context, u *biz.User) (*biz.User, error) { // Verify that the has been created var user biz.User result := r.data.db.Where(&biz.User{Mobile: u.Mobile}).First(&user) if result.RowsAffected == 1 { return nil, status.Errorf(codes.AlreadyExists, "User already exists") } user.Mobile = u.Mobile user.NickName = u.NickName user.Password = encrypt(u.Password) // Password encryption res := r.data.db.Create(&user) if res.Error != nil { return nil, status.Errorf(codes.Internal, res.Error.Error()) } userInfoRes := modelToResponse(user) return &userInfoRes, nil } // Password encryption func encrypt(psd string) string { options := &password.Options{SaltLen: 16, Iterations: 10000, KeyLen: 32, HashFunction: sha512.New} salt, encodedPwd := password.Encode(psd, options) return fmt.Sprintf("$pbkdf2-sha512$%s$%s", salt, encodedPwd) } // ModelToResponse transforms the values of all fields in the user table func modelToResponse(user biz.User) biz.User { userInfoRsp := biz.User{ ID: user.ID, Mobile: user.Mobile, Password: user.Password, NickName: user.NickName, Gender: user.Gender, Role: user.Role, Birthday: user.Birthday, } return userInfoRsp }
Modify the file in the user/internal/biz / directory
Modify greeter The go file is user Go file, as follows:
package biz import ( "context" "github.com/go-kratos/kratos/v2/log" "gorm.io/gorm" "time" ) type User struct { ID int64 `gorm:"primarykey"` Mobile string `gorm:"index:idx_mobile;unique;type:varchar(11) comment 'Mobile phone number, unique user ID';not null"` Password string `gorm:"type:varchar(100);not null "` // Whether the user password is encrypted should be paid attention to when saving it NickName string `gorm:"type:varchar(25) comment 'User nickname'"` Birthday *time.Time `gorm:"type:datetime comment 'Date of birth'"` Gender string `gorm:"column:gender;default:male;type:varchar(16) comment 'female:female,male:male'"` Role int `gorm:"column:role;default:1;type:int comment '1:Ordinary users, 2:administrators'"` CreatedAt time.Time `gorm:"column:add_time"` UpdatedAt time.Time `gorm:"column:update_time"` DeletedAt gorm.DeletedAt IsDeletedAt bool } type UserRepo interface { CreateUser(context.Context, *User) (*User, error) } type UserUsecase struct { repo UserRepo log *log.Helper } func NewUserUsecase(repo UserRepo, logger log.Logger) *UserUsecase { return &UserUsecase{repo: repo, log: log.NewHelper(logger)} } func (uc *UserUsecase) Create(ctx context.Context, u *User) (*User, error) { return uc.repo.CreateUser(ctx, u) }
Modify biz Go file, as follows:
package biz import "github.com/google/wire" // ProviderSet is biz providers. var ProviderSet = wire.NewSet(NewUserUsecase)
New user Go file, directory user / internal / biz / entity / user Go contents are as follows:
It is assumed that the table corresponding to the database has been created, and the database name is shop_ The user table name is user
package main import ( "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" "gorm.io/gorm/schema" "log" "os" "time" "user/internal/biz" ) // Linked database func main() { dsn := "root:root@tcp(127.0.0.1:3306)/shop_user?charset=utf8mb4&parseTime=True&loc=Local" newLogger := logger.New( log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer logger.Config{ SlowThreshold: time.Second, // Slow SQL threshold LogLevel: logger.Info, // Log level Colorful: true, // Disable color printing }, ) // Global mode db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ NamingStrategy: schema.NamingStrategy{ SingularTable: true, }, Logger: newLogger, }) if err != nil { panic(err) } _ = db.AutoMigrate(&biz.User{}) }
Modify the file in / user / internal directory
Modify or delete user / internal / service / greeter Go is user Go, as follows:
package service import ( "context" "github.com/go-kratos/kratos/v2/log" v1 "user/api/user/v1" "user/internal/biz" ) type UserService struct { v1.UnimplementedUserServer uc *biz.UserUsecase log *log.Helper } // NewUserService new a greeter service. func NewUserService(uc *biz.UserUsecase, logger log.Logger) *UserService { return &UserService{uc: uc, log: log.NewHelper(logger)} } // CreateUser create a user func (u *UserService) CreateUser(ctx context.Context, req *v1.CreateUserInfo) (*v1.UserInfoResponse, error) { user, err := u.uc.Create(ctx, &biz.User{ Mobile: req.Mobile, Password: req.Password, NickName: req.NickName, }) if err != nil { return nil, err } userInfoRsp := v1.UserInfoResponse{ Id: user.ID, Mobile: user.Mobile, Password: user.Password, NickName: user.NickName, Gender: user.Gender, Role: int32(user.Role), } if user.Birthday != nil { userInfoRsp.Birthday = uint64(user.Birthday.Unix()) } return &userInfoRsp, nil }
Modify service Go file, as follows:
package service import "github.com/google/wire" // ProviderSet is service providers. var ProviderSet = wire.NewSet(NewUserService)
Modify the file in the user/internal/server / directory
Delete http Go file
Modify grpc The contents of the go file are as follows:
package server import ( "github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/middleware/recovery" "github.com/go-kratos/kratos/v2/transport/grpc" v1 "user/api/user/v1" "user/internal/conf" "user/internal/service" ) // NewGRPCServer new a gRPC server. func NewGRPCServer(c *conf.Server, u *service.UserService, logger log.Logger) *grpc.Server { var opts = []grpc.ServerOption{ grpc.Middleware( recovery.Recovery(), ), } if c.Grpc.Network != "" { opts = append(opts, grpc.Network(c.Grpc.Network)) } if c.Grpc.Addr != "" { opts = append(opts, grpc.Address(c.Grpc.Addr)) } if c.Grpc.Timeout != nil { opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration())) } srv := grpc.NewServer(opts...) v1.RegisterUserServer(srv, u) return srv }
Modify server Go contents are as follows:
package server import ( "github.com/go-kratos/kratos/v2/registry" "github.com/google/wire" "user/internal/conf" consul "github.com/go-kratos/kratos/contrib/registry/consul/v2" consulAPI "github.com/hashicorp/consul/api" ) // ProviderSet is server providers. var ProviderSet = wire.NewSet(NewGRPCServer, NewRegistrar) // NewRegistrar introduces consumer func NewRegistrar(conf *conf.Registry) registry.Registrar { c := consulAPI.DefaultConfig() c.Address = conf.Consul.Address c.Scheme = conf.Consul.Scheme cli, err := consulAPI.NewClient(c) if err != nil { panic(err) } r := consul.New(cli, consul.WithHealthCheck(false)) return r }
Execute wire command
Execute make wire from the root directoryExecute the command to create a table from the root directory
go run internal/biz/entity/user.goStart program
Execute command from root directory kratos run
Simple test service
- New user Go file user / test / user go
- user. The contents of the go file are as follows:
package main import ( "context" "fmt" "google.golang.org/grpc" v1 "user/api/user/v1" ) var userClient v1.UserClient var conn *grpc.ClientConn func main() { Init() TestCreateUser() // Create user conn.Close() } // Init initialization link func Init() { var err error conn, err = grpc.Dial("127.0.0.1:50051", grpc.WithInsecure()) if err != nil { panic("grpc link err" + err.Error()) } userClient = v1.NewUserClient(conn) } // TestCreateUser test creates 10 user data func TestCreateUser() { for i := 0; i < 10; i++ { rsp, err := userClient.CreateUser(context.Background(), &v1.CreateUserInfo{ Mobile: fmt.Sprintf("1350116722%d", i), Password: "admin", NickName: fmt.Sprintf("YW%d", i), }) if err != nil { panic("grpc Failed to create user" + err.Error()) } fmt.Println(rsp.Id) } }
- Query your own database to see if there is any inserted data.