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

news2024/11/26 4:41:14

项目背景

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

代码已经上传到 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!")

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

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

相关文章

中颖51芯片学习4. 可编程计数器阵列PCA0

中颖51芯片学习4. 可编程计数器阵列PCA0 一、PCA介绍1. PCA简介2. SH79F9476的PCA0特性3. PCA0 功能4. 时钟5. PCA0原理框图6. 工作方式 二、PCA0寄存器1. PCA0标志寄存器2. PCA使能寄存器3. PCA0方式寄存器4. P0CPMn PCA捕捉/比较寄存器5. P0FORCE强制输出控制寄存器6. PCA0计…

《极域多媒体教室互动管理系统软件》控制方法大全

前言及背景: 当我坐在电脑前,打开它,点开谷歌,刚刚想打开百度,突然闪出来了: 该网页已被阻止!!! 正文: 1.极域控制原理: 好…

使用EZDML自动生成测试数据

项目场景: 项目开发时,新创建的表需要增加一部分测试数据用于简单的功能测试。 问题描述 无论使用代码还是使用plsql自带的数据生成工具都感觉有点麻烦,我只想点点点就能生成数据。 解决方案: 提示:这里填写该问题的具体解决方案: 使用 EZDML 可以方便的生成测试数据。…

吴恩达深度学习 (week1,2)

文章目录 1、神经网络监督学习2、深度学习兴起原因3、深度学习二元分类4、深度学习Logistic 回归5、Logistic 回归损失函数6、深度学习梯度下降法7、深度学习向量法8、Python 中的广播9、上述学习总结10、大作业实现:rocket::rocket:(1)训练初始数据&…

如何开始用 C++ 写一个光栅化渲染器?

光栅化渲染器是计算机图形学中最基础且广泛应用的一种渲染技术,它将三维模型转化为二维图像。下面我们将逐步介绍如何使用C语言从零开始构建一个简单的光栅化渲染器。 一、理解光栅化渲染原理 光栅化是一种将几何数据(如点、线、三角形)转换…

一文详解手机IP地址如何改变

在互联网时代,手机的IP地址扮演着至关重要的角色。它不仅是手机在网络中的标识,还关系到手机的网络连接、隐私保护以及访问权限等方面。然而,在某些情况下,我们可能需要改变手机的IP地址,以满足特定的需求或解决网络问…

8×8点阵数码管显示驱动/大电流数码管驱动IC-VK16K33C SOP20

产品品牌:永嘉微电/VINKA 产品型号:VK16K33C 封装形式:SOP20 概述 VK16K33C是一种带按键扫描接口的数码管或点阵LED驱动控制专用芯片,内部集成有数据锁 存器、键盘扫描、LED 驱动模块等电路。数据通过I2C通讯接口与MCU通信。SE…

腾讯再次回归电商,视频号小店真的要起飞了?

大家好,我是电商小布。 在互联网快速发展的现状下,各个平台都开始加入到电商这一行。 就连之前在电商上栽过跟头的腾讯,都再次回归电商,推出了视频号小店这个项目。 视频号小店背靠着视频号平台,结合当前最热的电商…

数字中国_智慧公厕

在面向未来构建城市竞争新优势、推动城市治理现代化的进程中,推进城市智慧化发展、数字化转型显得尤为重要。作为一种新形态的信息化公共厕所,智慧公厕扮演着举足轻重的角色,对于智慧城市和智慧乡村的发展至关重要,也是城市信息化…

如何加密VM虚拟机

参考官方文档:加密虚拟机 (vmware.com) 选择该虚拟机,然后选择虚拟机 > 设置。在选项选项卡中,选择访问控制。单击加密。选择适当的加密类型。单击加密,键入加密密码,然后单击加密。 要获得虚拟机的访问权限&#…

C++ primer 第十八章

C语言的三大特性:异常处理、命名空间、多重继承。 1.异常处理 异常处理机制允许我们能够将问题的检测与解决过程分离开来。 1.1、抛出异常 在C语言中,我们通过抛出一条表达式来引发一个异常。 当执行一个throw时,程序的控制权从throw转移…

linux 开机自启动

方式1—依赖桌面启动,一般适用与UI相关程序 1、创建运行脚本,以管理员放方式运行,加入密码 vim runapp.sh #!/bin/bash cd /home/nvidia/test echo ‘passcode’ | sudo -S ./testapp 2、终端输入 gnome-session-properties 3、在com…

【超简单】基于PaddleSpeech搭建个人语音听写服务

一、【超简单】之基于PaddleSpeech搭建个人语音听写服务 1.需求分析 亲们,你们要写会议纪要嘛?亲们,你们要写会议纪要嘛?亲们,你们要写会议纪要嘛?当您面对成吨的会议录音,着急写会议纪要而不得不愚公移山、人海战术?听的头晕眼花,听的漏洞百出,听的怀疑人生,那么你…

跨框架探索:React Redux 和 Vuex 对比分析快速掌握React Redux

React Redux 和 Vuex 都是前端状态管理库,分别用于 React 和 Vue.js 框架。 它们都提供了一套规范的状态管理机制,帮助开发者更好地组织和管理应用状态。下面是它们的一些异同点: 相同点: 中心化状态管理:两者都提…

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).…

一文介绍CNN/RNN/GAN/Transformer等架构 !!

文章目录 前言 1、卷积神经网络(CNN) 2、循环神经网络(RNN) 3、生成对抗网络(GAN) 4、Transformer 架构 5、Encoder-Decoder架构 前言 本文旨在介绍深度学习架构,包括卷积神经网络CNN、循环神经…

K8S node节点配置

1.开始操作之前要先关闭防火墙,SELinux,swap分区 关闭防火墙 sudo systemctl stop firewalld关闭SELinux sudo setenforce 0 # 临时关闭 sudo sed -i s/^SELINUXenforcing$/SELINUXper…

应用Ribo-seq技术量化tRNA对乳腺癌细胞转移的调控

技术简介 Ribo-seq,又称为Ribosome Profiling或者翻译组测序,能够对与核糖体结合并正在被翻译的约30 nt的mRNA片段进行测序,详细检测体内的翻译状态,Ribo-seq是连接转录组学与蛋白质组学之间的桥梁。该技术可构建癌细胞全基因组水…

为什么PCB板上需要晶振

PCB板,即印刷电路板,是现代电子设备中不可或缺的组成部分。它的基本功能是提供电子元件之间的电气连接,使电子元件能够正确、高效地工作。然而,为了使电子设备能够正常工作,PCB板上的电子元件需要遵循一定的时序和频率…

Java入门基础知识第八课(数组)——冒泡排序、Arrays工具类

前面二白讲了关于数组的概念、语法以及简单的输入输出,实际上关于数组的知识还有很多,接下来咱们讲一下冒泡排序以及一些常用的Arrays工具类,需要记忆的知识很多,而且容易混淆。 一、冒泡排序 简介(原理)…