go-zero 实战(3)

引入 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位置

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营第36期DAY35

DAY35 122买卖股票的最佳时机ii 很巧妙&#xff0c;也很难想到&#xff1a;计算每天的利润&#xff08;今天卖出&#xff0c;昨天买入的利润&#xff09;&#xff0c;只取正数相加。 class Solution {public: int maxProfit(vector<int>& prices) { int…

【机器学习300问】93、到底什么是优化器optimizer?

本文是对之前我写的梯度下降优化算法相关内容进行一次简要总结。在学习PyTorch框架的过程中&#xff0c;会遇到“优化器”&#xff08;optimizer&#xff09;这个概念。我想用通俗易懂的方式&#xff0c;说说优化器到底是个什么东西&#xff0c;并在此基础上&#xff0c;将前文…

Qt代码初识

文章目录 Qt代码初识1. Qt Hello World 程序1.1 使⽤ "按钮" 实现1.1.1 纯代码⽅式实现1.1.2 可视化操作实现 1.2 使⽤ "标签" 实现1.2.1 纯代码⽅式实现1.2.2 可视化操作实现 2. 项⽬⽂件解析2.1 .pro ⽂件解析2.2 widget.h ⽂件解析2.3 main.cpp ⽂件解析…

SwanLab入门深度学习:BERT IMDB文本情感分类

基于BERT模型的IMDB电影评论情感分类&#xff0c;是NLP经典的Hello World任务之一。 这篇文章我将带大家使用SwanLab、transformers、datasets三个开源工具&#xff0c;完成从数据集准备、代码编写、可视化训练的全过程。 观察了一下&#xff0c;中文互联网上似乎很少有能直接…

Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645)

漏洞复现环境搭建请参考 http://t.csdnimg.cn/MxmId 漏洞版本 Apache Log4j 2.8.2之前的2.x版本 漏洞验证 &#xff08;1&#xff09;开放端口4712 漏洞利用 &#xff08;1&#xff09;ysoserial工具获取 wget https://github.com/frohoff/ysoserial/releases/download/v0…

强化学习算法

从上图看出&#xff0c;强化学习可以分成价值/策略、随机策略/确定策略、在线策略/离线策略、蒙特卡洛/时间差分这四个维度。这里分析了基础算法中除了在线策略/离线策略以外的其他维度。 &#xff08;一&#xff09;基础知识 一、基础概念 重点概念&#xff1a;状态S、动作A、…

浏览器自动化~插件推荐Automa

引言 作为一款现代浏览器&#xff0c;得自动化吧&#xff0c;自主完成那些日复一日的重复性任务&#xff0c;开启音乐啥的不在话下~。而你则可以专注于其他更有意义的事情&#xff0c;如享受音乐带来的愉悦。但如果你对编写脚本一窍不通&#xff0c;又该如何实现这一愿景呢&am…

华为机考入门python3--(28)牛客28-素数伴侣

分类&#xff1a;质数、素数、贪心算法、矩阵 知识点&#xff1a; 素数里除了2&#xff0c;都是奇数 奇奇偶&#xff0c;偶&#xff0b;偶偶 对矩阵求和 sum(map(sum, matrix)) 查找元素 3 在列表中的索引 my_list.index(3) 题目来自【牛客】 质数又称素数&#xff0c;是指…

一种综合评价及决策方法:层次分析法AHP

大家好&#xff0c;层次分析法(Analytic Hierarchy Process&#xff0c;AHP)是一种多准则决策方法&#xff0c;它帮助决策者处理复杂的决策问题&#xff0c;将其分解成层次结构&#xff0c;然后通过两两比较来确定各个层次的因素之间的相对重要性。这种分析方式允许决策者对问题…

【vue与iframe通讯】

vue 与 iframe 通讯 发送数据vue 向 iframe 发送数据iframe 向 vue 发送数据接收信息( vue & iframe 通用) 实现相互通讯通讯流程图实现代码vue 页面iframe页面iframe内部重定向访问地址,更新vue路由 代码下载 前言&#xff1a;vue嵌套iframe实现步骤 发送数据 vue 向 if…

回溯算法05(leetcode491/46/47)

参考资料&#xff1a; https://programmercarl.com/0491.%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97.html 491. 非递减子序列 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素…

微软开发者大会:编程进入自然语言时代、“AI员工”闪亮登场

当地时间周二&#xff0c;美国科技公司微软召开年度Build开发者大会。在CEO纳德拉的带领下&#xff0c;微软各个产品团队再一次展现出惊人的执行力&#xff0c;在发布会上又拿出了接近50个新产品或功能更新。 整场发布会持续了接近两个小时&#xff0c;在这里挑选了一些投资者…

知识表示概述

文章目录 知识表示研究现状技术发展趋势 知识表示 知识是人类在认识和改造客观世界的过程中总结出的客观事实、概念、定理和公理的集合。知识具有不同的分类方式&#xff0c;例如按照知识的作用范围可分为常识性知识与领域性知识。知识表示是将现实世界中存在的知识转换成计算机…

Linux进程的地址空间

Linux进程的地址空间 1. 前言 在编写程序语言的代码时&#xff0c;打印输出一个变量的地址时&#xff0c;这个地址在内存中是以什么形式存在的&#xff1f;一个地址可以存储两个不同的值吗&#xff1f; 运行以下代码&#xff1a; #include <stdio.h> #include <un…

C#-根据日志等级进行日志的过滤输出

文章速览 概要具体实施创建Log系统动态修改日志等级 坚持记录实属不易&#xff0c;希望友善多金的码友能够随手点一个赞。 共同创建氛围更加良好的开发者社区&#xff01; 谢谢~ 概要 方便后期对软件进行维护&#xff0c;需要在一些关键处添加log日志输出&#xff0c;但时间长…

vulhub——ActiveMQ漏洞

文章目录 一、CVE-2015-5254(反序列化漏洞)二、CVE-2016-3088&#xff08;任意文件写入漏洞&#xff09;2.1 漏洞原理2.2 写入webshell2.3 写入crontab 三、CVE-2022-41678&#xff08;远程代码执行漏洞&#xff09;方法一方法2 四、CVE-2023-46604&#xff08;反序列化命令执行…

HTML+CSS+JS 扩散登录表单动画

效果演示 Code <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,us…

MAIA:多模态自动化可解释智能体的突破

随着人工智能技术的飞速发展&#xff0c;深度学习模型在图像识别、自然语言处理等领域取得了显著成就。然而&#xff0c;这些模型的“黑箱”特性使得其决策过程难以理解&#xff0c;限制了它们的应用范围和可靠性。为了解决这一问题&#xff0c;研究者们提出了多种模型可解释性…

【机器学习】—机器学习和NLP预训练模型探索之旅

目录 一.预训练模型的基本概念 1.BERT模型 2 .GPT模型 二、预训练模型的应用 1.文本分类 使用BERT进行文本分类 2. 问答系统 使用BERT进行问答 三、预训练模型的优化 1.模型压缩 1.1 剪枝 权重剪枝 2.模型量化 2.1 定点量化 使用PyTorch进行定点量化 3. 知识蒸馏…

[emailprotected](7)父子通信,传递元素内容

目录 1&#xff0c;children 属性2&#xff0c;多个属性 普通对象等&#xff0c;可以通过变量直接传递&#xff0c;那类似 vue 中的 slot 插槽&#xff0c;如何传递元素内容&#xff1f; 1&#xff0c;children 属性 实际上&#xff0c;写在自定义组件标签的内部代码&#xf…