因为前端业务需求的多样性与敏捷性,我们可能考虑需要用php 作为client,实现数据的组装与拼接,以应对前端的多边的需求;用go 来实现server端。我们采用laravel 作为client的框架,kratos 作为server
在$GOPATH 的src 下创建项目目录并初始化
# 创建目录
$ mkdir -p kratos-tiway
# 初始化
$ go mod init
我们准备创建app目录作为server目录,api 作为proto 和client 文件目录
$ mkdir -p app
$ mkdir -p api
在app目录下使用 --nomod 添加服务,共用 go.mod ,
创建user 服务
创建user proto
kratos new app/user --nomod
kratos proto add api/user/v1/user.proto
我们现在看下我们项目的整体架构
编辑用户的proto
syntax = "proto3";
package user.v1;
option go_package = "kratos-tiway/api/user/v1;v1";
service User {
rpc GetUserList(SearchUser) returns (UserListResponse){}; // 用户列表
rpc GetUserByMobile(MobileRequest) returns (UserInfoResponse){}; // 通过 mobile 查询用户
rpc GetUserByNickname(NicknameRequest) returns (UserInfoResponse){}; // 通过 昵称 查询用户
rpc GetUserById(IdRequest) returns (UserInfoResponse){}; // 通过 Id 查询用户
rpc CreateUser(CreateUserInfo) returns (UserInfoResponse){}; // 创建用户
rpc UpdateUser(UpdateUserInfo) returns (UpdateUserResponse){}; // 更新用户
rpc CheckPassword(PasswordCheckInfo) returns (CheckResponse){}; // 检查用户密码
}
message SearchUser {
int32 page = 1;
int32 limit = 2;
int64 id = 3;
string name = 4;
string nickname = 5;
string email = 6;
string mobile = 7;
int32 status = 8;
int64 created_at = 9;
}
message UserInfoResponse{
int64 id = 1;
string name = 2;
string mobile = 3;
string nickName = 4;
string email = 5;
string password = 6;
int32 status = 7;
int64 created_at = 8;
}
message UserListResponse{
int32 total = 1;
repeated UserInfoResponse data = 2;
}
message MobileRequest{
string mobile = 1;
}
message NicknameRequest{
string nickname = 1;
}
message IdRequest{
int64 id = 1;
}
// 创建用户
message CreateUserInfo{
string mobile = 1;
string nickname = 2;
string password = 3;
}
message UpdateUserInfo{
int64 id = 1;
string nickname = 2;
string name = 3;
string mobile = 4;
string email = 5;
}
message PasswordCheckInfo{
string Mobile = 1;
string password = 2;
}
message CheckResponse{
bool success = 1;
}
message UpdateUserResponse {
bool success = 1;
string message = 2;
}
生成client
kratos proto client api/user/v1/user.proto
生成server
$ kratos proto server api/user/v1/user.proto -t app/user/internal/service
app/user/internal/service/user.go
删除多余文件
rm app/user/internal/biz/greeter.go
rm app/user/internal/data/greeter.go
rm app/user/internal/server/http.go
rm app/user/internal/service/greeter.go
创建数据数据库与表结构
CREATE DATABASE [IF NOT EXISTS] kratos-tiway;
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(50) NOT NULL COMMENT '用户名',
`nickname` varchar(150) DEFAULT NULL COMMENT '昵称',
`avatar` varchar(150) DEFAULT NULL COMMENT '头像',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
`salt` varchar(40) DEFAULT NULL COMMENT '加密盐',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`mobile` varchar(100) DEFAULT NULL COMMENT '手机号',
`status` tinyint DEFAULT NULL COMMENT '状态 0:禁用 1:正常',
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更细时间',
`deleted_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '删除时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='用户表';
链接数据库kratos-tiway/app/user/internal/data/data.go
package data
import (
"github.com/go-kratos/kratos/v2/log"
_ "github.com/go-sql-driver/mysql"
"github.com/google/wire"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"kratos-tiway/app/user/internal/conf"
)
// ProviderSet is data providers.
var ProviderSet = wire.NewSet(
NewData,
NewDB,
NewUserRepo,
)
// Data .
type Data struct {
db *gorm.DB
log *log.Helper
}
func NewDB(conf *conf.Data, logger1 log.Logger) *gorm.DB {
log := log.NewHelper(log.With(logger1, "module", "ums-service/data/gorm"))
db, err := gorm.Open(mysql.Open(conf.Database.Source), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
log.Fatalf("failed opening connection to mysql: %v", err)
}
return db
}
// NewData .
func NewData(db *gorm.DB, logger log.Logger) (*Data, func(), error) {
log := log.NewHelper(log.With(logger, "module", "order-service/data"))
d := &Data{
db: db,
log: log,
}
return d, func() {
}, nil
}
修改app/user/internal/server/grpc.go
func NewGRPCServer(c *conf.Server, user *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, user)
return srv
}
app/user/internal/server/server.go 去除http server 依赖声明
var ProviderSet = wire.NewSet(NewGRPCServer)