From 5a913ce465a9c236e50a3f74ddc665873d8256d0 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Tue, 2 Sep 2025 10:26:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=BE=AA=E7=8E=AF=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E9=97=AE=E9=A2=98=EF=BC=8C=E5=BC=82=E6=AD=A5=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=BC=95=E8=B5=B7=E7=9A=84=EF=BC=8C=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=87=BA=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/controller/LoginController.java | 2 + .../impl/AccountUserBaseServiceImpl.java | 43 +++--- .../impl/AccountUserInfoServiceImpl.java | 18 +-- .../service/impl/AsyncTaskService.java | 47 +++++++ .../service/impl/WxQrCodeServiceImpl.java | 124 +++++++++++++++++- 5 files changed, 197 insertions(+), 37 deletions(-) create mode 100644 mall-account/src/main/java/com/suisung/mall/account/service/impl/AsyncTaskService.java diff --git a/mall-account/src/main/java/com/suisung/mall/account/controller/LoginController.java b/mall-account/src/main/java/com/suisung/mall/account/controller/LoginController.java index a93df90b..709175bc 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/controller/LoginController.java +++ b/mall-account/src/main/java/com/suisung/mall/account/controller/LoginController.java @@ -48,9 +48,11 @@ import java.util.Map; @RequestMapping("/mobile/account/login") public class LoginController extends BaseControllerImpl { + // @Lazy @Autowired private AccountUserBaseService accountUserBaseService; + // @Lazy @Autowired private AccountUserInfoService accountUserInfoService; diff --git a/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBaseServiceImpl.java b/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBaseServiceImpl.java index b83e1cc2..b8d723e3 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBaseServiceImpl.java +++ b/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBaseServiceImpl.java @@ -68,7 +68,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.util.Pair; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -109,8 +108,6 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl params) { @@ -2995,7 +2996,7 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl implements AccountUserInfoService { + private static final Logger logger = LoggerFactory.getLogger(AccountUserInfoServiceImpl.class); @Autowired private AccountUserBaseService accountUserBaseService; - @Autowired private AccountUserLoginService accountUserLoginServicel; - @Autowired private AccountUserLevelLogService accountUserLevelLogService; - @Autowired private AccountBaseUserLevelService accountBaseUserLevelService; - @Autowired private AccountBaseConfigService accountBaseConfigService; - + @Lazy @Autowired private ShopService shopService; - @Autowired private AccountUserSnsService accountUserSnsService; - @Autowired private ShopUserExpHistoryService shopUserExpHistoryService; - @Autowired private AccountUserInfoService accountUserInfoService; - @Autowired private PayService payService; - private static Logger logger = LoggerFactory.getLogger(AccountUserInfoServiceImpl.class); - /** * 实名认证页面 * @@ -749,7 +741,7 @@ public class AccountUserInfoServiceImpl extends BaseServiceImpl + * 官方文档地址:https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html + * + * @param sceneId 场景值ID(整数形式的ID),范围是1-100000 + * scene_id: 场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000) + * 说明: + * 1. 每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id 或 scene_str) + * 2. 永久二维码的scene_id参数值必须是大于0且小于100000的整数 + * 3. 同一个access_token和scene_id或scene_str生成的二维码ticket是相同的,扫描后推送的事件中的eventkey值也相同 + * 4. 开发者可通过事件推送接口接收用户扫描二维码的事件,并根据scene_id或scene_str做相应的业务处理 + * @return Pair<二维码图片URL, 错误信息> + */ + public Pair genWechatLimitQrCode(Integer sceneId) { + try { + // 参数校验 + if (sceneId == null || sceneId <= 0 || sceneId > 100000) { + return Pair.of("", I18nUtil._("场景值ID必须是1-100000之间的整数")); + } + + // 获取access_token + String accessToken = wxUtil.getAccessToken(); + if (StrUtil.isBlank(accessToken)) { + return Pair.of("", I18nUtil._("获取微信access_token失败")); + } + + // 微信生成二维码的接口URL(使用A接口-永久二维码) + String reqUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken; + + // 构造请求参数 + Map params = new HashMap<>(); + params.put("action_name", "QR_LIMIT_SCENE"); // 永久整数参数二维码 + + Map actionInfo = new HashMap<>(); + Map scene = new HashMap<>(); + scene.put("scene_id", sceneId); + actionInfo.put("scene", scene); + params.put("action_info", actionInfo); + + String paramStr = JSONUtil.toJsonStr(params); + + // 发送请求获取ticket + String responseStr = HttpUtil.post(reqUrl, paramStr); + JSONObject responseJson = JSONUtil.parseObj(responseStr); + + if (responseJson.containsKey("errcode") && responseJson.getInt("errcode") != 0) { + String errorMsg = responseJson.getStr("errmsg", I18nUtil._("生成二维码失败")); + log.error("生成微信永久二维码失败,错误码:{},错误信息:{}", responseJson.getInt("errcode"), errorMsg); + return Pair.of("", errorMsg); + } + + String ticket = responseJson.getStr("ticket"); + if (StrUtil.isBlank(ticket)) { + return Pair.of("", I18nUtil._("获取二维码ticket失败")); + } + + // 使用ticket换取二维码图片 + String qrCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + URLEncoder.encode(ticket, "UTF-8"); + + // 生成文件名 + String fileName = "limit_" + sceneId + "_qrcode.jpg"; + + // 下载二维码图片 + byte[] qrCodeBytes = HttpUtil.downloadBytes(qrCodeUrl); + + if (qrCodeBytes == null || qrCodeBytes.length == 0) { + return Pair.of("", I18nUtil._("下载二维码图片失败")); + } + + // 保存二维码图片 + Map resultMap = new HashMap<>(); + String wxQrCodeUrl = ""; + + if (!ConfigConstant.FILE_STORAGE_DISK) { + // 存入第三方文件存储服务 + InputStream stream = new ByteArrayInputStream(qrCodeBytes); + String dir = "/media/plantform"; + + Integer uploadType = accountBaseConfigService.getConfig("upload", 1); + + if (uploadType.equals(1)) { + wxQrCodeUrl = ConfigConstant.URL_BASE + "/admin/oss/upload" + dir + "/" + fileName; + } else if (uploadType.equals(2)) { + // oss 服务 + String folder = ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat("/qrcode/"); + wxQrCodeUrl = ossService.uploadObject2OSS(null, folder + fileName, stream, fileName, Convert.toLong(qrCodeBytes.length)); + } else if (uploadType.equals(4)) { + String qrcodePath = String.format("%s/media/plantform/qrcode/%s/", ConfigConstant.STATIC_FILE_PATH, 2); + IoUtil.write(FileUtil.getOutputStream(qrcodePath + fileName), true, qrCodeBytes); + File qrcodeFile = FileUtil.file(qrcodePath + fileName); + wxQrCodeUrl = ossService.uploadObject4OSS(qrcodeFile, TENGXUN_DEFAULT_DIR.concat(dir).concat("/").concat(fileName)); + } + } else { + // 存入本地文件 + String qrcodePath = String.format("%s/media/plantform/qrcode/%s/", ConfigConstant.STATIC_FILE_PATH, 2); + File qrcodeDir = new File(qrcodePath); + if (!qrcodeDir.exists()) { + qrcodeDir.mkdirs(); + } + IoUtil.write(FileUtil.getOutputStream(qrcodePath + fileName), true, qrCodeBytes); + wxQrCodeUrl = ConfigConstant.URL_BASE + "/media/plantform/qrcode/" + 2 + "/" + fileName; + } + + resultMap.put("wxQrCodeUrl", wxQrCodeUrl); + resultMap.put("fileName", fileName); + resultMap.put("ticket", ticket); + + log.info("成功生成微信永久二维码,sceneId: {}, 二维码URL: {}", sceneId, wxQrCodeUrl); + return Pair.of(wxQrCodeUrl, ""); + + } catch (Exception e) { + log.error("生成微信永久二维码时发生异常,sceneId: {}", sceneId, e); + return Pair.of("", I18nUtil._("生成二维码错误: ") + e.getMessage()); + } + } + + @Override public Map genUnlimitedWxQrCode(String preparedUrl, Map param) { try {