Go-kratos 框架商城微服務實戰之使用者服務 (二)
這篇主要編寫服務介面。寫的不清晰的地方可看原始碼,歡迎大佬指教。
- 新增
user.proto
服務介面
注:這裡的目錄有做修改,完整專案目錄為
shop/service/user/api/user/v1/user.proto
, 根目錄還是指代user
目錄
- 編輯
user/api/user/v1/user.proto
檔案
.
.
.
service User{
rpc CreateUser(CreateUserInfo) returns (UserInfoResponse){}; // 建立使用者
rpc GetUserList(PageInfo) returns (UserListResponse){}; // 使用者列表
rpc GetUserByMobile(MobileRequest) returns (UserInfoResponse){}; // 通過 mobile 查詢使用者
rpc GetUserById(IdRequest) returns (UserInfoResponse){}; // 通過 Id 查詢使用者
rpc UpdateUser(UpdateUserInfo) returns (google.protobuf.Empty){}; // 更新使用者
rpc CheckPassword(PasswordCheckInfo) returns (CheckResponse){}; // 驗證使用者密碼
}
.
.
.
// 使用者列表
message UserListResponse{
int32 total = 1;
repeated UserInfoResponse data = 2;
}
// 分頁
message PageInfo{
uint32 pn = 1;
uint32 pSize = 2;
}
message MobileRequest{
string mobile = 1;
}
message IdRequest{
int64 id = 1;
}
message UpdateUserInfo{
int64 id = 1;
string nickName = 2;
string gender = 3;
uint64 birthday = 4;
}
message PasswordCheckInfo{
string password = 1;
string encryptedPassword = 2;
}
message CheckResponse{
bool success = 1;
}
- 重新生成 proto ,根目錄執行命令
make api
- 編寫使用者列表介面
user/internal/data/user.go
檔案下新增兩個方法
// ListUser .
func (r *userRepo) ListUser(ctx context.Context, pageNum, pageSize int) ([]*biz.User, int, error) {
var users []biz.User
result := r.data.db.Find(&users)
if result.Error != nil {
return nil, 0, result.Error
}
total := int(result.RowsAffected)
r.data.db.Scopes(paginate(pageNum, pageSize)).Find(&users)
rv := make([]*biz.User, 0)
for _, u := range users {
rv = append(rv, &biz.User{
ID: u.ID,
Mobile: u.Mobile,
Password: u.Password,
NickName: u.NickName,
Gender: u.Gender,
Role: u.Role,
Birthday: u.Birthday,
})
}
return rv, total, nil
}
// paginate 分頁
func paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
if page == 0 {
page = 1
}
switch {
case pageSize > 100:
pageSize = 100
case pageSize <= 0:
pageSize = 10
}
offset := (page - 1) * pageSize
return db.Offset(offset).Limit(pageSize)
}
}
user/internal/biz/user.go
檔案修改
package biz
.
.
..
.
.
type UserRepo interface {
CreateUser(context.Context, *User) (*User, error)
ListUser(ctx context.Context, pageNum, pageSize int) ([]*User, int, error)
}
.
.
.
func (uc *UserUsecase) List(ctx context.Context, pageNum, pageSize int) ([]*User, int, error) {
return uc.repo.ListUser(ctx, pageNum, pageSize)
}
user/internal/service/user.go
檔案新增程式碼
.
.
.
// GetUserList .
func (u *UserService) GetUserList(ctx context.Context, req *v1.PageInfo) (*v1.UserListResponse, error) {
list, total, err := u.uc.List(ctx, int(req.Pn), int(req.PSize))
if err != nil {
return nil, err
}
rsp := &v1.UserListResponse{}
rsp.Total = int32(total)
for _, user := range list {
userInfoRsp := UserResponse(user)
rsp.Data = append(rsp.Data, &userInfoRsp)
}
return rsp, nil
}
func UserResponse(user *biz.User) v1.UserInfoResponse {
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
}
- 編寫手機號查詢使用者介面
user/internal/data/user.go
檔案下新增
.
.
.
// UserByMobile .
func (r *userRepo) UserByMobile(ctx context.Context, mobile string) (*biz.User, error) {
var user biz.User
result := r.data.db.Where(&biz.User{Mobile: mobile}).First(&user)
if result.Error != nil {
return nil, result.Error
}
if result.RowsAffected == 0 {
return nil, status.Errorf(codes.NotFound, "使用者不存在")
}
return &user, nil
}
user/internal/biz/user.go
檔案修改
package biz
.
.
.
type UserRepo interface {
CreateUser(context.Context, *User) (*User, error)
ListUser(ctx context.Context, pageNum, pageSize int) ([]*User, int, error)
UserByMobile(ctx context.Context, mobile string) (*User, error)
}
.
.
.
func (uc *UserUsecase) UserByMobile(ctx context.Context, mobile string) (*User, error) {
return uc.repo.UserByMobile(ctx, mobile)
}
user/internal/service/user.go
檔案新增程式碼. . . // GetUserByMobile . func (u *UserService) GetUserByMobile(ctx context.Context, req *v1.MobileRequest) (*v1.UserInfoResponse, error) { user, err := u.uc.UserByMobile(ctx, req.Mobile) if err != nil { return nil, err } rsp := UserResponse(user) return &rsp, nil }
- 編寫ID查詢使用者介面
和手機號查詢差不多這裡就不重複寫了
user/internal/data/user.go
檔案下新增user/internal/biz/user.go
檔案修改user/internal/service/user.go
檔案新增程式碼
- 編寫使用者更新介面
user/internal/data/user.go
檔案下新增
.
.
.
// UpdateUser .
func (r *userRepo) UpdateUser(ctx context.Context, user *biz.User) (bool, error) {
var userInfo biz.User
result := r.data.db.Where(&biz.User{ID: user.ID}).First(&userInfo)
if result.RowsAffected == 0 {
return false, status.Errorf(codes.NotFound, "使用者不存在")
}
userInfo.NickName = user.NickName
userInfo.Birthday = user.Birthday
userInfo.Gender = user.Gender
res := r.data.db.Save(&userInfo)
if res.Error != nil {
return false, status.Errorf(codes.Internal, res.Error.Error())
}
return true, nil
}
user/internal/biz/user.go
檔案修改
package biz
.
.
.
type UserRepo interface {
CreateUser(context.Context, *User) (*User, error)
ListUser(ctx context.Context, pageNum, pageSize int) ([]*User, int, error)
UserByMobile(ctx context.Context, mobile string) (*User, error)
UpdateUser(context.Context, *User) (bool, error)
}
.
.
.
func (uc *UserUsecase) UpdateUser(ctx context.Context, user *User) (bool, error) {
return uc.repo.UpdateUser(ctx, user)
}
user/internal/service/user.go
檔案新增程式碼
.
.
.
// UpdateUser .
func (u *UserService) UpdateUser(ctx context.Context, req *v1.UpdateUserInfo) (*emptypb.Empty, error) {
birthDay := time.Unix(int64(req.Birthday), 0)
user, err := u.uc.UpdateUser(ctx, &biz.User{
ID: req.Id,
Gender: req.Gender,
Birthday: &birthDay,
NickName: req.NickName,
})
if err != nil {
return nil, err
}
if user == false {
return nil, err
}
return &empty.Empty{}, nil
}
- 編寫驗證使用者密碼介面
user/internal/data/user.go
檔案下新增方法
// import "github.com/anaskhan96/go-password-encoder"
// import "crypto/sha512"
// CheckPassword .
func (r *userRepo) CheckPassword(ctx context.Context, pwd, encryptedPassword string) (bool, error) {
options := &password.Options{SaltLen: 16, Iterations: 10000, KeyLen: 32, HashFunction: sha512.New}
passwordInfo := strings.Split(encryptedPassword, "$")
check := password.Verify(pwd, passwordInfo[2], passwordInfo[3], options)
return check, nil
}
user/internal/biz/user.go
檔案修改
package biz
.
.
.
type UserRepo interface {
CreateUser(context.Context, *User) (*User, error)
ListUser(ctx context.Context, pageNum, pageSize int) ([]*User, int, error)
UserByMobile(ctx context.Context, mobile string) (*User, error)
UpdateUser(context.Context, *User) (bool, error)
CheckPassword(ctx context.Context, password, encryptedPassword string) (bool, error)
}
.
.
.
func (uc *UserUsecase) CheckPassword(ctx context.Context, password, encryptedPassword string) (bool, error) {
return uc.repo.CheckPassword(ctx, password, encryptedPassword)
}
user/internal/service/user.go
檔案新增程式碼
// CheckPassword .
func (u *UserService) CheckPassword(ctx context.Context, req *v1.PasswordCheckInfo) (*v1.CheckResponse, error) {
check, err := u.uc.CheckPassword(ctx, req.Password, req.EncryptedPassword)
if err != nil {
return nil, err
}
return &v1.CheckResponse{Success: check}, nil
}
- 簡單編寫測試程式碼
啟動專案
krtaos run
修改測試檔案
user/test/user.go
放開註釋,進行本檔案進行測試
.
.
.
func main() {
Init()
TestGetUserList() // 獲取使用者列表
//TestCreateUser() // 建立使用者
//TestUpdateUser() // 更新使用者
//TestGetUserByMobile() // 根據手機獲取使用者
conn.Close()
}
.
.
.
func TestGetUserList() {
r, err := userClient.GetUserList(context.Background(), &v1.PageInfo{
Pn: 1,
PSize: 6,
})
if err != nil {
panic("grpc get err" + err.Error())
}
for _, user := range r.Data {
fmt.Println(user.Mobile, user.NickName, user.Password)
// 驗證密碼
checkRsp, err := userClient.CheckPassword(context.Background(), &v1.PasswordCheckInfo{
Password: "admin",
EncryptedPassword: user.Password,
})
if err != nil {
panic(" get check user psw err" + err.Error())
}
fmt.Println(checkRsp.Success)
}
fmt.Println(r.Total)
}
func TestGetUserByMobile() {
rsp, err := userClient.GetUserByMobile(context.Background(), &v1.MobileRequest{
Mobile: "13501167228",
})
if err != nil {
panic("grpc get user by mobile err" + err.Error())
}
fmt.Println(rsp)
}
func TestUpdateUser() {
rsp, err := userClient.UpdateUser(context.Background(), &v1.UpdateUserInfo{
Id: 19,
Gender: "female",
NickName: fmt.Sprintf("YWW%d", 233),
})
if err != nil {
panic("grpc update user err" + err.Error())
}
fmt.Println(rsp)
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結