当前位置: 代码网 > it编程>编程语言>Java > springboot如何通过接口实现动态二维码的定时刷新

springboot如何通过接口实现动态二维码的定时刷新

2025年05月27日 Java 我要评论
一、需求场景在web应用中,动态二维码常用于以下场景:登录验证:微信扫码登录、app扫码授权支付场景:支付宝/微信支付码定时刷新票务系统:电子票二维码防截屏盗用会员系统:动态会员码累计积分二、技术方案

一、需求场景

在web应用中,动态二维码常用于以下场景:

  • 登录验证:微信扫码登录、app扫码授权
  • 支付场景:支付宝/微信支付码定时刷新
  • 票务系统:电子票二维码防截屏盗用
  • 会员系统:动态会员码累计积分

二、技术方案设计

1、 整体流程

三、前端部分

大致流程

1、请求后端接口(按照现有项目格式即可)

2、后端接口的返回类型定义(byte[])

3、前端接收时定义响应类型(重点:responsetype: 'arraybuffer')

4、对后端返回数据进行转化:arraybuffertobase64

5、对数据和标签进行绑定

具体实现

1、获取后端 二维码 图片接口

	import {
		generatemembercode
	} from '@/api/inter/member-code.js';

data() {
			return {
				codeimg: '',
				timer: null, // 添加定时器引用,
			}
		},
		onshow() {
			// 立即加载一次
			this.makemembercode();

			// 设置定时器(注意保存引用)
			this.timer = setinterval(() => {
				this.makemembercode();
			}, 30000);
		},
		onhide() {
			// 页面隐藏时清除定时器
			if (this.timer) {
				clearinterval(this.timer);
				this.timer = null;
			}
		},
        methods: {
			async makemembercode() {
				const memberid = 1; // 使用假数据中的 id
				const membername = '张三'; // 使用假数据中的 nickname
				const params = {
					memberid,
					membername
				};
				try {
                    // 调用后端接口(这里可改成符合你项目的请求方式)
					const response = await generatemembercode(params);
					console.log('完整响应:', response);

					// 调试数据类型
					console.log('响应数据类型:', typeof response);

					// 处理二进制数据(适用于小程序)
					if (typeof response === 'object' && response instanceof arraybuffer) {
						const base64 = uni.arraybuffertobase64(response);
						this.codeimg = `data:image/png;base64,${base64}`;
						console.log('新的 codeimg:', this.codeimg); // 调试输出
					} else if (typeof response.data === 'string') {
						this.codeimg = `data:image/png;base64,${response.data}`;
					}
					// 处理url
					else if (response.data.imageurl) {
						this.codeimg = response.data.imageurl;
					}
				} catch (error) {
					console.error('请求失败:', error);
					uni.showtoast({
						title: '会员码加载失败',
						icon: 'none'
					});
				}
			}
        }

上面部分用到的代码: member-code.js

import { httpclient } from '@/api/utils/request.js'; // 确保路径正确
import api from '../../config/api.js'; // 导入 api 配置

const http = new httpclient(api.base);


/**
 * 获取后端二维码
 */
export async function generatemembercode(params) {
    try {
        const response = await http.getbuffer('/api/wx/generate-qrcode',params);
        console.log('response:', response);
        return response; // 返回响应数据
    } catch (error) {
        console.error('error:', error);
        throw error; // 继续抛出错误以供上层处理
    }
}

请求接口工具类:request.js

class httpclient {
	constructor(baseurl) {
		this.baseurl = baseurl;
	}

async getbuffer(url, params = {}) {
		try {
			//await this.checktokenandnavigate(); // 在发送请求前检查 token
			const querystring = this.buildquerystring(params);
			const fullurl = `${this.baseurl}${url}${querystring}`;
	
			return new promise((resolve, reject) => {
				uni.request({
					url: fullurl,
					method: 'get',
					header: {
						'content-type': 'application/json',
						'x-auth-token': `${uni.getstoragesync('token')}` // 如果需要在 header 中发送 token
					},
					responsetype: 'arraybuffer', // 指定响应类型为 arraybuffer
					success: (response) => {
						resolve(response.data);
					},
					fail: (error) => {
						console.error('get request error:', error);
						reject(error);
					}
				});
			});
		} catch (error) {
			// 如果 checktokenandnavigate 抛出错误(例如没有 token),则这里处理错误
			return promise.reject(error);
		}
	}
    buildquerystring(params) {
	  if (!params || object.keys(params).length === 0) {
	    return '';
	  }
	  return '?' + object.keys(params)
	    .map(key => encodeuricomponent(key) + '=' + encodeuricomponent(params[key]))
	    .join('&');
	}
}

