go-zero 实战(3)

news2025/1/11 15:48:32

引入 Redis

在之前的 user 微服务中引入 redis。

1. 修改 user/internal/config/config.go

package config

import (
	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/zrpc"
)

type Config struct {
	zrpc.RpcServerConf
	Mysql      MysqlConfig
	CacheRedis cache.CacheConf // redis config -- 加入这一行代码
}

type MysqlConfig struct {
	DataSource string
}

2. 修改 user/etc/user.yaml 文件

加入 redis的配置

CacheRedis:
  - Host: 127.0.0.1:6379
    Pass: thinker
    Type: node

3. 修改 user/database/sqlx.go 文件

修改这里,是为了在查询数据时候,利用redis做缓存。

import (
	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/core/stores/sqlc"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

// we use go-zero sqlx

type DBConn struct {
	Conn      sqlx.SqlConn    // mysql
	ConnCache sqlc.CachedConn // redis
}

func Connect(datasource string, conf cache.CacheConf) *DBConn {
	sqlConn := sqlx.NewMysql(datasource)
	d := &DBConn{
		Conn: sqlConn,
	}
	if conf != nil {
		cachedConn := sqlc.NewConn(sqlConn, conf)
		d.ConnCache = cachedConn
	}
	return d
}

4. 修改 /user/internal/svc/servicecontext.go 文件

package svc

import (
	"user/database"
	"user/internal/config"
	"user/internal/dao"
	"user/internal/repo"
)

type ServiceContext struct {
	Config   config.Config
	UserRepo repo.UserRepo
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config:   c,
		UserRepo: dao.NewUserDao(database.Connect(c.Mysql.DataSource, c.CacheRedis)),  // 增加了 redis的缓冲配置
	}
}

5. 在 user/internal/repo/user.go 中增加接口

package repo

import (
	"context"
	"user/internal/model"
)

type UserRepo interface {
	Save(ctx context.Context, user *model.User) error
	FindById(ctx context.Context, id int64) (user *model.User, err error)  //新增
}

6. 在 user/internal/dao/user.go 中实现接口

func (d *UserDao) FindById(ctx context.Context, id int64) (user *model.User, err error) {

	user = &model.User{}
	querySql := fmt.Sprintf("select * from %s where id = ?", user.TableName())
	userIdKey := fmt.Sprintf("%s%d", cacheUserIdPrefix, id)
	err = d.ConnCache.QueryRowCtx(ctx, user, userIdKey,
		func(ctx context.Context, conn sqlx.SqlConn, v any) error {
			return conn.QueryRowCtx(ctx, v, querySql, id)
		})
	return
}

7. 在 user/logic/userlogic.go 中实现 GetUser rpc

func (l *UserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
	// todo: add your logic here and delete this line

	id, err := strconv.ParseInt(in.Id, 10, 64)
	if err != nil {
		return nil, err
	}
	u, err := l.svcCtx.UserRepo.FindById(context.Background(), id)
	if err != nil {
		return nil, err
	}
	return &user.UserResponse{
		Id:     in.GetId(),
		Name:   u.Name,
		Gender: u.Gender,
	}, nil
}

User 微服务rpc接口增加缓存完成。

测试

1. 修改 userapi/internal/handler/routes.go 文件

增加如下路由代码

{
	Method: http.MethodGet,
	Path: "/user/get/:id",
	Handler: handler.GetUser,
},

2. 修改 userapi/internal/types/types.go 文件

增加一个 IdRequest 结构体,主要是为了处理上一步中的请求

type IdRequest struct {
	Id string `json:"name" path:"id"`
}

3. 修改 userapi/internal/handler/userhandler.go 文件,实现GetUser接口

文件中增加如下代码:

