Appearance
项目开发
- 具体使用
kratos命令行工具进行开发
安装 kratos
- 安装 kratos 命令行工具
bash
# 开启 go module
go env -w GO111MODULE=on
# 安装 kratos 命令行工具
go install github.com/go-kratos/kratos/cmd/kratos/v2@latest安装 Protobuf
bash
# mac 安装
brew install protobuf创建项目
- 使用
kratos命令行工具创建一个项目
bash
# 创建一个项目
kratos new <project-name>
# cd 项目目录
cd <project-name>
# 下载依赖
go mod tidy
# 安装 wire 依赖注入工具
go get github.com/google/wire/cmd/wire@latest
# 生成所有proto源码、wire等等
go generate ./...
# 运行项目
kratos run项目结构

移除示例模块
移除 api/helloworld 模块
bash
# 移除示例模块
rm -rf api/helloworld移除helloworld 模块的业务代码
bash
rm -rf internal/biz/greeter.go
rm -rf internal/data/greeter.go
rm -rf internal/service/greeter.go清除注入代码
- 编辑
internal/biz/biz.go文件
bash
# 删除 ProviderSet 中的 NewGreeterUsecase 依赖注入代码
var ProviderSet = wire.NewSet()- 编辑
internal/data/data.go文件
bash
# 删除 ProviderSet 中的 NewGreeterRepo 依赖注入代码
var ProviderSet = wire.NewSet(NewData)- 编辑
internal/service/service.go文件
bash
# 删除 ProviderSet 中的 NewGreeterService 依赖注入代码
var ProviderSet = wire.NewSet()清除服务注入代码
编辑
internal/server/grpc.go文件,移除标红代码即可

