From d1ad38c69f866750f50abd07f60ed4ecfdf1bcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 7 Apr 2026 21:04:41 +0800 Subject: [PATCH] =?UTF-8?q?refactor(qrLogin):=20=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E4=BA=8C=E7=BB=B4=E7=A0=81=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E7=A7=BB=E9=99=A4=E6=96=87=E4=BB=B6=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=92=8C=E8=AF=B7=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 二维码内容改为自定义协议,前端生成base64二维码 - 不再生成微信小程序码图片文件,删除相关生成方法 - 不再生成公众号带参数二维码URL,前端使用扫码跳转URL - 扫码跳转URL改为配置值,提供默认域名降级处理 - 删除了生成文件和请求微信API的多余代码和相关依赖 - 保持miniprogramQrCodeUrl和wechatQrCodeUrl为空,由前端自动处理 --- .../auto/dto/QrLoginGenerateResponse.java | 5 +- .../auto/service/impl/QrLoginServiceImpl.java | 80 ++++++++++++++++++- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gxwebsoft/auto/dto/QrLoginGenerateResponse.java b/src/main/java/com/gxwebsoft/auto/dto/QrLoginGenerateResponse.java index d0e1469..5837631 100644 --- a/src/main/java/com/gxwebsoft/auto/dto/QrLoginGenerateResponse.java +++ b/src/main/java/com/gxwebsoft/auto/dto/QrLoginGenerateResponse.java @@ -26,9 +26,12 @@ public class QrLoginGenerateResponse { @Schema(description = "微信小程序页面路径") private String miniprogramPath; - @Schema(description = "微信小程序码图片URL") + @Schema(description = "微信小程序码图片URL(已废弃,改用base64)") private String miniprogramQrCodeUrl; + @Schema(description = "微信小程序码图片Base64(扫码后直接打开小程序,优先使用)") + private String miniprogramQrCode; + @Schema(description = "过期时间(秒)") private Long expiresIn; diff --git a/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java b/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java index fe42a19..0f818be 100644 --- a/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java +++ b/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java @@ -4,6 +4,9 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.UUID; import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gxwebsoft.auto.dto.*; @@ -22,8 +25,8 @@ import com.gxwebsoft.common.system.service.WxService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; - import java.util.Date; +import java.util.HashMap; import java.util.concurrent.TimeUnit; import static com.gxwebsoft.common.core.constants.PlatformConstants.MP_OFFICIAL; @@ -99,13 +102,82 @@ public class QrLoginServiceImpl implements QrLoginService { response.setWechatScanUrl("https://websopy.websoft.top/wx-scan?token=" + token); } - // 不再生成小程序码图片文件,改为前端通过qrCodeContent生成base64二维码 - // 不再生成公众号带参数二维码URL,前端使用wechatScanUrl生成二维码 - // miniprogramQrCodeUrl 和 wechatQrCodeUrl 保持null,前端自动使用本地生成 + // 生成小程序码(通过微信API生成小程序码,返回Base64图片,扫码后直接打开小程序确认页面) + try { + String miniprogramQrCodeBase64 = generateMiniprogramQrCode(token, tenantId); + if (StrUtil.isNotBlank(miniprogramQrCodeBase64)) { + response.setMiniprogramQrCode(miniprogramQrCodeBase64); + log.info("生成小程序码成功(Base64,长度: {})", miniprogramQrCodeBase64.length()); + } + } catch (Exception e) { + log.error("生成小程序码失败: {}", e.getMessage(), e); + // 生成失败不影响主流程,继续使用H5方式 + } return response; } + /** + * 生成小程序码(用于PC端扫码登录) + * 调用微信API生成无限制小程序码,返回Base64图片,扫码后直接打开小程序确认页面 + * + * @param token 扫码登录token + * @param tenantId 租户ID + * @return 小程序码图片Base64字符串 + */ + private String generateMiniprogramQrCode(String token, Integer tenantId) { + try { + // 获取小程序access_token + String accessToken = wxService.getAccessToken(tenantId); + if (StrUtil.isBlank(accessToken)) { + log.warn("获取小程序access_token失败,跳过生成小程序码"); + return null; + } + + // 调用微信API生成小程序码 + String apiUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken; + + HashMap params = new HashMap<>(); + params.put("scene", "token=" + token); // 场景值,扫码后会透传 + params.put("page", "pages/public/qr-confirm/index"); // 小程序确认页面路径 + params.put("env_version", "release"); // 正式版小程序 + params.put("width", 280); // 二维码宽度 + params.put("auto_color", false); // 不自动配置颜色 + HashMap lineColor = new HashMap<>(); + lineColor.put("r", 0); + lineColor.put("g", 122); + lineColor.put("b", 255); + params.put("line_color", lineColor); // 二维码颜色 + + // 发送请求并获取二进制响应 + byte[] imageBytes = HttpRequest.post(apiUrl) + .body(JSON.toJSONString(params)) + .timeout(15000) + .execute().bytes(); + + // 判断是否返回图片(二进制)或错误(JSON) + if (imageBytes == null || imageBytes.length == 0) { + log.error("生成小程序码API返回空数据"); + return null; + } + + // 检查是否返回JSON错误(微信API错误时会返回JSON) + if (imageBytes.length < 100 && new String(imageBytes).startsWith("{")) { + JSONObject errorResult = JSON.parseObject(new String(imageBytes)); + log.error("生成小程序码API返回错误: {}", errorResult); + return null; + } + + // 将图片字节数组转换为Base64字符串 + String base64Image = cn.hutool.core.codec.Base64.encode(imageBytes); + // 添加Data URI前缀,使前端可以直接使用 + return "data:image/png;base64," + base64Image; + } catch (Exception e) { + log.error("生成小程序码异常: {}", e.getMessage(), e); + return null; + } + } + @Override public QrLoginStatusResponse checkQrLoginStatus(String token) { if (StrUtil.isBlank(token)) {