func (u *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {

	var req types.IdRequest
	if err := httpx.ParsePath(r, &req); err != nil {
		httpx.ErrorCtx(r.Context(), w, err)
		return
	}

	l := logic.NewUserLogic(r.Context(), u.svcCtx)
	resp, err := l.GetUser(&req)
	if err != nil {
		httpx.ErrorCtx(r.Context(), w, err)
	} else {
		httpx.OkJsonCtx(r.Context(), w, resp)
	}
}

4. 修改 userapi/internal/logic/userapilogic.go 文件

文件中增加 GetUser 方法

func (l *UserLogic) GetUser(t *types.IdRequest) (resp *types.Response, err error) {
	userResponse, err := l.svcCtx.UserRpc.GetUser(context.Background(), &user.IdRequest{
		Id: t.Id,
	})
	if err != nil {
		return nil, err
	}
	resp = &types.Response{
		Message: "success",
		Data:    userResponse,
	}
	return
}

该方法主要调用了 user微服务的 RPC GetUser接口 服务

5. 启动微服务开始测试

  1. 启动 user 服务
  2. 启动 user api 服务
  3. 测试截图
    在这里插入图片描述
    到此,引入 redis 缓存成功。

go-zero 中的 JWT 使用

jwt 在目前登录、鉴权等场景中引用非常广泛
jwt 是加密的字符串,需要一个密钥,并且可以通过设置过期时间来使 jwt 生成的 token 失效。

由于我们的 userapi 微服务是对外提供接口的,因此,我们在 userapi 中使用 jwt。

1. 修改 userapi/internal/config/config.go 文件

添加 Auth 结构体

package config

import (
	"github.com/zeromicro/go-zero/rest"
	"github.com/zeromicro/go-zero/zrpc"
)

type Config struct {
	rest.RestConf
	UserRpc zrpc.RpcClientConf
	Auth    struct {
		AccessSecret string
		AccessExpire int64
	}
}

2. 修改 userapi/etc/userapi-api.yaml 文件

在文件中,增加如下配置。

Auth:
  AccessSecret: "sdskewie@129120$%120&*!"
  AccessExpire: 604800

3. 修改 userapi/internal/handler/routers.go 文件

func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {

	handler := NewUserHandler(serverCtx)
	server.AddRoutes(
		[]rest.Route{
			{
				Method:  http.MethodPost,
				Path:    "/Register",
				Handler: handler.Register,
			},
			{
				Method:  http.MethodPost,
				Path:    "/Login",
				Handler: handler.Login,
			},
		},
	)

	server.AddRoutes(
		[]rest.Route{
			{
				Method: http.MethodGet,
				Path: "/user/get/:id",
				Handler: handler.GetUser,
			},
		},
		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),   // need jwt
	)
}

需要 jwt 认证的接口,就需要 rest.WithJwt(serverCtx.Config.Auth.AccessSecret), 这行go代码 。

4. 修改 userapi/internal/handler/userhandler.go 文件 ,实现 Login 接口

在该 文件 中,添加 Login 方法

func (u *UserHandler) Login(w http.ResponseWriter, r *http.Request) {
	var req types.LoginRequest
	if err := httpx.ParseJsonBody(r, &req); err != nil {
		httpx.ErrorCtx(r.Context(), w, err)
		return
	}

	l := logic.NewUserLogic(r.Context(), u.svcCtx)
	resp, err := l.Login(&req)
	if err != nil {
		httpx.ErrorCtx(r.Context(), w, err)
	} else {
		httpx.OkJsonCtx(r.Context(), w, resp)
	}
}

5. 修改 userapi/internal/login/userapilogin.go 文件

在该文件中,添加 login 方法,登录成功后生成 jwt

func (l *UserLogic) getToken(secretKey string, iat, seconds int64, userId int) (string, error) {

	claims := make(jwt.MapClaims)
	claims["exp"] = iat + seconds
	claims["iat"] = iat
	claims["userId"] = userId
	token := jwt.New(jwt.SigningMethodES256)
	token.Claims = claims
	return token.SignedString([]byte(secretKey))
}

