【golang】动态生成微信小程序二维码实战下:golang 生成 小程序二维码图片 并通过s3协议上传到对象存储桶 | 腾讯云 cos

项目背景

在自研的系统,需要实现类似草料二维码的功能
将我们自己的小程序,通过代码生成相想要的小程序二维码

代码已经上传到 Github 需要的朋友可以自取
https://github.com/ctra-wang/wechat-mini-qrcode

一、生成Qrcode并提交到对象存储

通过源生API实现对小程序二维码的生成

1、s3上传多云对象存储桶

感谢suyuan32同学对代码的开源: https://github.com/suyuan32/simple-admin-file

Your Image Description

让我们一起支持群主维护simple-admin 社群吧!!!
不能加入星球的朋友记得来点个Star!!
https://github.com/suyuan32/simple-admin-core

2、源码

下面为示意代码,

需要的package如下:

  • github.com/silenceper/wechat/v2
  • github.com/aws/aws-sdk-go/aws
func NewVerifyRaceSignTeamLogic(ctx context.Context, svcCtx *svc.ServiceContext) *VerifyRaceSignTeamLogic {
	return &VerifyRaceSignTeamLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx}
}

func (l *VerifyRaceSignTeamLogic) VerifyRaceSignTeam(req *types.RaceSignTeamInfo) (resp *types.BaseMsgResp, err error) {
	deptId := ctxdata.GetIntParamFromJwt(l.ctx, "deptId")

	// 根据具体赛事id查询
	raceSignTeam, err := l.svcCtx.CtraGoRaceRpc.GetRaceSignTeamById(l.ctx, &ctragorace.IDReq{
		Id: *req.Id,
	})
	if err != nil {
		return nil, err
	}

	flag := false
	if int(deptId) != constant.ORG_TYPE_ADMIN {
		// 根据 deptid 换 orgInfo
		orgRes, err := l.svcCtx.CtraGoRaceRpc.GetRaceOrgInfoList(l.ctx, &ctragorace.RaceOrgInfoListReq{
			DeptId: &deptId,
		})
		if err != nil {
			return nil, err
		}

		if orgRes.Total > 0 {
			// 非管理员,查看该权限下所有赛事
			raceList, err := l.svcCtx.CtraGoRaceRpc.GetRaceInfoList(l.ctx, &ctragorace.RaceInfoListReq{
				RaceOrgInfoId: *orgRes.Data[0].Id,
			})
			if err != nil {
				return nil, err
			}
			if raceList.Total > 0 {
				for _, datum := range raceList.Data {
					if *datum.Id == *raceSignTeam.RaceInfoId {
						flag = true
						break
					}
				}
			}
		}
	} else {
		flag = true
	}

	if !flag {
		return nil, errorx.NewCodeAbortedError("该用户暂无权限进行审核!")
	}

	// -----------------------	生成 微信小程序二维码  使用:github.com/silenceper/wechat/v2		-----------------------
	// 初始化 Wechat 实例
	wc := wechat.NewWechat()
	//这里本地内存保存access_token,也可选择redis,memcache或者自定cache
	memory := cache.NewMemory()
	cfg := &miniConfig.Config{
		AppID:     constant.MINI_APP_LATEST_ID,
		AppSecret: constant.MINI_APP_LATEST_SECRET,
		Cache:     memory,
	}
	mini := wc.GetMiniProgram(cfg)
	qr := mini.GetQRCode()
	qrRes, err := qr.CreateWXAQRCode(qrcode.QRCoder{
		Page: l.svcCtx.Config.QrCode.Page,
		Path: fmt.Sprintf(l.svcCtx.Config.QrCode.Path, raceSignTeam.RaceInfoId),
		//CheckPath:  nil,
		Width: l.svcCtx.Config.QrCode.Width,
		//Scene: "pathName=/race/pages/group&id=58",
		//AutoColor:  false,
		//LineColor:  nil,
		//IsHyaline:  false,
		//EnvVersion: "",
	})
	if err != nil {
		return nil, errorx.NewCodeAbortedError("通过微信小程序API生成小程序二维码失败!")

	}
	// -----------------------	将 微信小程序二维码 生成为本地文件用于存入对象存储cos   -----------------------
	// 拼接文件路径
	fileDir := fmt.Sprintf("/upload/race-info/%s/", time.Now().Format("2006_01"))
	newFileName := generatoruuid.GetUuid() + ".jpg"

	// 获取当前 Pod 的工作目录
	pwd, err := os.Getwd()
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("os创建文件夹失败!")
	}
	// 创建文件路径
	err = os.MkdirAll(pwd+fileDir, 0755)
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("os创建文件夹失败!")
	}
	// 复制文件(空文件)到该路径
	qrcodeFile, err := os.Create(pwd + fileDir + newFileName)
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("os创建文件失败!")
	}
	// 将通过API生成小程序二维码->写入到文件中
	_, err = qrcodeFile.Write(qrRes)
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("os创建文件失败!")
	}
	defer qrcodeFile.Close()
	// 删除文件
	defer os.RemoveAll(pwd + fileDir + newFileName)

	// -----------------------	推送文件到tencent对象存储cos   -----------------------
	// 创建s3实例
	sess := session.Must(session.NewSession(
		&aws.Config{
			Region:      aws.String(l.svcCtx.Config.QrCode.Region),
			Credentials: credentials.NewStaticCredentials(l.svcCtx.Config.QrCode.SecretId, l.svcCtx.Config.QrCode.SecretKey, ""),
			Endpoint:    aws.String(l.svcCtx.Config.QrCode.EndPoint),
		},
	))
	CloudStorage := s3.New(sess)

	qrFile, err := os.Open(pwd + fileDir + newFileName)
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("读取新创建qrcode失败!")
	}
	defer qrFile.Close()

	// 处理存放cos的路径
	// - C 端
	// - 赛事报名:race-sign/赛事id/
	// - 赛事信息:race-info/赛事id/ ✅
	// - 用户里程碑:member-moment/用户id/
	// - 用户个人信息: member-info/用户id/
	// - B 端 (不在这里使用)
	// - banner:banner/
	relativeSrc := fmt.Sprintf("%s/%s/%d/%s",
		l.svcCtx.Config.QrCode.Folder,
		"race-info",
		*raceSignTeam.RaceInfoId,
		newFileName)
	//  发送到tencent-cos
	_, err = CloudStorage.PutObjectWithContext(context.Background(), &s3.PutObjectInput{
		Bucket: aws.String(l.svcCtx.Config.QrCode.BucketName),
		Key:    aws.String(relativeSrc),
		Body:   qrFile,
	})
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("文件上传到tencent-cos失败!")
	}

	fmt.Println("QR code upload tencent cos successfully!")

	// -----------------------	更新数据库表 race_sign_team  -----------------------
	// 更新团报状态
	res1, err := l.svcCtx.CtraGoRaceRpc.UpdateRaceSignTeam(l.ctx,
		&ctragorace.RaceSignTeamInfo{
			Id:         req.Id,
			IsValidate: pointy.GetPointer(int32(constant.SIGN_TEAM_IS_VALIDATE_ACCESS)),
			TeamQrcode: &relativeSrc,
		})
	if err != nil {
		return nil, err
	}

	return &types.BaseMsgResp{Msg: res1.Msg}, nil

}

