前面《kratos微服务实战(五)kratos项目之自定义接口》我们实现了自定义接口,在登录的时候,没有做任何的逻辑,同时数据也没有与数据库进行交互,所以这里接入gorm框架来操作mysql。
一、创建数据库
这里我们使用mysql的test库,在test库里面创建一张accounts的表,ddl语句如下:
CREATE TABLE `accounts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `nickname` varchar(255) DEFAULT NULL, `ico` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `sex` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
然后向这张表插入一条数据
INSERT INTO `test`.`accounts` (`id`, `username`, `password`, `nickname`, `ico`, `age`, `sex`) VALUES (1, 'zhangsan', '123456', '张三', 'http://gips0.baidu.com/it/u=1690853528,2506870245&fm=3028&app=3028&f=JPEG&fmt=auto?w=1024&h=1024', 20, 1);
二、安装依赖
这里我们使用gorm框架操作mysql,所以需要在安装下依赖
#安装mysql依赖 go get gorm.io/driver/mysql #安装grom依赖 go get gorm.io/gorm
三、编写数据库连接配置
前面我们介绍了,操作业务数据mysql这些dao相关的操作的代码是写在internal/data目录下的,所以这里按照这个规范来执行即可。这里主要做的就是初始化mysql的连接、初始化mysql连接的代码直接在internal/data/data.go文件中执行即可。所以操作步骤如下:
1、展开type Date struct,把db设置成变量
type Data struct { db *gorm.DB }
这里的data struct是创建项目自动创建好了,只需要在这里添加变量即可。
2、改写newData方法
这里我们需要在默认生成的NewData方法里面添加一个db的传参变量,然后把这个变量赋值给Data对象,完整代码如下:
func NewData(c *conf.Data, logger log.Logger, db *gorm.DB) (*Data, func(), error) { cleanup := func() { log.NewHelper(logger).Info("closing the data resources") } return &Data{ db: db, }, cleanup, nil }
3、编写初始化数据库连接的方法
新创建一个方法NewDbEngine,这里主要是初始化数据库连接,完整代码示例如下:
func NewDbEngine(c *conf.Data) (db *gorm.DB, err error) { db, err = gorm.Open(mysql.Open(c.Database.Source), &gorm.Config{}) return db, err }
4、注册NewDbEngine
后面会涉及到使用wire自动注入,所以这里需要把NewDbEngine给注册下,直接拖到最上边,可以看到一行代码:
var ProviderSet = wire.NewSet(NewData, NewGreeterRepo)
我们把这里的NewDbEngine给添加进去即可,示例如下:
var ProviderSet = wire.NewSet(NewData, NewGreeterRepo, NewDbEngine)
5、修改config
这里需要修改下mysql的连接,mysql的配置信息在configs/config.yaml文件,修改mysql即可
四、编写domain层
这里我们编写对应的model,及model相关的查询方法,在internal/biz目录下创建一个account.go的文件
我们需要再这个account.go里面定义如下信息:
1、定义model对象 2、定义查询account相关信息的repository 3、为repository编写查询相关信息的抽象方法 4、实例化repository 5、声明可用于自动注入的UseCase 6、编写调用respository(dao)层实现的方法
所以完整的account.go代码如下:
package biz import ( "context" pb "user-center/api/account/v1" ) /* * 定义account对象 */ type Account struct { Username string `json:"username"` Password string `json:"password"` Nickname string `json:"nickname"` Icon string `json:"icon"` Age int `json:"age"` Sex int `json:"sex"` } /* * 编写关于account操作dao查询的方法,看作是java的repository层 */ type AccountRepo interface { FindByUsernameAndPassword(ctx context.Context, loginReq *pb.LoginRequest) (acc *Account, err error) } /* * 定义account使用实例,用于自动注入account实例 */ type AccountUseCase struct { acc AccountRepo } /* * 实例化AccountUserCase */ func NewAccountUseCase(acc AccountRepo) *AccountUseCase { return &AccountUseCase{acc: acc} } /* *这个方法*可以看作是service层编写方法去调用dao层的过渡方法 *通过用户名和密码查找用户信息 */ func (uc *AccountUseCase) GetAccountInfoByUsernameAndPassword(ctx context.Context, loginReq *pb.LoginRequest) (acc *Account, err error) { res, err := uc.acc.FindByUsernameAndPassword(ctx, loginReq) return res, err }
前面我们编写好了之后,还需要把account.go这里的usecase注册上去,接着打开internal/biz/biz.go文件,可以看到自动注入了helloworld的usecase
这里把NewAccountUseCase注册上去即可,示例如下:
var ProviderSet = wire.NewSet(NewGreeterUsecase, NewAccountUseCase)
五、编写dao层代码
dao层的代码时再internal/data下面编写的,所以这里我们继续再internal/data下面创建一个account.go文件
这里我们主要是做两件事情:
1、引用前面注册的AccountRepo 2、实现在biz里面定义的repository的抽象方法
所以这里完整的代码示例如下:
package data import ( "context" "fmt" v1 "user-center/api/account/v1" "user-center/internal/biz" ) type accountRepo struct { data *Data } func NewAccountRepo(data *Data) biz.AccountRepo { return &accountRepo{ data: data, } } func (acc accountRepo) FindByUsernameAndPassword(ctx context.Context, loginReq *v1.LoginRequest) (res *biz.Account, err error) { account := &biz.Account{} acc.data.db.Where("username = ? and password = ?", loginReq.Username, loginReq.Password).First(&account) fmt.Println("准备查找用户", account) return account, nil }
这里同样的,dao层的代码写完之后,需要注册进去,打开internal/data/data.go文件,可以看到这行代码
var ProviderSet = wire.NewSet(NewData, NewGreeterRepo, NewDbEngine)
这里我们把上面的NewAccountRepo注册进去,注册后的代码是:
var ProviderSet = wire.NewSet(NewData, NewGreeterRepo, NewDbEngine, NewAccountRepo)
六、编写service逻辑
这里就简单了,回到internal/service/account.go文件(这个文件实在上一篇里面使用kratos proto server生成的),找到刚才的login实现的地方。这里整个操作数据库的逻辑是:
1、service层的login 调用 biz层的查找用户方法 2、biz层的查找用户方法 调用 dao层的数据库操作方法 3、原路返回查找结果并且处理
所以我们改造后的internal/service/account.go文件的login方法的完整代码如下:
func (s *AccountService) Login(ctx context.Context, req *pb.LoginRequest) (*pb.LoginResponse, error) { acc, err := s.uc.GetAccountInfoByUsernameAndPassword(ctx, req) fmt.Println("查询用户是:{}", acc) if err != nil { return &pb.LoginResponse{Code: 401, Msg: "用户不存在", }, nil } else { return &pb.LoginResponse{Code: 200, Msg: "请求成功", Token: "123456"}, nil } }
备注:
1、这里我们主要是为了跟后续使用token再接上其他接口使用,暂时就不在这里把用户数据返回回去了,不然要重新编译account.proto比较麻烦。
2、这里我们暂时使用fmt打印日志的方式来查看调用mysql是否成功。
七、自动注入
这里还是一样的,前面注册了biz和data,这里直接使用wire自动注入一遍
#进入cmd目录 cd cmd/user-center #自动注入 wire
执行完成之后可以查看到wire_gen.go的文件多出来了repo和usecase的部分
八、启动测试
最后我们把项目启动起来测试一下。
同时在控制台可以看到打印出来了查询的用户信息和执行的sql
以上就是我们为kratos微服务添加使用gorm操作数据库的案例。最后按照惯例,附上本案例的源码,登陆后即可下载。
还没有评论,来说两句吧...