func (l *UserLogic) Login(t *types.LoginRequest) (string, error) {

	userId := 100
	auth := l.svcCtx.Config.Auth
	return l.getToken(auth.AccessSecret, time.Now().Unix(), auth.AccessExpire, userId)
}

6. 启动 useapi微服务 测试

  1. 加入 jwt 后,再次测试 user/get/1接口,返回401
    在这里插入图片描述
  2. 先登录,拿到 jwt
    在这里插入图片描述
  3. 使用 jwt 访问 user/get/1 接口
    在这里插入图片描述
    jwt 测试成功。

github位置

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

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

相关文章

SAP PRD覆盖QAS 替代方案构想

随着时间的推移,SAP PRD的数据跟QAS的差异会越来越大,一般是定期PRD覆盖QAS。但是在没有BASIS的情况下,没有这块经验的情况下,也没有外部支持的情况下,贸然做这个事情也是有风险的,有没有替代方案&#xff…

【ArcGIS微课1000例】0112:沿线(面)按距离或百分比生成点

文章目录 一、沿线生成点工具介绍二、线状案例三、面状案例一、沿线生成点工具介绍 位置:工具箱→数据管理工具→采样→沿线生成点 摘要:沿线或面以固定间隔或百分比创建点要素。 用法:输入要素的属性将保留在输出要素类中。向输出要素类添加新字段 ORIG_FID,并设置为输…

地理信息系统(GIS)软件开发

地理信息系统(GIS)软件开发是一项复杂且系统性很强的工程,涉及空间数据的采集、管理、分析和展示。以下是一个典型的GIS软件开发流程,包括各个步骤的详细说明。北京木奇移动技术有限公司,专业的软件外包开发公司&#…

K8S二进制安装与部署

一、安装部署步骤 1.1 初始化配置 1.2 所有 node 节点部署docker引擎 1.3 准备cfssl证书生成工具 1.4 生成Etcd证书 1.5 部署 Master 组件 1.6 部署 Worker Node 组件 1.7 部署 CNI 网络组件-部署 flannel 1.8 部署 CoreDNS 1.9 master02 节点部署 1.10 负载均衡部署…

dll文件是什么?电脑丢失某个dll文件有什么解决办法

Dll文件是什么?这个文件在电脑中是什么样的地位?如果电脑提示丢失了某个dll文件那么有什么办的解决这个问题呢?如何将丢失的dll文件进行修复呢?今天这篇文章将按就来教大家几种修复丢失dll文件问题的方法。 DLL 文件,全…

【永洪BI】超链接

1. 概述 1.1 功能简介 超链接,是将不同内容进行连接的元素,可以在表、图表、文本等组件上设置超链接,在预览时可以查看超链接效果。 产品内的超链接包括:链接到报告、链接到指定网址、导出、刷新、数据。 1.2 应用场景 想要从…

【Python】 如何使用逗号作为千位分隔符打印数字

基本原理 在Python中,打印数字时自动添加千位分隔符可以提高数字的可读性,尤其是在处理大数字时。Python提供了多种方法来实现这一功能,包括使用内置的format()函数、f-string(格式化字符串字面量)以及locale模块。 …

AI绘图副业创收,热门擦边变现赛道怎么玩?网友:瑟瑟才是人类前进的动力!

大家好,我是设计师阿威 今天给大家介绍一个用 AI 搞擦边的变现赛道 而且可以说是0 成本变现的 现在真的越来越多的人都想 0 成本变现,那么 0 成本到底能不能变现,变现的上下限又是多少? 今天这个案例就可以很好的进行说明 可以…

K8S认证|CKA题库+答案| 5. 创建 Ingress

5 . 创建 Ingress 您必须在以下Cluster/Node上完成此考题: Cluster Master node Worker node k8s master …

python从0开始学习(九)