3、源码分析

3.1、拿到qrcode二进制

qrRes 为拿到的图片二进制

// -----------------------	生成 微信小程序二维码  使用:github.com/silenceper/wechat/v2		-----------------------
	// 初始化 Wechat 实例
	wc := wechat.NewWechat()
	//这里本地内存保存access_token,也可选择redis,memcache或者自定cache
	memory := cache.NewMemory()
	cfg := &miniConfig.Config{
		AppID:     constant.MINI_APP_LATEST_ID,
		AppSecret: constant.MINI_APP_LATEST_SECRET,
		Cache:     memory,
	}
	mini := wc.GetMiniProgram(cfg)
	qr := mini.GetQRCode()
	qrRes, err := qr.CreateWXAQRCode(qrcode.QRCoder{
		Page: l.svcCtx.Config.QrCode.Page,
		Path: fmt.Sprintf(l.svcCtx.Config.QrCode.Path, raceSignTeam.RaceInfoId),
		//CheckPath:  nil,
		Width: l.svcCtx.Config.QrCode.Width,
		//Scene: "pathName=/race/pages/group&id=58",
		//AutoColor:  false,
		//LineColor:  nil,
		//IsHyaline:  false,
		//EnvVersion: "",
	})
	if err != nil {
		return nil, errorx.NewCodeAbortedError("通过微信小程序API生成小程序二维码失败!")

	}

3.2、二维码存为本地文件

将 微信小程序二维码 生成为本地文件用于存入对象存储cos

