天天看點

go-micro項目實戰一 建立使用者服務

使用者服務

使用者服務,提供登入、注冊、修改密碼等功能。

建立服務

micro new shopping/user

整理結構

增加model目錄和repository目錄,删掉proto裡預設的example檔案夾,建立user檔案夾。

開發步驟:1.定義接口 -> 2.生成接口代碼 -> 3.編寫model層代碼 -> 4.編寫repository資料操作代碼 -> 5.實作接口 -> 6.修改main.go

因為這是第一個微服務,是以會盡可能地較長的描述建立微服務的過程

定義使用者服務接口

syntax = "proto3";

package go.micro.srv.user;

service UserService {
	rpc Register (RegisterRequest) returns (Response){}
	rpc Login (LoginRequest) returns (Response){}
	rpc UpdatePassword (UpdatePasswordRequest) returns (Response){}
}

message User {
	uint32 id = 1;
	string name = 2;
	string phone = 3;
	string password = 4;
}

message RegisterRequest{
	User user = 1;
}

message LoginRequest{
	string phone = 1;
	string password = 2;
}

message UpdatePasswordRequest{
	uint32 uid = 1;
	string oldPassword = 2;
	string newPassword = 3;
	string confirmPassword = 4;
}

message Response {
	string code = 1;
	string msg = 2;
}


           

生成接口代碼

執行指令

protoc --proto_path=. --micro_out=. --go_out=. proto/user/user.proto

編寫model.user

package model

import "github.com/jinzhu/gorm"

type User struct {
	gorm.Model
	Name string
	Phone string `gorm:"type:char(11);`
	Password string
}
           

編寫repository.user

package repository

import (
	"github.com/jinzhu/gorm"
	"shopping/user/model"
)

type Repository interface {
	Find(id int32) (*model.User, error)
	Create(*model.User) error
	Update(*model.User, int64) (*model.User, error)
	FindByField(string, string, string) (*model.User, error)
}

type User struct {
	Db *gorm.DB
}

func (repo *User) Find(id uint32) (*model.User, error) {
	user :=  &model.User{}
	user.ID = uint(id)
	if err := repo.Db.First(user).Error; err != nil {
		return nil, err
	}
	return user, nil
}

func (repo *User) Create(user *model.User) error {
	if err := repo.Db.Create(user).Error; err != nil {
		return err
	}
	return nil
}

func (repo *User) Update(user *model.User) (*model.User, error) {
	if err := repo.Db.Model(user).Updates(&user).Error; err != nil {
		return nil, err
	}
	return user, nil
}

func (repo *User) FindByField(key string, value string, fields string) (*model.User, error) {
	if len(fields) == 0 {
		fields = "*"
	}
	user :=  &model.User{}
	if err := repo.Db.Select(fields).Where(key+" = ?", value).First(user).Error; err != nil {
		return nil, err
	}
	return user, nil
}

           

實作接口handler.user

package handler

import (
	"context"
	"github.com/micro/go-log"
	"github.com/micro/go-micro/errors"
	"golang.org/x/crypto/bcrypt"
	"shopping/user/model"
	"shopping/user/repository"

	user "shopping/user/proto/user"
)

type User struct{
	Repo *repository.User
}

// Call is a single request handler called via client.Call or the generated client code
func (e *User) Register(ctx context.Context, req *user.RegisterRequest, rsp *user.Response) error {
	hashedPwd, err := bcrypt.GenerateFromPassword([]byte(req.User.Password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}

	user := &model.User{
		Name:req.User.Name,
		Phone:req.User.Phone,
		Password:string(hashedPwd),
	}

	if err := e.Repo.Create(user);err != nil{
		log.Log("create error")
		return err
	}

	rsp.Code = "200"
	rsp.Msg = "注冊成功"

	return nil
}

func (e *User)Login(ctx context.Context, req *user.LoginRequest, rsp *user.Response) error {
	user , err := e.Repo.FindByField("phone" , req.Phone , "id , password")
	if err != err{
		return err
	}

	if user == nil{
		return errors.Unauthorized("go.micro.srv.user.login", "該手機号不存在")
	}

	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
		return errors.Unauthorized("go.micro.srv.user.login", "密碼錯誤")
	}

	rsp.Code = "200"
	rsp.Msg = "登入成功"

	return nil
}

func (e *User)UpdatePassword(ctx context.Context, req *user.UpdatePasswordRequest, rsp *user.Response) error {
	user,err := e.Repo.Find(req.Uid)

	if user == nil{
		return errors.Unauthorized("go.micro.srv.user.login", "該使用者不存在")
	}

	if err != nil {
		return err
	}
	//驗證老密碼是否正常
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword)); err != nil {
		return errors.Unauthorized("go.micro.srv.user.login", "舊密碼認證失敗")
	}

	//驗證通過後,對新密碼hash存下來
	hashedPwd, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	user.Password = string(hashedPwd)
	e.Repo.Update(user)

	rsp.Code = "200"
	rsp.Msg =user.Name+",您的密碼更新成功"

	return nil
}
           

修改main.go

因為需要在main.go裡建立資料庫連接配接,在根目錄下建立database.go

package main

import (
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func CreateConnection() (*gorm.DB, error) {
	host := "192.168.0.111"
	user := "mytestroot"
	dbName := "shopping"
	password := "mytestroot"
	return gorm.Open("mysql", fmt.Sprintf(
		"%s:%[email protected](%s:3306)/%s?charset=utf8&parseTime=True&loc=Local",
		user, password, host, dbName,
	),
	)
}

           

然後修改main.go

package main

import (
	"github.com/micro/go-log"
	"github.com/micro/go-micro"
	"github.com/micro/go-grpc"
	"shopping/user/handler"
	"shopping/user/model"
	"shopping/user/repository"

	user "shopping/user/proto/user"
)

func main() {

	db,err := CreateConnection()
	defer db.Close()

	db.AutoMigrate(&model.User{})

	if err != nil {
		log.Fatalf("connection error : %v \n" , err)
	}

	repo := &repository.User{db}

	// New Service
	service := grpc.NewService(
		micro.Name("go.micro.srv.user"),
		micro.Version("latest"),
	)

	// Initialise service
	service.Init()

	// Register Handler
	user.RegisterUserServiceHandler(service.Server(), &handler.User{repo})

	// Register Struct as Subscriber
	//micro.RegisterSubscriber("go.micro.srv.user", service.Server(), new(subscriber.Example))

	// Register Function as Subscriber
	//micro.RegisterSubscriber("go.micro.srv.user", service.Server(), subscriber.Handler)

	// Run service
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}
}

           

啟動服務,驗證接口

go run main.go database.go

micro api --namespace=go.micro.srv

注冊接口

go-micro項目實戰一 建立使用者服務

登入接口

go-micro項目實戰一 建立使用者服務

修改密碼接口

go-micro項目實戰一 建立使用者服務

繼續閱讀