前言 上一篇文章我们介绍了python中的序列类型和元组类型,本篇文章将接着往下将。 1、字典类型 字典类型是根据一个信息查找另一个信息的方式所构成的“键值对”,它表示索引用的键和对应的值构成的成对关系。它是一个可变数据类型,也就是说它…

Cython学习笔记和例程

Chapter2 :Compiling and Running Cython Code 编译运行Cython代码有好几种方式,没有必要全部掌握,可以根据需要选择合适的方式。这里例举了3种常见方式,基本也够用了。一般方法3创建setup.py是最基础的,自由度也最高…

java+Angular+Nginx+原生HTML+JS+CSS+Jquery融合B/S版电子病历系统云HIS系统源码

javaAngularNginx原生HTMLJSCSSJquery融合B/S版电子病历系统云HIS系统源码 Java版云HIS系统融合电子病历系统,是医学专用软件。医院通过电子病历以电子化方式记录患者就诊的信息,包括:首页、病程记录、检查检验结果、医嘱、手术记录、护理记录…

新手第一次做抖店,应该注意什么?知道这些技巧让你更快拿到结果

大家好,我是电商花花。 新手第一次刚开始接触抖音小店,都会担心自己做不好,操作不到位的想法,怕自己做店长时间不出单。 其实做店担心不出单是很正常的,但是只要我们掌握正确的做店方法和技巧也能很快就做好抖音小店…

文件包含漏洞--pikachu靶场

目录 文件包含 文件包含函数 文件包含漏洞原理 文件包含的分类 LFI-本地文件包含 RFI-远程文件包含 基于pikachu靶场练习 本地文件包含 远程文件包含 防御 文件包含 文件包含是程序员将需要重复调用的函数写入一个文件,对该文件包含时的操作,如…

从容应对亿级QPS访问,Redis还缺少什么?no.29

众所周知,Redis 在线上实际运行时,面对海量数据、高并发访问,会遇到不少问题,需要进行针对性扩展及优化。本课时,我会结合微博在使用 Redis 中遇到的问题,来分析如何在生产环境下对 Redis 进行扩展改造&…

基于yolov8+flask搭建一个web版本的网页模型预测系统

测试环境: anaconda3python3.8 torch1.9.0cu111 ultralytics8.2.2 首先我们将训练好的权重放在weights目录下面 并将名字改成yolov8n.pt,如果不想改可以在代码app.py都把路径改过来即可。然后我们打开 python app.py之后看到 我们点击选择文件支持图…

K8s 二进制部署---下篇(多master节点 负载均衡 高可用)

一 master02 节点部署 master01192.168.11.5kube-apiserver,kube-controller-manager,kube-scheduler,etcdmaster02192.168.11.12kube-apiserver,kube-controller-manager,kube-scheduler,etcdnode01192.1…

Matomo用户行为分析 - 功能篇

在上一篇文章《Matomo用户行为分析 - 安装篇》中我们介绍了分析工具的作用、Saas平台和开源项目的优缺点、Matomo的部署和基本安装使用,让我们对分析工具有个大致的了解,那么本章我们将对Matomo的常见功能进行详细介绍。 常见功能 平台的基本分析能力很…

PDF Reader Pro for Mac 直装激活版:专业PDF阅读编辑软件

在数字化时代,PDF文件已成为我们日常工作和学习中不可或缺的一部分。然而,如何高效、便捷地阅读、编辑和管理这些PDF文件,却一直是许多人面临的难题。现在,有了PDF Reader Pro for Mac,这些难题将迎刃而解。 PDF Reade…

SashulinMessageBroker:在消息流中调用C++ DLL

一、背景 在现实应用中,算法、核心逻辑为了追求快速高效的运行速度,很多人都采用C来编写,并打包成动态库供外部使用。SMB针对这种应用场景,提供了DLL组件,实现在消息流中对DLL的动态调用。下实例讲解如何实现DLL as S…