// -----------------------	将 微信小程序二维码 生成为本地文件用于存入对象存储cos   -----------------------
	// 拼接文件路径
	fileDir := fmt.Sprintf("/upload/contracts/%s/", time.Now().Format("2006_01"))
	newFileName := generatoruuid.GetUuid() + ".jpg"

	// 获取当前 Pod 的工作目录
	pwd, err := os.Getwd()
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("os创建文件夹失败!")
	}
	// 创建文件路径
	err = os.MkdirAll(pwd+fileDir, 0755)
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("os创建文件夹失败!")
	}
	// 复制文件(空文件)到该路径
	qrcodeFile, err := os.Create(pwd + fileDir + newFileName)
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("os创建文件失败!")
	}
	// 将通过API生成小程序二维码->写入到文件中
	_, err = qrcodeFile.Write(qrRes)
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("os创建文件失败!")
	}
	defer qrcodeFile.Close()
	// 删除文件
	defer os.RemoveAll(pwd + fileDir + newFileName)

3.3、推送文件到tencent对象存储cos

通过s3协议上传到对象存储桶 | 腾讯云 cos
这里注意要将刚才保存的图片再次打开 os.Open()

// -----------------------	推送文件到tencent对象存储cos   -----------------------
	// 创建s3实例
	sess := session.Must(session.NewSession(
		&aws.Config{
			Region:      aws.String(l.svcCtx.Config.QrCode.Region),
			Credentials: credentials.NewStaticCredentials(l.svcCtx.Config.QrCode.SecretId, l.svcCtx.Config.QrCode.SecretKey, ""),
			Endpoint:    aws.String(l.svcCtx.Config.QrCode.EndPoint),
		},
	))
	CloudStorage := s3.New(sess)

	qrFile, err := os.Open(pwd + fileDir + newFileName)
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("读取新创建qrcode失败!")
	}
	defer qrFile.Close()

	// 处理存放cos的路径
	// - C 端
	// - 赛事报名:race-sign/赛事id/
	// - 赛事信息:race-info/赛事id/ ✅
	// - 用户里程碑:member-moment/用户id/
	// - 用户个人信息: member-info/用户id/
	// - B 端 (不在这里使用)
	// - banner:banner/
	relativeSrc := fmt.Sprintf("%s/%s/%d/%s",
		l.svcCtx.Config.QrCode.Folder,
		"race-info",
		*raceSignTeam.RaceInfoId,
		newFileName)
	//  发送到tencent-cos
	_, err = CloudStorage.PutObjectWithContext(context.Background(), &s3.PutObjectInput{
		Bucket: aws.String(l.svcCtx.Config.QrCode.BucketName),
		Key:    aws.String(relativeSrc),
		Body:   qrFile,
	})
	if err != nil {
		l.Logger.Errorf(err.Error())
		return nil, errorx.NewCodeAbortedError("文件上传到tencent-cos失败!")
	}

	fmt.Println("QR code upload tencent cos successfully!")

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

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

相关文章

前端:自制年历

详细思路可以看我的另一篇文章《前端:自制月历》,基本思路一致,只是元素布局略有差异 ①获取起始位startnew Date(moment().format(yyyy-01-01)).getDay() ②获取总的格子数numMath.ceil(365/7)*7,这里用365或者366计算结果都是一样的371 …

数据库中了勒索病毒怎么办?(数据库恢复的终极大招DUL)

数据库如何预防勒索病毒 接上文,如果数据库中了勒索病毒,并且备份也同样被攻陷,那该怎么办?以最为常见的Lockbit3.0为例,LockBit采用先进的加密算法,通常是对称密钥加密和非对称密钥加密的组合。这使得被感…

适合虚拟主持人活动的全身动作捕捉设备:VDSuit Full

在虚拟主持人领域,全身动作捕捉设备一直以其逼真的效果和生动的表现力备受瞩目。相比光学全身动作捕捉设备,惯性全身动作捕捉设备更适合应用在企业品牌虚拟主持人发布会、虚拟主持人直播等活动场合。 广州虚拟动力全身动作捕捉设备VDSuit Full&#xff0…

OSCP靶场--Nagoya

OSCP靶场–Nagoya 考点 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.214.21 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-02 08:52 EDT Nmap scan report for 192.168.214.21 Host is up (0.38s latency).…

colmap安装问题汇总

问题目录 问题0、没有root权限怎么安装colmap? 问题1、ERROR: SiftGPU not fully supported/Could not connect to any X display 问题2、Cannot specify include directories for imported target "freeimage::FreeImage". 问题3、could not find ZL4 问…

鸿蒙ArkUI开发学习:【渲染控制语法】

ArkUI开发框架是一套构建 HarmonyOS / OpenHarmony 应用界面的声明式UI开发框架,它支持程序使用 if/else 条件渲染, ForEach 循环渲染以及 LazyForEach 懒加载渲染。本节笔者介绍一下这三种渲染方式的使用。 if/else条件渲染 使用 if/else 进行条件渲染…

