springboot如何通过接口实现动态二维码的定时刷新
目录
- 一、需求场景
- 二、技术方案设计
- 三、前端部分
- 大致流程
- 具体实现
- 四、后端部分
- 五、效果展示
- 六、安全性设计
- 七、总结
一、需求场景
在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); /** * 获取后端二维码 */ expjavascriptort 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(); // 在发送请求前检查 tokehttp://www.devze.comn 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 { .android..api, };
2、模板进行渲染
<view class="qrcode d-Flex just-content-center align-items-center"> <image :src="`${codeImg}`"></image> http://www.devze.com </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, imageFor编程客栈mat, 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动态二维码刷新的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论