编辑
internal/server/http.go文件, 按照上面同样操作即可
添加 Proto 文件
- 根据业务需求创建
admin模块,并创建login业务接口
bash
# 创建 admin 模块 login 业务接口
kratos proto add api/login/login.proto
# 创建 admin 模块 admin 业务接口
kratos proto add api/admin/admin.proto- 示例
login.proto
proto
syntax = "proto3";
package api.login;
import "google/api/annotations.proto";
option go_package = "yellow/api/login;login";
option java_multiple_files = true;
option java_package = "api.login";
service Login {
// 获取登录env信息
rpc Env (EnvRequest) returns (EnvReply){
option (google.api.http) = {
get: "/login/env"
};
};
// 账号登录
rpc LoginAccount (LoginAccountRequest) returns (LoginAccountReply){
option (google.api.http) = {
post: "/login/account",
body: "*",
};
};
}
message EnvRequest {}
message EnvReply {
string uid = 1; // 自动生成的ID
string server = 2; // 当前服务器
// ... 其他参数,自由定制
}
message LoginAccountRequest{
string username = 1; // 登录账号
string password = 2; // 登录密码
}
message LoginAccountReply{
string token = 1; // 登录token
string refresh_token = 2; // 刷新token
}- 示例
admin.proto
proto
syntax = "proto3";
package api.admin;
import "google/api/annotations.proto";
option go_package = "yellow/api/admin;admin";
option java_multiple_files = true;
option java_package = "api.admin";
service Admin {
// 获取登录信息
rpc AdminInfo(AdminInfoRequest) returns (AdminReply){
option (google.api.http) = {
get: "/admin/info"
};
};
// 创建管理员
rpc CreateAdmin (CreateAdminRequest) returns (CreateAdminReply){
option (google.api.http) = {
post: "/admin",
body: "*",
};
};
// 更新管理员
rpc UpdateAdmin (UpdateAdminRequest) returns (UpdateAdminReply){
option (google.api.http) = {
put: "/admin/{id}",
body: "*",
};
};
// 删除管理员
rpc DeleteAdmin (DeleteAdminRequest) returns (DeleteAdminReply){
option (google.api.http) = {
delete: "/admin",
// delete请求不需要 body
};
};
// 获取管理员信息
rpc GetAdmin (GetAdminRequest) returns (AdminReply){
option (google.api.http) = {
get: "/admin/{id}"
};
};
// 管理员信息
rpc ListAdmin (ListAdminRequest) returns (ListAdminReply){
option (google.api.http) = {
get: "/admins"
};
};
}
message AdminInfoRequest{}
message AdminReply{
int64 id = 1; // 用户ID
string name = 2; // 用户名称
string password = 3; // 用户密码
string avatar = 4; // 用户头像
int32 is_dis = 5; // 是否禁用
int32 is_del = 6; // 是否删除
string created_at = 7; // 创建时间
string update_at = 8; // 更新时间
int32 deleted = 9; //删除时间
}
message CreateAdminRequest {
string name = 1; // 用户姓名
string password = 2; // 用户密码
string avatar = 3; // 用户头像
}
message CreateAdminReply{}
message UpdateAdminRequest {
string id = 1;
string name = 2; // 用户名称
string password = 3; // 用户密码
string avatar = 4; // 用户头像
}
message UpdateAdminReply{}
message DeleteAdminRequest {
repeated int64 ids = 1; // 设置复数,批量删除
}
message DeleteAdminReply{}
message GetAdminRequest {
int64 id = 1; // 用户ID
}
message ListAdminRequest {
int32 current_page = 1; // 当前页数
string keyword = 2; // 关键字搜索
}
message ListAdminReply {
int32 total = 1; // 总条数
int32 current_page = 2; // 当前页数
repeated Admin list = 3; // 用户列表
}生成 Proto 代码
bash
# 全部生成
make api
# 生成 admin 模块 login 业务接口的代码
kratos proto client api/login/login.proto
# 生成 admin 模块 admin 业务接口的代码
kratos proto client api/admin/admin.proto- 会在
api/admin目录下生成login.pb.go、login_grpc.pb.go、login_http.pb.go文件 - 会在
api/admin目录下生成admin.pb.go、admin_grpc.pb.go、admin_http.pb.go文件
生成 Service 代码
bash
# 生成 admin 模块 login 业务接口的代码
kratos proto server api/login/login.proto
# 生成 admin 模块 admin 业务接口的代码
kratos proto server api/admin/admin.proto- 会在
internal/service目录下生成login.go和admin.go文件
代码规范
internal/biz 目录
主要用户定义业务逻辑接口,并提供操作实例
创建
internal/biz/login.go文件
go
package biz
import (
"context"
"yellow/api/login"
"github.com/go-kratos/kratos/v2/log"
)
// LoginRepo 定义接口清单
type LoginRepo interface {
Env(ctx context.Context, request login.EnvRequest) (login.EnvReply, error)
LoginAccount(ctx context.Context, request login.LoginAccountRequest) (login.LoginAccountRequest, error)
}
// LoginBiz 定义注入实体
type LoginBiz struct {
repo LoginRepo
log *log.Helper
}
// NewLoginBiz 创建实体
func NewLoginBiz(repo LoginRepo, logger log.Logger) *LoginBiz {
return &LoginBiz{repo: repo, log: log.NewHelper(logger)}
}- 在
internal/biz/biz.go中注入LoginBiz实体
go
package biz
import "github.com/google/wire"
// ProviderSet is biz providers.
var ProviderSet = wire.NewSet(NewLoginBiz)internal/data 目录
完成各种数据连接操作,例如
mysql、redis完成数据库数据操作,例如定义表实体、CURD 操作
完成缓存操作,例如存储缓存
完成 oss,cos 操作方法
完成 文件 操作方法
示例:在
internal/data/data.go文件,完成数据库,redis 连接操作
go
package data
import (
"yellow/internal/conf"
"github.com/go-kratos/kratos/v2/log"
"github.com/google/wire"
"github.com/redis/go-redis/v9"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// ProviderSet is data providers.
var ProviderSet = wire.NewSet(NewData)
// Data .
type Data struct {
db *gorm.DB // gorm 操作数据库
cache *redis.Client // redis 作为缓存
}
// NewData .
func NewData(c *conf.Data, logger log.Logger) (*Data, func(), error) {
cleanup := func() {
log.NewHelper(logger).Info("closing the data resources")
}
return &Data{db: NewMysql(c), cache: NewRedis(c)}, cleanup, nil
}
func NewMysql(c *conf.Data) *gorm.DB {
db, err := gorm.Open(mysql.Open(c.Database.Source), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true,
})
if err != nil {
log.Errorf("failed opening connection to mysql: %v", err)
panic("failed to connect database")
}
return db
}
func NewRedis(c *conf.Data) *redis.Client {
rdb := redis.NewClient(&redis.Options{
Addr: c.Redis.Addr,
Password: c.Redis.Password,
WriteTimeout: c.Redis.WriteTimeout.AsDuration(),
ReadTimeout: c.Redis.ReadTimeout.AsDuration(),
})
if err := rdb.Close(); err != nil {
log.Error(err)
panic("failed to connect redis")
}
return rdb
}- 示例:创建
internal/data/login.go文件,完成数据库操作方法
go
package data
import (
"context"
"yellow/api/login"
"yellow/internal/biz"
"github.com/go-kratos/kratos/v2/log"
)
type LoginData struct {
data *Data
log *log.Helper
}
func NewLoginData(data *Data, logger log.Logger) biz.LoginRepo {
return &LoginData{
data: data,
log: log.NewHelper(logger),
}
}
func (d *LoginData) Env(ctx context.Context, req *login.EnvRequest) (*login.EnvReply, error) {
return &login.EnvReply{}, nil
}
func (d *LoginData) LoginAccount(ctx context.Context, req *login.LoginAccountRequest) (*login.LoginAccountReply, error) {
return &login.LoginAccountReply{}, nil
}internal/service 目录
- 实现具体业务
- 编辑
internal/service/login.go文件
go
package service
import (
"context"
"yellow/internal/biz"
pb "yellow/api/login"
"github.com/go-kratos/kratos/v2/log"
)
type LoginService struct {
pb.UnimplementedLoginServer
// 重点 这里必须 实例化 biz.LoginBiz
biz *biz.LoginBiz
log *log.Helper
}
func NewLoginService(biz *biz.LoginBiz, logger log.Logger) *LoginService {
return &LoginService{
// 重点 这里必须 实例化 biz.LoginBiz
biz: biz,
log: log.NewHelper(logger),
}
}
func (s *LoginService) Env(ctx context.Context, req *pb.EnvRequest) (*pb.EnvReply, error) {
return &pb.EnvReply{}, nil
}
func (s *LoginService) LoginAccount(ctx context.Context, req *pb.LoginAccountRequest) (*pb.LoginAccountReply, error) {
return &pb.LoginAccountReply{}, nil
}go
package service
import (
"context"
"yellow/api/login"
"yellow/internal/biz"
"github.com/go-kratos/kratos/v2/log"
)
type LoginService struct {
biz biz.LoginBiz
log *log.Helper
}
func NewLoginService(biz biz.LoginBiz, logger log.Logger) *LoginService {
return &LoginService{
biz: biz,
log: log.NewHelper(logger),
}
}
func (s *LoginService) Env(ctx context.Context, req *login.EnvRequest) (*login.EnvReply, error) {
return s.biz.Env(ctx, req)
}
func (s *LoginService) LoginAccount(ctx context.Context, req *login.LoginAccountRequest) (*login.LoginAccountReply, error) {
return s.biz.LoginAccount(ctx, req)
}internal/server 目录
注册服务
在
http.go中注册http服务,在grpc.go中注册grpc服务,2 个地方代码基本一样
go
package server
import (
apiLogin "yellow/api/login"
"yellow/internal/conf"
"yellow/internal/service"
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware/recovery"
"github.com/go-kratos/kratos/v2/transport/http"
)
// NewHTTPServer new an HTTP server.
func NewHTTPServer(c *conf.Server, login *service.LoginService, logger log.Logger) *http.Server {
var opts = []http.ServerOption{
http.Middleware(
recovery.Recovery(),
),
}
if c.Http.Network != "" {
opts = append(opts, http.Network(c.Http.Network))
}
if c.Http.Addr != "" {
opts = append(opts, http.Address(c.Http.Addr))
}
if c.Http.Timeout != nil {
opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
}
srv := http.NewServer(opts...)
// 注册login模块
apiLogin.RegisterLoginHTTPServer(srv, login)
return srv
}验证 wire
go
cd <project_name>/cmd
// wire 注入没有报错,即完成成功
wire
// 运行项目
kratos run