go-zero整合单机版Redis并实现增删改查

go-zero整合单机版Redis并实现增删改查

本教程基于go-zero微服务入门教程,项目工程结构同上一个教程。

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:6379Type: nodePass: "123456789"Tls: false

config.go

config.go文件中新增RedisConf配置信息,如下:

	RedisConf struct {Host stringType string `json:",default=node,options=node|cluster"`Pass string `json:",optional"`Tls  bool   `json:",optional"`}

servicecontext.go

servicecontext.go文件新增Redis配置信息,完整代码如下:

package svcimport ("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.ConfigRedisClient *redis.RedisUserModel 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/testprefix : /redis/test
)service admin-api{@doc(summary : "Redis新增数据")@handler RedisAddpost /redisAdd(ApiRedisReq)returns(ApiRedisResp)@doc(summary : "Redis删除数据")@handler RedisDeletepost /redisDelete(ApiRedisReq)returns(ApiRedisResp)@doc(summary : "Redis修改数据")@handler RedisUpdatepost /redisUpdate(ApiRedisReq)returns(ApiRedisResp)@doc(summary : "Redis查询数据")@handler RedisGetget /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("数据转换异常")}// 添加数据到Redisvar 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.RedisResperr = 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.RedisResperr = 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.RedisResperr = 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"}}%

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/797879.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle容器镜像制作

