go-micro微服务实战-创建用户服务
go-micro微服务实战-创建用户服务
网上按照一些微服务实战项目学习,以此深入学习微服务,这里我选择go-micro
用户服务
用户服务提供用户注册、用户登录、修改密码等功能
新建服务
go-micro new service user
整理目录结构
增加model目录和repository目录(MVC),删掉proto里默认内容,创建config目录。
开发步骤:1.定义接口(proto) -> 2.生成接口代码 -> 3.编写model层代码 -> 4.编写repository数据操作代码 -> 5.实现接口 -> 6.修改main.go
定义用户服务接口
user.proto
syntax = "proto3";
package user;
option go_package = "./proto;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.proto
编写model.user
model/user.go
package model
var Models = []interface{}{
&User{},
}
type Model struct {
Id uint32 `gorm:"primaryKey;autoIncrement" json:"id" form:"id"`
}
type User struct {
Model
Name string `gorm:"size:32;unique;" json:"name" form:"name"`
Phone string `gorm:"size:32;unique;" json:"phone" form:"phone"`
Password string `gorm:"size:512" json:"password" form:"password"`
}
编写repository.user
repository/user.go
package repository
import (
"gorm.io/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 = 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
handler/user.go
package handler
import (
"context"
"fmt"
"go-micro.dev/v4/errors"
log "go-micro.dev/v4/logger"
"golang.org/x/crypto/bcrypt"
"shopping/user/model"
"shopping/user/repository"
userpb "shopping/user/proto"
)
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 *userpb.RegisterRequest, rsp *userpb.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(4, "create error")
return err
}
rsp.Code = "200"
rsp.Msg = "注册成功"
return nil
}
func (e *User)Login(ctx context.Context, req *userpb.LoginRequest, rsp *userpb.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 *userpb.UpdatePasswordRequest, rsp *userpb.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
package main
import (
"flag"
"shopping/user/config"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"shopping/user/handler"
"shopping/user/model"
"github.com/mlogclub/simple/sqls"
userpb "shopping/user/proto"
"shopping/user/repository"
"go-micro.dev/v4"
log "go-micro.dev/v4/logger"
)
var (
service = "user"
version = "latest"
configFile = flag.String("config", "\xxxx\config\config.yml", "配置文件路径")
)
func main() {
flag.Parse()
// 初始化配置
conf := config.Init(*configFile)
// gorm配置
gormConf := &gorm.Config{
NamingStrategy: schema.NamingStrategy{
SingularTable: true, // 单数形式,User表名为user 复数形式 User的表名应该是users
TablePrefix: "t_", //表名前缀 User的表名应该是t_user
},
}
// 连接数据库
if err := sqls.Open(conf.DB.Url, gormConf, conf.DB.MaxIdleConns, conf.DB.MaxOpenConns, model.Models...); err != nil {
log.Fatal(err)
}
// Create service
srv := micro.NewService(
micro.Name(service),
micro.Version(version),
)
srv.Init()
repo := &repository.User{sqls.DB()}
// Register handler
userpb.RegisterUserServiceHandler(srv.Server(), &handler.User{repo})
// Run service
if err := srv.Run(); err != nil {
log.Fatal(err)
}
}
补充下config
config/config.yml
# 数据库配置
DB:
Url: user:password!@#@tcp(xx.xx.xx.xx:3306)/shopping?charset=utf8mb4&parseTime=True&loc=Local
MaxIdleConns: 50
MaxOpenConns: 200
config/config.go
package config
import (
"fmt"
"io/ioutil"
"gopkg.in/yaml.v2"
log "go-micro.dev/v4/logger"
)
var Instance *Config
type Config struct {
// 数据库配置
DB struct {
Url string `yaml:"Url"`
MaxIdleConns int `yaml:"MaxIdleConns"`
MaxOpenConns int `yaml:"MaxOpenConns"`
} `yaml:"DB"`
}
func Init(filename string) *Config {
Instance = &Config{}
if yamlFile, err := ioutil.ReadFile(filename); err != nil {
fmt.Println(err)
log.Fatal(err)
} else if err = yaml.Unmarshal(yamlFile, Instance); err != nil {
fmt.Println(err)
log.Fatal(err)
}
return Instance
}
运行验证
服务端
go run main.go
调用
> go-micro call user UserService.Register "{\"user\":{\"id\":1,\"name\": \"liaolin\",\"phone\":\"13218289117\",\"password\":\"123456\"}}"
{"code":"200","msg":"注册成功"}
> go-micro call user UserService.Login "{\"phone\":\"13218289117\",\"password\":\"123456\"}"
{"code":"200","msg":"登录成功"}
> go-micro call user UserService.UpdatePassword "{\"uid\":1,\"oldPassword\": \"123456\",\"newPassword\":\"654321\",\"confirmPassword\":\"654321\"}"
{"code":"200","msg":"liaolin,您的密码更新成功"}
> go-micro call user UserService.Login "{\"phone\":\"13218289117\",\"password\":\"123456\"}"
{"id":"go.micro.srv.user.login","code":401,"detail":"密码错误","status":"Unauthorized"}
> go-micro call user UserService.Login "{\"phone\":\"13218289117\",\"password\":\"654321\"}"
{"code":"200","msg":"登录成功"}

浙公网安备 33010602011771号