go-kratos v2 + gorm 實現增刪改查demo
由於正在學習Bilibili的go開源框架 go-kratos,簡單學習的過程中有一些摸索過程,現在根據go-kratos v2 + gorm 實現增刪改查demo實現用戶的增刪改查
mysql用戶表
#sql
CREATE TABLE `user` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` char(20) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '名稱',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用戶表';
項目初始化
0.文檔地址
1.創建項目模板
kratos new user
cd user
2.拉取項目依賴
go mod download
3.生成proto模板
kratos proto add api/user/user.proto
這個時候我們去修改api/user/user.proto, 先僅僅實現用戶新增功能,代碼如下
syntax = "proto3";
package api.user.v1;
option go_package = "users/api/user/v1;v1";
option java_multiple_files = true;
option java_package = "api.user.v1";
import "google/api/annotations.proto";
// the validate rules:
// https://github.com/envoyproxy/protoc-gen-validate
import "validate/validate.proto";
service user {
// 用戶創建
rpc CreateUser(CreateUserRequest) returns (CreateUserReply){
option (google.api.http) = {
post: "/v1/user"
body: "*"
};
}
message User {
int64 id = 1;
string name = 2;
}
message CreateUserRequest {
string name = 1 [(validate.rules).string = {min_len : 5, max_len: 50}];
}
message CreateUserReply {
User User = 1;
}
proro文件中有參數校驗,使用 proto-gen-validate 文檔地址
4.生成proto源碼 文檔地址
kratos proto client api/user/user.proto
5.生成server模板
kratos proto server api/user/user.proto -t internal/service
coding階段
打開 internal/service/user.go,代碼如下:
package service
import (
"context"
"github.com/go-kratos/kratos/v2/log"
"users/internal/biz"
pb "users/api/user/v1"
)
type UserService struct {
pb.UnimplementedUserServer
uc *biz.UserUseCase
log *log.Helper
}
func NewUserService(uc *biz.UserUseCase, logger log.Logger) *UserService {
return &UserService{uc:uc, log: log.NewHelper(logger)}
}
// 用戶創建
func (s *UserService) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserReply, error) {
s.log.WithContext(ctx).Infof("CreateUser Received: %v", req)
user := biz.User{
Id: 0,
Name: req.Name,
}
return &pb.CreateUserReply{}, s.uc.Create(ctx, &user)
}
打開 internal/service/service.go,代碼如下:
package service
import "github.com/google/wire"
// ProviderSet is service providers.
var ProviderSet = wire.NewSet(NewUserService)
代碼中引入了biz.User, 建立 ./internal/biz/user.go
package biz
import (
"context"
"github.com/go-kratos/kratos/v2/log"
)
type User struct {
Id int64
Name string
}
type UserRepo interface{
CreateUser(ctx context.Context, user *User) error
}
type UserUseCase struct{
repo UserRepo
log *log.Helper
}
func NewUserUseCase(repo UserRepo, logger log.Logger) *UserUseCase {
return &UserUseCase{repo:repo, log: log.NewHelper(logger)}
}
// 創建
func (uc *UserUseCase) Create(ctx context.Context, user *User) error {
return uc.repo.CreateUser(ctx, user)
}
修改 ./internal/biz/biz.go
package biz
import "github.com/google/wire"
// ProviderSet is biz providers.
var ProviderSet = wire.NewSet(NewUserUseCase)
打開 ./internal/data/data.go
package data
import (
"users/internal/conf"
"github.com/go-kratos/kratos/v2/log"
"github.com/google/wire"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// ProviderSet is data providers.
var ProviderSet = wire.NewSet(NewData, NewUserRepo)
// Data .
type Data struct {
db *gorm.DB
}
// NewData .
func NewData(conf *conf.Data, logger log.Logger) (*Data, func(), error) {
log := log.NewHelper(logger)
// mysql數據庫連接
db, err := gorm.Open(mysql.Open(conf.Database.Source), &gorm.Config{});
if err != nil {
return nil, nil, err
}
d := &Data{
db: db,
}
return d, func() {
log.Info("message", "closing the data resources")
}, nil
}
建立 ./internal/data/user.go
package data
import (
"context"
"errors"
"github.com/go-kratos/kratos/v2/log"
"gorm.io/gorm"
"users/internal/biz"
"users/internal/data/model"
)
type userRepo struct {
data *Data
log *log.Helper
}
func (u userRepo) CreateUser(ctx context.Context, user *biz.User) error {
// 判斷名稱是否存在,存在則返回錯誤
record := u.GetUserByName(user.Name)
if record.Id != 0 {
return errors.New("用戶名已存在")
}
return u.data.db.Model(&model.User{}).Create(&model.User{
Id: 0,
Name: user.Name,
}).Error
}
func NewUserRepo(data *Data, logger log.Logger) biz.UserRepo {
return &userRepo{
data: data,
log: log.NewHelper(logger),
}
}
建立 ./internal/data/model/user.go
package model
type User struct{
Id int64 `json:"id"`
Name string `json:"name"`
}
func (User) TableName() string {
return "user"
}
修改./internal/server/http.go
package server
import (
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware/logging"
"github.com/go-kratos/kratos/v2/middleware/metrics"
"github.com/go-kratos/kratos/v2/middleware/recovery"
"github.com/go-kratos/kratos/v2/middleware/tracing"
"github.com/go-kratos/kratos/v2/middleware/validate"
"github.com/go-kratos/kratos/v2/transport/http"
v1 "users/api/user/v1"
"users/internal/conf"
"users/internal/service"
)
// NewHTTPServer new a HTTP server.
func NewHTTPServer(c *conf.Server, user *service.UserService, logger log.Logger) *http.Server {
var opts = []http.ServerOption{
http.Middleware(
recovery.Recovery(),
tracing.Server(),
logging.Server(logger),
metrics.Server(),
validate.Validator(),
),
}
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...)
v1.RegisterUserHTTPServer(srv, user)
return srv
}
修改./internal/server/grpc.go
package server
import (
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware/logging"
"github.com/go-kratos/kratos/v2/middleware/metrics"
"github.com/go-kratos/kratos/v2/middleware/recovery"
"github.com/go-kratos/kratos/v2/middleware/tracing"
"github.com/go-kratos/kratos/v2/middleware/validate"
"github.com/go-kratos/kratos/v2/transport/grpc"
v1 "users/api/user/v1"
"users/internal/conf"
"users/internal/service"
)
// NewGRPCServer new a gRPC server.
func NewGRPCServer(c *conf.Server, user *service.UserService, logger log.Logger) *grpc.Server {
var opts = []grpc.ServerOption{
grpc.Middleware(
recovery.Recovery(),
tracing.Server(),
logging.Server(logger),
metrics.Server(),
validate.Validator(),
),
}
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
}
修改配置文件
打開 ./configs/config.yaml,修改成自己的數據庫
server:
http:
addr: 0.0.0.0:8000
timeout: 1s
grpc:
addr: 0.0.0.0:9000
timeout: 1s
data:
database:
driver: mysql
source: root: root@tcp(127.0.0.1:3306)/kratos_user?charset=utf8&parseTime=True&loc=Local
redis:
addr: 127.0.0.1:6379
read_timeout: 0.2s
write_timeout: 0.2s
項目編譯
生成所有proto源碼、wire等等
go generate ./...
運行項目
kratos run
發起請求 (postman)
POST localhost:8000/v1/user
{
"name":"周周周周周"
}
以上是單個http接口請求,完整的增刪改查自行下載
鏈接: https://pan.baidu.com/s/1mfUGAFr4YA3GtQUJ9Gd6TQ 密碼: 2cma