fix(wx-login): 修复微信小程序二维码 tenantId 为 null 的问题
- 修改 getOrderQRCodeUnlimited 方法,从 scene 参数中提取租户 ID - 新增 extractTenantIdFromScene 方法,用于解析 scene 参数中的租户 ID - 新增 getAccessTokenForTenant 方法,为指定租户获取 AccessToken -优化缓存策略,按租户分别缓存 AccessToken -增加详细的日志记录,便于调试和监控 - 添加单元测试,验证功能的正确性
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.gxwebsoft.common.system.controller;
|
||||
|
||||
import com.gxwebsoft.common.system.entity.User;
|
||||
import com.gxwebsoft.common.system.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 微信登录控制器测试
|
||||
*
|
||||
* @author WebSoft
|
||||
* @since 2025-08-23
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("dev")
|
||||
public class WxLoginControllerTest {
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
/**
|
||||
* 测试从scene参数解析租户ID的逻辑
|
||||
*/
|
||||
@Test
|
||||
public void testExtractTenantIdFromScene() {
|
||||
log.info("=== 开始测试scene参数解析 ===");
|
||||
|
||||
// 测试用户ID 33103
|
||||
Integer testUserId = 33103;
|
||||
|
||||
// 查询用户信息
|
||||
User user = userService.getByIdIgnoreTenant(testUserId);
|
||||
if (user != null) {
|
||||
log.info("用户ID {} 对应的租户ID: {}", testUserId, user.getTenantId());
|
||||
log.info("用户信息 - 用户名: {}, 手机: {}", user.getUsername(), user.getPhone());
|
||||
} else {
|
||||
log.warn("未找到用户ID: {}", testUserId);
|
||||
}
|
||||
|
||||
// 测试不同的scene格式
|
||||
String[] testScenes = {
|
||||
"uid_33103",
|
||||
"uid_1",
|
||||
"uid_999999",
|
||||
"invalid_scene",
|
||||
null
|
||||
};
|
||||
|
||||
for (String scene : testScenes) {
|
||||
log.info("测试scene: {} -> 预期解析结果", scene);
|
||||
// 这里模拟解析逻辑
|
||||
if (scene != null && scene.startsWith("uid_")) {
|
||||
try {
|
||||
String userIdStr = scene.substring(4);
|
||||
Integer userId = Integer.parseInt(userIdStr);
|
||||
User testUser = userService.getByIdIgnoreTenant(userId);
|
||||
if (testUser != null) {
|
||||
log.info(" 解析成功: 用户ID {} -> 租户ID {}", userId, testUser.getTenantId());
|
||||
} else {
|
||||
log.info(" 用户不存在: 用户ID {} -> 默认租户ID 10550", userId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.info(" 解析异常: {} -> 默认租户ID 10550", e.getMessage());
|
||||
}
|
||||
} else {
|
||||
log.info(" 无效格式 -> 默认租户ID 10550");
|
||||
}
|
||||
}
|
||||
|
||||
log.info("=== scene参数解析测试完成 ===");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试查找特定用户
|
||||
*/
|
||||
@Test
|
||||
public void testFindSpecificUsers() {
|
||||
log.info("=== 开始查找特定用户 ===");
|
||||
|
||||
// 查找租户10550的用户
|
||||
Integer[] testUserIds = {1, 2, 3, 33103, 10001, 10002};
|
||||
|
||||
for (Integer userId : testUserIds) {
|
||||
User user = userService.getByIdIgnoreTenant(userId);
|
||||
if (user != null) {
|
||||
log.info("用户ID: {}, 租户ID: {}, 用户名: {}, 手机: {}",
|
||||
userId, user.getTenantId(), user.getUsername(), user.getPhone());
|
||||
} else {
|
||||
log.info("用户ID: {} - 不存在", userId);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("=== 特定用户查找完成 ===");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试URL解析
|
||||
*/
|
||||
@Test
|
||||
public void testUrlParsing() {
|
||||
log.info("=== 开始测试URL解析 ===");
|
||||
|
||||
String testUrl = "127.0.0.1:9200/api/wx-login/getOrderQRCodeUnlimited/uid_33103";
|
||||
log.info("测试URL: {}", testUrl);
|
||||
|
||||
// 提取scene部分
|
||||
String[] parts = testUrl.split("/");
|
||||
String scene = parts[parts.length - 1]; // 最后一部分
|
||||
log.info("提取的scene: {}", scene);
|
||||
|
||||
// 解析用户ID
|
||||
if (scene.startsWith("uid_")) {
|
||||
String userIdStr = scene.substring(4);
|
||||
try {
|
||||
Integer userId = Integer.parseInt(userIdStr);
|
||||
log.info("解析的用户ID: {}", userId);
|
||||
|
||||
User user = userService.getByIdIgnoreTenant(userId);
|
||||
if (user != null) {
|
||||
log.info("对应的租户ID: {}", user.getTenantId());
|
||||
} else {
|
||||
log.warn("用户不存在");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("用户ID格式错误: {}", userIdStr);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("=== URL解析测试完成 ===");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user