go-zero整合单机版Redis并实现增删改查
本教程基于go-zero微服务入门教程
,项目工程结构同上一个教程。
本教程主要实现go-zero框架整合单机版Redis,并暴露接口实现对Redis数据的增删改查。
本文源码:https://gitee.com/songfayuan/go-zero-demo (教程源码分支:2.zero整合单机Redis)
准备工作
- 如不熟悉go-zero项目的,请先查看上一篇
go-zero微服务入门教程
。 - 请自行安装好单机版Redis,建议采用docker安装。
rpc新增Redis配置
以下操作在rpc模块执行。
sys.yaml
sys.yaml配置文件新增Redis配置信息,如下:
# Redis配置
RedisConf:
Host: 192.168.2.204:6379
Type: node
Pass: "123456789"
Tls: false
config.go
config.go文件中新增RedisConf配置信息,如下:
RedisConf struct {
Host string
Type string `json:",default=node,options=node|cluster"`
Pass string `json:",optional"`
Tls bool `json:",optional"`
}
servicecontext.go
servicecontext.go文件新增Redis配置信息,完整代码如下:
package svc
import (
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"go-zero-demo/rpc/model/sysmodel"
"go-zero-demo/rpc/sys/internal/config"
)
type ServiceContext struct {
Config config.Config
RedisClient *redis.Redis
UserModel sysmodel.SysUserModel
}
func NewServiceContext(c config.Config) *ServiceContext {
sqlConn := sqlx.NewMysql(c.Mysql.Datasource)
conf := redis.RedisConf{
Host: c.RedisConf.Host,
Type: c.RedisConf.Type,
Pass: c.RedisConf.Pass,
Tls: c.RedisConf.Tls,
}
return &ServiceContext{
Config: c,
RedisClient: redis.MustNewRedis(conf),
UserModel: sysmodel.NewSysUserModel(sqlConn),
}
}
编写rpc服务
修改sys.proto文件
新增Redis操作请求的配置,如下:
message RedisReq{
string name = 1;
string nickName = 2;
string password = 3;
string email = 4;
string key = 5;
}
message RedisResp{
string name = 1;
string nickName = 2;
string password = 3;
string email = 4;
}
service Sys{
// redis增删改查
rpc RedisAdd(RedisReq)returns(RedisResp);
rpc RedisDelete(RedisReq)returns(RedisResp);
rpc RedisUpdate(RedisReq)returns(RedisResp);
rpc RedisGet(RedisReq)returns(RedisResp);
}
用goctl生成rpc代码
生成方法同上篇文章,自行查看。
编写API Gateway代码
编写api文件
redis.api
在api目录下创建新目录doc/redis,在redis目录下创建redis.api文件。
syntax = "v1"
info(
title: "Redis操作相关"
desc: "Redis操作相关"
author: "宋发元"
)
type (
ApiRedisReq {
Name string `json:"name"`
NickName string `json:"nickName"`
Password string `json:"password,optional"`
Email string `json:"email"`
}
ApiRedisResp {
Code int64 `json:"code"`
Message string `json:"message"`
Data ApiRedisReq `json:"data"`
}
ApiRedisGetReq {
Key string `form:"key"`
}
)
@server (
group : redis/test
prefix : /redis/test
)
service admin-api{
@doc(
summary : "Redis新增数据"
)
@handler RedisAdd
post /redisAdd(ApiRedisReq)returns(ApiRedisResp)
@doc(
summary : "Redis删除数据"
)
@handler RedisDelete
post /redisDelete(ApiRedisReq)returns(ApiRedisResp)
@doc(
summary : "Redis修改数据"
)
@handler RedisUpdate
post /redisUpdate(ApiRedisReq)returns(ApiRedisResp)
@doc(
summary : "Redis查询数据"
)
@handler RedisGet
get /redisGet(ApiRedisGetReq)returns(ApiRedisResp)
}
admin.api
在api/doc/目录下创建admin.api文件。
import "sys/user.api"
import "redis/redis.api"
info(
title : "Golang学习项目"
author: "songfayuan"
email: "songfayuan123@qq.com"
version: "1.0.0.0"
)
用goctl生成API Gateway代码
生成方法同上篇文章,自行查看。但是此处要基于admin.api文件去生成代码,如果基于redis.api生成,则生成的代码只有redis.api定义的接口代码,其他api文件定义的接口代码不被生成。
修改API Gateway代码调用rpc服务
redisaddlogic.go
修改api/internal/logic/redis/test/redisaddlogic.go
里的RedisAdd
方法,如下:
func (l *RedisAddLogic) RedisAdd(req *types.ApiRedisReq) (resp *types.ApiRedisResp, err error) {
addRes, err := l.svcCtx.Sys.RedisAdd(l.ctx, &sysclient.RedisReq{
Name: req.Name,
NickName: req.NickName,
Password: req.Password,
Email: req.Email,
})
if err != nil {
resJson, _ := json.Marshal(addRes)
logx.WithContext(l.ctx).Errorf("Redis新增数据测试:操作失败,请求参数param = %s,异常信息errMsg = %s", resJson, err.Error())
return nil, rpcerror.New(err)
}
return &types.ApiRedisResp{
Code: 200,
Message: "操作成功",
Data: types.ApiRedisReq{
Name: addRes.Name,
NickName: addRes.NickName,
Password: addRes.Password,
Email: addRes.Email,
},
}, nil
}
redisdeletelogic.go
修改api/internal/logic/redis/test/redisdeletelogic.go
里的RedisDelete
方法,如下:
func (l *RedisDeleteLogic) RedisDelete(req *types.ApiRedisReq) (resp *types.ApiRedisResp, err error) {
l.svcCtx.Sys.RedisDelete(l.ctx, &sysclient.RedisReq{})
return &types.ApiRedisResp{
Code: 200,
Message: "操作成功",
Data: types.ApiRedisReq{},
}, nil
}
redisupdatelogic.go
修改api/internal/logic/redis/test/redisupdatelogic.go
里的RedisUpdate
方法,如下:
func (l *RedisUpdateLogic) RedisUpdate(req *types.ApiRedisReq) (resp *types.ApiRedisResp, err error) {
updateRes, err := l.svcCtx.Sys.RedisUpdate(l.ctx, &sysclient.RedisReq{
Name: req.Name,
NickName: req.NickName,
Password: req.Password,
Email: req.Email,
})
if err != nil {
resJson, _ := json.Marshal(updateRes)
logx.WithContext(l.ctx).Errorf("Redis更新数据测试:操作失败,请求参数param = %s,异常信息errMsg = %s", resJson, err.Error())
return nil, rpcerror.New(err)
}
return &types.ApiRedisResp{
Code: 200,
Message: "操作成功",
Data: types.ApiRedisReq{
Name: updateRes.Name,
NickName: updateRes.NickName,
Password: updateRes.Password,
Email: updateRes.Email,
},
}, nil
}
redisgetlogic.go
修改api/internal/logic/redis/test/redisgetlogic.go
里的RedisGet
方法,如下:
func (l *RedisGetLogic) RedisGet(req *types.ApiRedisGetReq) (resp *types.ApiRedisResp, err error) {
param := &sysclient.RedisReq{}
copier.Copy(param, req)
getRes, err := l.svcCtx.Sys.RedisGet(l.ctx, param)
if err != nil {
resJson, _ := json.Marshal(getRes)
logx.WithContext(l.ctx).Errorf("获取数据测试:操作失败,请求参数param = %s,异常信息errMsg = %s", resJson, err.Error())
return nil, rpcerror.New(err)
}
return &types.ApiRedisResp{
Code: 200,
Message: "操作成功",
Data: types.ApiRedisReq{
Name: getRes.Name,
NickName: getRes.NickName,
Password: getRes.Password,
Email: getRes.Email,
},
}, nil
}
修改rpc代码调用crud代码
redisaddlogic.go
- 修改
rpc/sys/internal/logic/redisaddlogic.go
,如下内容:
// redis增删改查
func (l *RedisAddLogic) RedisAdd(in *sysclient.RedisReq) (*sysclient.RedisResp, error) {
if in.Name == "" {
return nil, errors.New("账号不能为空")
}
if in.NickName == "" {
return nil, errors.New("姓名不能为空")
}
if in.Email == "" {
return nil, errors.New("邮箱不能为空")
}
// 将结构体转换为 JSON 字符串
jsonString, err := json.Marshal(in)
if err != nil {
logx.WithContext(l.ctx).Errorf("Redis新增数据测试:数据转换json出错,异常信息errMsg = %s", err.Error())
return nil, errors.New("数据转换异常")
}
// 添加数据到Redis
var key = "songfayuan"
addErr := l.svcCtx.RedisClient.Set(key, string(jsonString))
if addErr != nil {
return nil, errors.New("存储Redis异常")
}
// 查询Redis的数据
getData, err := l.svcCtx.RedisClient.Get(key)
// 将字符串数据解码为 RedisResp 结构体
var redisResp sysclient.RedisResp
err = json.Unmarshal([]byte(getData), &redisResp)
if err != nil {
logx.WithContext(l.ctx).Errorf("Redis新增数据测试:返回值封装异常,异常信息errMsg = %s", err.Error())
return nil, errors.New("返回值封装异常")
}
return &redisResp, nil
}
redisdeletelogic.go
- 修改
rpc/sys/internal/logic/redisdeletelogic.go
,如下内容:
func (l *RedisDeleteLogic) RedisDelete(in *sysclient.RedisReq) (*sysclient.RedisResp, error) {
var key = "songfayuan"
res, err := l.svcCtx.RedisClient.Del(key)
if err != nil {
return nil, errors.New("删除Redis异常")
}
logx.Infof("删除Redis数据结果:%s", res)
return &sysclient.RedisResp{}, nil
}
redisupdatelogic.go
- 修改
rpc/sys/internal/logic/redisupdatelogic.go
,如下内容:
func (l *RedisUpdateLogic) RedisUpdate(in *sysclient.RedisReq) (*sysclient.RedisResp, error) {
if in.Name == "" {
return nil, errors.New("账号不能为空")
}
if in.NickName == "" {
return nil, errors.New("姓名不能为空")
}
if in.Email == "" {
return nil, errors.New("邮箱不能为空")
}
// 将结构体数据转为json字符串
jsonString, err := json.Marshal(in)
if err != nil {
logx.WithContext(l.ctx).Errorf("Redis更新数据测试:数据转换json出错,异常信息errMsg = %s", err.Error())
return nil, errors.New("数据转换异常")
}
// 更新数据到Redis,这里的修改,就是设置新值即可
key := "songfayuan"
editRes := l.svcCtx.RedisClient.Set(key, string(jsonString))
if editRes != nil {
return nil, errors.New("修改Redis数据异常")
}
// 查询Redis的数据
getData, err := l.svcCtx.RedisClient.Get(key)
// 将字符串数据转换为结构体
var redisResp sysclient.RedisResp
err = json.Unmarshal([]byte(getData), &redisResp)
if err != nil {
logx.WithContext(l.ctx).Errorf("修改Redis数据测试:返回值封装异常,异常信息errMsg = %s", err.Error())
return nil, errors.New("返回值封装异常")
}
return &redisResp, nil
}
redisgetlogic.go
- 修改
rpc/sys/internal/logic/redisgetlogic.go
,如下内容:
func (l *RedisGetLogic) RedisGet(in *sysclient.RedisReq) (*sysclient.RedisResp, error) {
// 查询Redis的数据
getData, err := l.svcCtx.RedisClient.Get(in.Key)
// 将字符串数据解码为 RedisResp 结构体
var redisResp sysclient.RedisResp
err = json.Unmarshal([]byte(getData), &redisResp)
if err != nil {
logx.WithContext(l.ctx).Errorf("Redis新增数据测试:返回值封装异常,异常信息errMsg = %s", err.Error())
return nil, errors.New("返回值封装异常")
}
return &redisResp, nil
}
完整调用演示
最后,在根目录go-zero-demo执行下命令。
go mod tidy
运行rpc服务
运行方法同上篇文章,自行查看。
运行api
运行方法同上篇文章,自行查看。
api调用
以下调用采用curl进行,你也可以用postman调用。
新增接口
songfayuan@MacBook-Pro ~ curl -X POST -H "Content-Type: application/json" -d '{"name":"songfayuan","nickName":"宋发元","email":"1414@qq.com"}' localhost:8888/redis/test/redisAdd
{"code":200,"message":"操作成功","data":{"name":"songfayuan","nickName":"宋发元","password":"","email":"1414@qq.com"}}%
删除接口
songfayuan@MacBook-Pro ~ curl -X POST -H "Content-Type: application/json" -d '{"name":"songfayuan","nickName":"宋发元6666","email":"1414@qq.com"}' localhost:8888/redis/test/redisDelete
{"code":200,"message":"操作成功","data":{"name":"","nickName":"","password":"","email":""}}%
修改接口
songfayuan@MacBook-Pro ~ curl -X POST -H "Content-Type: application/json" -d '{"name":"songfayuan","nickName":"宋发元6666","email":"1414@qq.com"}' localhost:8888/redis/test/redisUpdate
{"code":200,"message":"操作成功","data":{"name":"songfayuan","nickName":"宋发元6666","password":"","email":"1414@qq.com"}}%
查询接口
songfayuan@MacBook-Pro ~ curl "localhost:8888/redis/test/redisGet?key=songfayuan"
{"code":200,"message":"操作成功","data":{"name":"songfayuan","nickName":"宋发元6666","password":"","email":"1414@qq.com"}}%