export {
	httpclient
};

接口地址api 配置类:api.js

// 生产环境
const prod = {
  base: "http://xxxxxx:8099",
};

// 开发环境
const dev = {
  base: "http://xxxxxxx:8099",
};

// 默认生产环境
let api = prod;

// 如果是开发环境
if (process.env.node_env === "development") {
  api = dev;
}

// 微信小程序和app的打包方式建议为生产环境,所以这块直接条件编译赋值()
// #ifdef mp-weixin || app-plus
// 这个直接使用的是 dev 地址
api = dev;
// #endif

export default {
  ...api,
};

2、模板进行渲染

	<view class="qrcode d-flex just-content-center align-items-center">
					<image :src="`${codeimg}`" style="width: 350rpx; height: 350rpx;"></image>
				</view>

四、后端部分

具体实现

1、添加依赖

<!-- zxing core and java se -->
    <dependency>
        <groupid>com.google.zxing</groupid>
        <artifactid>core</artifactid>
        <version>3.4.1</version>
    </dependency>
    <dependency>
        <groupid>com.google.zxing</groupid>
        <artifactid>javase</artifactid>
        <version>3.4.1</version>
    </dependency>

2、接口实现controller

import com.google.zxing.barcodeformat;
import com.google.zxing.encodehinttype;
import com.google.zxing.writerexception;
import com.google.zxing.client.j2se.matrixtoimagewriter;
import com.google.zxing.common.bitmatrix;
import com.google.zxing.qrcode.qrcodewriter;

import org.springframework.http.httpheaders;
import org.springframework.http.httpstatus;
import org.springframework.http.mediatype;
import org.springframework.http.responseentity;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestparam;
import org.springframework.web.bind.annotation.restcontroller;

import java.io.bytearrayoutputstream;
import java.nio.file.filesystems;
import java.util.hashmap;
import java.util.map;

@restcontroller
public class qrcodecontroller {

    @getmapping("/generate-qrcode")
    public responseentity<byte[]> generateqrcode(
            @requestparam string memberid,
            @requestparam string membername) throws writerexception {
        
        // 构建二维码内容(内容可根据自己业务动态修改)
        // 建议加上唯一标识,安全码、起始时间、状态等,保证二维码安全性
        string qrcontent = "member id: " + memberid + ", member name: " + membername;

        // 设置二维码参数
        int width = 300;
        int height = 300;
        string imageformat = "png"; // 图片格式

        map<encodehinttype, object> hints = new hashmap<>();
        hints.put(encodehinttype.character_set, "utf-8");

        // 生成二维码
        qrcodewriter qrcodewriter = new qrcodewriter();
        bitmatrix bitmatrix = qrcodewriter.encode(qrcontent, barcodeformat.qr_code, width, height, hints);

        // 将二维码写入字节数组输出流
        bytearrayoutputstream pngoutputstream = new bytearrayoutputstream();
        matrixtoimagewriter.writetostream(bitmatrix, imageformat, pngoutputstream);

        // 返回二维码图片
        httpheaders headers = new httpheaders();
        headers.setcontenttype(mediatype.image_png);
        return new responseentity<>(pngoutputstream.tobytearray(), headers, httpstatus.ok);
    }
}

接口测试

get http://localhost:8080/generate-qrcode?memberid=12345&membername=johndoe

前端处理后端的数据时,在一定要指定相应类型:responsetype: 'arraybuffer'

五、效果展示

六、安全性设计

风险防御方案
二维码盗用30秒短时效性 + 单次有效性验证
接口的暴力请求限流策略(如guava ratelimiter)
中间人 攻击全站https + 数据签名
xss攻击前端输入过滤 + csp安全策略

七、总结

关键技术栈

  • 前端定时器 + 二进制流处理
  • 后端二维码生成 + 状态管理
  • 高效的缓存策略

最佳实践建议

  • 始终为二维码添加时效性和唯一性标识
  • 敏感操作需二次确认(如扫码后的授权确认)
  • 监控二维码使用率,优化生成策略

通过前后端协作,动态二维码既能提升用户体验,又能有效保障系统安全性。

以上就是springboot如何通过接口实现动态二维码的定时刷新的详细内容,更多关于springboot动态二维码刷新的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com