AI大模型的10大趋势预判!

大模型发展竞争愈发激烈。全球瞩目的文生视频Sora、谷歌Gemini 1.5、Meta的V-JEPA以及超越GPT4的Claude3相继发布。Open AI的GPT5也即将问世。奥特曼不仅自研芯片,还投资可控核聚变公司,以算力和能源为未来储备关键资源。 在算力紧平衡和数据资源荒的背…

俄罗斯留学有哪些世界一流的名校呢,柯桥留学俄语培训

有哪些世界一流的名校呢 ☢ 理工类院校 俄罗斯是科教大国,高等教育水平位于世界前列,拥有许多国际著名大学。众多世界知名大学拥有很多独具特色的优势专业,其中理工类大学得天独厚的专业性也是被世界所认可的。凭着其高水准的教育&#xff…

gitee和idea集成

1 集成插件 2 配置账号密码 3 直接将项目传到仓库 4直接从gitee下载项目

yolov5交互式界面 通用界面-yolo-pyqt-gui(通用界面制作+代码-V5.0-6.0版本)

"YOLOv5交互式界面 - 通用界面-YOLO-PyQt-GUI" 它为YOLOv5的目标检测模型提供了一个用户友好的图形化操作界面。该项目通常基于Python的PyQt库构建,用于封装YOLOv5的功能,并将其转化为可视化工具,使得非专业开发人员也能便捷地使用…

超越接口:探索Dubbo的泛化调用机制

欢迎来到我的博客,代码的世界里,每一行都是一个故事 超越接口:探索Dubbo的泛化调用机制 前言泛化调用的概念Dubbo 中泛化调用的工作原理泛化实现动态RPC泛化调用的高级用法参数和返回值处理异常处理和错误处理策略 controller实践 前言 在现…

为什么 MySQL 采用 B+ 树作为索引?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 「为什么 MySQL 采用 B 树作为索引?」这句话,是不是在面试时经常出现。 要解释这个问题,其实不单单要从数据结构的角度出发,还要考虑磁盘 I/O 操作次数&am…

C语言-函数指针-快速排序算法(书籍示例-入门)

概述 使用C语言,实现结构体多元素,排序算法(冒泡排序),这里使用示例:书籍示例讲解 函数简介 函数声明 void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)) 参…

一维差分数组

797. 差分 输入一个长度为 n 的整数序列。接下来输入 m 个操作,每个操作包含三个整数 l,r,c,表示将序列中 [l,r] 之间的每个数加上 c。 请你输出进行完所有操作后的序列。 输入格式 第一行包含两个整数 n和 m 第二行包含 n个整数,表示整数序…

Redis Stack 安装部署

参考:Run Redis Stack on Docker | Redis Redis-stack 初体验_redis stack-CSDN博客 【docker】运行redis_docker run redis-stack-server requirepass-CSDN博客 Redis Stack 是一组软件套件,它主要由三部分组成。 一个是 Redis Stack Server&#x…

【HTB】 OpenSource

OpenSource 靶机地址:https://app.hackthebox.com/machines/471 信息收集 ┌──(root㉿kali)-[~/Desktop] └─# nmap -Pn -sC -sV -p- 10.129.212.208 --min-rate5000 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-08 16:01 CST Nmap scan report f…

Nginx服务 重写功能与反向代理

六、重写功能 rewrite Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库,rewrite是nginx服务器的重要功能之一,用于实现URL的…

Unity 世界坐标、屏幕坐标、UGUI 坐标 相互转换

Unity 世界坐标、屏幕坐标、UGUI 坐标 相互转换坐标转换是游戏开发过程中必不可少的环节 看下图 世界坐标、屏幕坐标、UI 坐标 三种坐标系的转换过程,此文章中的 UI 坐标特指 UGUI 坐标 从上图可以看到,世界坐标 和 UI 坐标 需要通过 屏幕坐标作为中间转…

MemberPress配置和使用会员登录页面

目录 隐藏 创建会员登录页面 编辑登录页面 设计您的登录页面 链接到您的登录页面 创建会员登录页面 要创建MemberPress会员登录页面,您需要做的就是导航到 MemberPress > 设置 > 页面选项卡,然后在页面顶部附近的“MemberPress 登录页面”…

面试官脑子有病系列:为什么 HashMap 是线程不安全的?

文章目录 前言HashMap为啥线程不安全?HashMap线程不安全的根本原因put 方法中的非原子性操作扩容时的非原子性操作 安全的HashMap总结 前言 Hi,大家好,我是王二蛋。 我们在面试的时候,经常会被问到一些有的没的、看似高深但与日…