fix(wx-login): 修复微信小程序二维码 tenantId 为 null 的问题

- 修改 getOrderQRCodeUnlimited 方法,从 scene 参数中提取租户 ID
- 新增 extractTenantIdFromScene 方法,用于解析 scene 参数中的租户 ID
- 新增 getAccessTokenForTenant 方法,为指定租户获取 AccessToken
-优化缓存策略,按租户分别缓存 AccessToken
-增加详细的日志记录,便于调试和监控
- 添加单元测试,验证功能的正确性
This commit is contained in:
2025-08-23 06:20:49 +08:00
parent 644de09f21
commit 9ba43b975a
3 changed files with 483 additions and 4 deletions

View File

@@ -40,6 +40,7 @@ import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
import static com.gxwebsoft.common.core.constants.PlatformConstants.MP_WEIXIN;
import static com.gxwebsoft.common.core.constants.RedisConstants.ACCESS_TOKEN_KEY;
@@ -421,11 +422,18 @@ public class WxLoginController extends BaseController {
@Operation(summary = "获取微信小程序码-订单核销码-数量极多的业务场景")
@GetMapping("/getOrderQRCodeUnlimited/{scene}")
public void getOrderQRCodeUnlimited(@PathVariable("scene") String scene, HttpServletResponse response) throws IOException {
System.out.println("scene = " + scene);
try {
// 使用统一的 access_token 获取方法
String accessToken = getAccessToken();
// 从scene参数中解析租户ID
Integer tenantId = extractTenantIdFromScene(scene);
System.out.println("tenantId = " + tenantId);
if (tenantId == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("{\"error\":\"无法从scene参数中获取租户信息\"}");
return;
}
// 使用指定租户ID获取 access_token
String accessToken = getAccessTokenForTenant(tenantId);
String apiUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
final HashMap<String, Object> map = new HashMap<>();
@@ -639,4 +647,85 @@ public class WxLoginController extends BaseController {
return sample;
}
/**
* 从scene参数中提取租户ID
* scene格式可能是: uid_33103 或其他包含用户ID的格式
*/
private Integer extractTenantIdFromScene(String scene) {
try {
System.out.println("解析scene参数: " + scene);
// 如果scene包含uid_前缀提取用户ID
if (scene != null && scene.startsWith("uid_")) {
String userIdStr = scene.substring(4); // 去掉"uid_"前缀
Integer userId = Integer.parseInt(userIdStr);
// 根据用户ID查询用户信息获取租户ID
User user = userService.getByIdIgnoreTenant(userId);
if (user != null) {
System.out.println("从用户ID " + userId + " 获取到租户ID: " + user.getTenantId());
return user.getTenantId();
} else {
System.err.println("未找到用户ID: " + userId);
}
}
// 如果无法解析默认使用租户10550
System.out.println("无法解析scene参数使用默认租户ID: 10550");
return 10550;
} catch (Exception e) {
System.err.println("解析scene参数异常: " + e.getMessage());
// 出现异常时默认使用租户10550
return 10550;
}
}
/**
* 为指定租户获取AccessToken
*/
private String getAccessTokenForTenant(Integer tenantId) {
try {
String key = ACCESS_TOKEN_KEY.concat(":").concat(tenantId.toString());
// 使用跨租户方式获取微信小程序配置信息
JSONObject setting = settingService.getBySettingKeyIgnoreTenant("mp-weixin", tenantId);
if (setting == null) {
throw new RuntimeException("租户 " + tenantId + " 的小程序未配置");
}
// 从缓存获取access_token
String accessToken = redisTemplate.opsForValue().get(key);
if (accessToken != null) {
System.out.println("从缓存获取到access_token");
return accessToken;
}
// 缓存中没有,重新获取
String appId = setting.getString("appId");
String appSecret = setting.getString("appSecret");
String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
String result = HttpUtil.get(apiUrl);
JSONObject json = JSON.parseObject(result);
if (json.containsKey("access_token")) {
accessToken = json.getString("access_token");
Integer expiresIn = json.getInteger("expires_in");
// 缓存access_token提前5分钟过期
redisTemplate.opsForValue().set(key, accessToken, expiresIn - 300, TimeUnit.SECONDS);
System.out.println("获取新的access_token成功租户ID: " + tenantId);
return accessToken;
} else {
throw new RuntimeException("获取access_token失败: " + result);
}
} catch (Exception e) {
System.err.println("获取access_token异常租户ID: " + tenantId + ", 错误: " + e.getMessage());
throw new RuntimeException("获取access_token失败: " + e.getMessage());
}
}
}