对于 Oracle 数据库的容器镜像制作,oracle 官方提供了 Dockerfile 文件和制作脚本的(https://github.com/oracle/docker-images)。这里以 12c 为例看看怎么使用。 下载官方提供的 Dockerfile 文件和制作脚本 $ git clone https://github.com/…

笛卡尔树[天梯赛二叉树专项训练]

文章目录 题目描述思路AC代码 题目描述 输入样例1 6 8 27 5 1 9 40 -1 -1 10 20 0 3 12 21 -1 4 15 22 -1 -1 5 35 -1 -1 输出样例1 YES 输入样例2 6 8 27 5 1 9 40 -1 -1 10 20 0 3 12 11 -1 4 15 22 -1 -1 50 35 -1 -1 输出样例2 NO思路 见注释 AC代码 #include <bits/st…

【重学C语言】五、分支结构

【重学C语言】五、分支结构 三种结构分支结构if 语句示例 1&#xff1a;基本的 if 语句 if...else 语句示例 2&#xff1a;if...else 语句 嵌套 if示例 3&#xff1a;嵌套的 if 语句 if 语句与逻辑运算符示例 4&#xff1a;使用逻辑与&#xff08;&&&#xff09;示例 5…

搭建python编译环境

目录 1.安装依赖包 2.安装失败进行换源 3. 更新系统 通过C 语言调用 Python 代码&#xff0c;需要先安装 libpython3 的 dev 依赖库&#xff08;不同的 ubuntu 版本下&#xff0c; python 版本 可能会有差异&#xff0c; 比如ubuntu 22.04 里是 libpython3.10-dev &#xff09…

2024/4/1—力扣—最小高度树

代码实现&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ struct TreeNode* buildTree(int *nums, int l, int r) {if (l > r) {return NULL; // 递归出口}struct…

题解:CF1941C(C. Rudolf and the Ugly String)

题解&#xff1a;CF1941C&#xff08;C. Rudolf and the Ugly String&#xff09; 题目翻译&#xff1a;给定一个字符串&#xff0c;请你求出最少需要删除几个字符才能使得该字符串内不存在 map 和 pie。 我们可以先在该字符串内找到所有的子串 mapie&#xff0c;并删除中间的…

[StartingPoint][Tier1]Sequel

Task 1 During our scan, which port do we find serving MySQL? (在扫描过程中&#xff0c;我们发现哪个端口为 MySQL 提供服务&#xff1f;) 3306 Task 2 What community-developed MySQL version is the target running? (目标正在运行哪个社区开发的 MySQL 版本&…

Python实现【坦克大战】+源码分享

写在前面&#xff1a; 坦克大战&#xff0c;这款经典的电子游戏&#xff0c;无疑是许多80后和90后心中不可磨灭的童年记忆。它不仅仅是一款游戏&#xff0c;更是那个时代科技娱乐方式的缩影&#xff0c;见证了电子游戏行业的起步与发展。 在那个电脑和网络尚未完全普及的年代…

c语言实现2048小游戏

#include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h>int best 0 ;// 定义2048游戏的结构体 typedef struct { int martix[16]; // 当前4*4矩阵的数字 int martixPrior[16]; // 上一步的4*4矩阵的数字 int emptyIndex[16…

LeetCode 1017. 负二进制转换

解题思路 相关代码 class Solution {public String baseNeg2(int n) {if(n0) return "0";String s"";while(n!0)if(Math.abs(n)%20){nn/(-2);ss0;}else{ss1; n (n-1)/(-2);}String t reverse(s);return t;}public String reverse(String s){Str…

嵌入式培训4-7

今日作业&#xff1a; 1、有一个隧道&#xff0c;全长5公里&#xff0c;有2列火车&#xff0c;全长200米&#xff0c; 火车A时速 100公里每小时 火车B时速 50公里每小时 现在要求模拟火车反复通过隧道的场景(不可能2列火车都在隧道内运行) 2、有一个隧道&#xff0c;全长5公里&…

前端三剑客 —— JavaScript (第一节)

目录 回顾内容 1.弹性布局 2.网格布局 JavaScript 概述 发展 浏览器 什么是Javascript JavaScript 能干什么 JavaScript需要的环境 JavaScript初体验 基本数据 JS书写方式 行内JS 页面JS 外部JS 1&#xff09;创建外部JS文件 2&#xff09;编写页面 对话框 警…

达梦数据库的快速加列参数ALTER_TABLE_OPT使用

达梦数据库的表数据量较大时&#xff0c;在线直接修改表结构新增字段会很慢 现象&#xff1a;开发人员测试环境增加一个字段耗时7分钟&#xff0c;数据量仅仅2千万&#xff1b; 为了解决这一问题&#xff0c;达梦数据库提供一个动态会话级参数&#xff1a;ALTER_TABLE_OPT&am…

vue中三种watcher

在分析之前我们先来看看&#xff0c;vue中都有哪些Watcher种类呢&#xff1f;以及分别在什么时候创建呢&#xff1f;从vue源码里面看&#xff0c;Watcher是一个公共类&#xff0c;在不同的地方去初始化Watcher就代表不同类的Watcher。主要分为以下三类&#xff1a; computed w…

【Threejs进阶教程-效果篇】1.Threejs文字与css2d/css3d技术

Threejs文字与css2d/css3d技术 学习ThreeJS的捷径学习之前先搞清楚自己想要什么样的效果贴图文字准备一张带文字的png贴图使用sprite来进行贴图实现2D始终面朝相机的文字使用planeGeometry来贴图实现3D文字使用planeGeometry来贴图实现伪3D文字动态贴图文字html2Canvas 文字几何…

【算法】寻找数组中心下标 - 双指针/求总和

题目 给定一个非空数组&#xff0c;找到一个元素&#xff0c;该元素左侧元素和等于其右侧元素和&#xff0c;返回该元素下标。 如果没有则返回-1&#xff0c;有多个则返回最左侧一个。 原理 1、双指针 定义两个变量&#xff0c;一个为从左侧累加的和 leftSum 0&#xff0c…

操作系统复习

虚拟内存 内存(memory)资源永远都是稀缺的&#xff0c;当越来越多的进程需要越来越来内存时&#xff0c;某些进程会因为得不到内存而无法运行&#xff1b; 虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存&#xff0c;而实际上&#xff0…

C++ P1271 【深基9.例1】选举学生会

文章目录 一、题目描述【深基9.例1】选举学生会题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 二、参考代码 一、题目描述 【深基9.例1】选举学生会 题目描述 学校正在选举学生会成员&#xff0c;有 n n n&#xff08; n ≤ 999 n\le 999 n≤999&#xff09;名候…

HTML基础知识详解(下)(如果想知道html的全部基础知识点,那么只看这一篇就足够了!)

前言&#xff1a;在上一篇文章中&#xff0c;我们已经学习完了超链接标签、列表标签和表格标签&#xff0c;但是我们还有一些标签没有学习&#xff0c;在这篇文章中&#xff0c;我们将学习剩余的标签。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页…

java的基本数据类型

在Java编程语言中&#xff0c;基本数据类型是构成Java程序的基础元素&#xff0c;它们用于存储简单值。Java的基本数据类型可以分为两大类&#xff1a;原始类型&#xff08;Primitive Types&#xff09;和引用类型&#xff08;Reference Types&#xff09;。原始类型包括整型、…