用户模块示例

最后更新于:2022-04-02 02:49:25

[TOC] ## 快速开始 查看[快速开始](../%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B.md),初始化项目 ## 目录 > [完整代码参考 github](https://github.com/idcpj/micro) ``` ├── Makefile ├── domain │   ├── model │   │   └── user.go │   ├── repository │   │   └── user_repository.go │   └── service │   └── user_data_service.go ├── generate.go ├── go.mod ├── go.sum ├── handler │   └── user.go ├── main.go ├── micro.mu ├── proto │   ├── user │   │   ├── user.pb.go │   │   └── user.pb.micro.go │   └── user.proto ├── Dockerfile ```
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 HasPassword string } ```

domain/repository/user_repository.go ``` package repository import ( "github.com/idcpj/micro/domain/model" "github.com/jinzhu/gorm" ) 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) } type UserRepository struct { db *gorm.DB } func NewUserRepository(db *gorm.DB) IUserRepository { return &UserRepository{db: db} } func (u *UserRepository) InitTable() error { return u.db.CreateTable(&model.User{}).Error } func (u *UserRepository) FindUserByName(name string) (*model.User, error) { user := &model.User{} return user, u.db.Where("user_name=?", 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 } func (u *UserRepository) findAll() (userAll []model.User, err error) { return userAll, u.db.Find(&userAll).Error } ```

domain/service/ser_data_service.go ``` package service import ( "errors" "github.com/idcpj/micro/domain/model" "github.com/idcpj/micro/domain/repository" "golang.org/x/crypto/bcrypt" ) var ( ERROR_VALIDATE_PASSWORD = errors.New("密码比对错误") ERROR_USER_INVALID = errors.New("账号无效") ) type IUserDataService interface { AddUser(user *model.User) (id int64, error error) DeleteUser(id int64) error UpdateUser(user *model.User, isChangepwd bool) error FindUserByName(name string) (*model.User, error) CheckPwd(userName string, pwd string) (isok bool, err error) } type UserDataService struct { UserRepository repository.IUserRepository } func NewUserDataService(userRepository repository.IUserRepository) IUserDataService { return &UserDataService{ UserRepository: userRepository, } } func (u *UserDataService) AddUser(user *model.User) (id int64, error error) { pwdByte, err := GeneratePassword(user.HasPassword) if err != nil { return user.ID, err } user.HasPassword = string(pwdByte) return u.UserRepository.CreateUser(user) } func (u *UserDataService) DeleteUser(id int64) error { return u.UserRepository.DeleteUserById(id) } func (u *UserDataService) UpdateUser(user *model.User, isChangePwd bool) error { if isChangePwd { pwd, err := GeneratePassword(user.HasPassword) if err != nil { return ERROR_VALIDATE_PASSWORD } user.HasPassword = string(pwd) } return u.UserRepository.UpdateUser(user) } func (u *UserDataService) FindUserByName(name string) (*model.User, error) { return u.UserRepository.FindUserByName(name) } func (u *UserDataService) CheckPwd(userName string, pwd string) (isok bool, err error) { user, err := u.UserRepository.FindUserByName(userName) if err != nil { return false, ERROR_USER_INVALID } return ValiDatePwd(pwd, user.HasPassword) } func GeneratePassword(pwd string) ([]byte, error) { return bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) } func ValiDatePwd(pwd string, hased string) (isok bool, err error) { if err = bcrypt.CompareHashAndPassword([]byte(pwd), []byte(hased)); err != nil { return false, ERROR_VALIDATE_PASSWORD } return true, nil } ```

generate.go ``` package main //go:generate make proto ```

go.mod ``` module github.com/idcpj/micro go 1.15 require ( github.com/asim/go-micro/v3 v3.5.0 github.com/golang/protobuf v1.5.2 github.com/jinzhu/gorm v1.9.16 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 google.golang.org/protobuf v1.26.0 ) // This can be removed once etcd becomes go gettable, version 3.4 and 3.5 is not, // see https://github.com/etcd-io/etcd/issues/11154 and https://github.com/etcd-io/etcd/issues/11931. replace google.golang.org/grpc => google.golang.org/grpc v1.26.0 ```

handler/user.go ``` package handler import ( "context" "github.com/idcpj/micro/domain/model" "github.com/idcpj/micro/domain/service" "github.com/idcpj/micro/proto/user" ) type User struct { userDataService service.IUserDataService } func (u *User) Register(ctx context.Context, request *user.UserRegisterRequest, response *user.UserRegisterResponse) error { userInfo := &model.User{ UserName: request.GetUserName(), FirstName: request.GetFirstName(), HasPassword: request.GetPwd(), } _, err := u.userDataService.AddUser(userInfo) if err != nil { return err } response.Message = "添加成功" return nil } func (u *User) Login(ctx context.Context, request *user.UserLoginRequest, response *user.UserLoginResponse) error { isOk, err := u.userDataService.CheckPwd(request.UserName, request.Pwd) if err != nil { return err } response.IsSuccess = isOk return nil } func (u *User) GetUserInfo(ctx context.Context, request *user.UserInfoRequest, response *user.UserInfoResponse) error { userInfo, err := u.userDataService.FindUserByName(request.UserName) if err != nil { return err } response = UserForResponse(userInfo) return nil } func UserForResponse(userInfo *model.User) *user.UserInfoResponse { response := &user.UserInfoResponse{} response.UserName = userInfo.UserName response.FirstName = userInfo.FirstName response.UserId = userInfo.ID return response } ```

proto/user.proto ``` syntax = "proto3"; package user; option go_package = "./proto/user;user"; 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 pwd=3; // other info } message UserRegisterResponse{ string message=1; } message userLoginRequest { string user_name=1; string pwd=2; } message UserLoginResponse { bool is_success=1; } ```

Makefile ``` GOPATH:=$(shell go env GOPATH) .PHONY: init init: go get -u github.com/golang/protobuf/proto go get -u github.com/golang/protobuf/protoc-gen-go go get github.com/asim/go-micro/v3/cmd/protoc-gen-micro .PHONY: proto proto: protoc --proto_path=. --micro_out=. --go_out=. proto/user.proto # mac sed -i "" 's|micro/go-micro|asim/go-micro/v3|g' proto/**/*.micro.go # linux #sed -i 's|micro/go-micro|asim/go-micro/v3|g' proto/**/*.micro.go .PHONY: build build: GOOS=linux go build -o user *.go .PHONY: test test: go test -v ./... -cover .PHONY: docker docker: docker build . -t user:latest ```

Dockerfile ``` FROM alpine ADD user /user ENTRYPOINT [ "/user" ] ```

## 编译成 docker ``` make init make proto make build make docker docker run -d user ``` ## 微服务架构 1. 先创建 *.proto 文件 2. 在 domain 中创建model 3. 在 domain 中创建 repository,实现与model交互的方法(不含业务逻辑) 4. 在 domain 中创建 service,实现与repository的交互(包含业务逻辑,hook处理等) 5. 在 handler 中创建 *.micro.go的 *handle(如 UserHandler) 的接口实现 并绑定 domain的service的实现
';