|
|
@@ -42,14 +42,22 @@ public class WeChatServiceImpl implements WeChatService {
|
|
|
|
|
|
@Override
|
|
|
public Map<String, Object> code2Session(String code) {
|
|
|
+ log.info("=== 开始调用微信 code2Session ===");
|
|
|
+ log.info("接收到的 code: {}", code);
|
|
|
+ log.info("code 长度: {}", code != null ? code.length() : 0);
|
|
|
+ log.info("Mock 模式: {}", mockEnabled);
|
|
|
+
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
if (code == null || code.trim().isEmpty()) {
|
|
|
+ log.error("❌ code 为空");
|
|
|
result.put("errcode", 400);
|
|
|
result.put("errmsg", "code 不能为空");
|
|
|
return result;
|
|
|
}
|
|
|
+
|
|
|
// 开发环境 Mock:无需真实 appid/secret 与外网请求
|
|
|
if (mockEnabled) {
|
|
|
+ log.info("✅ 使用 Mock 模式");
|
|
|
Map<String, Object> mock = new HashMap<>();
|
|
|
mock.put("errcode", 0);
|
|
|
mock.put("openid", "mock_openid_" + code.trim());
|
|
|
@@ -57,29 +65,74 @@ public class WeChatServiceImpl implements WeChatService {
|
|
|
mock.put("unionid", null);
|
|
|
return mock;
|
|
|
}
|
|
|
+
|
|
|
if (appId == null || appId.isEmpty() || secret == null || secret.isEmpty()) {
|
|
|
+ log.error("❌ 未配置 appid 或 secret");
|
|
|
+ log.error("appId: {}", appId != null ? (appId.isEmpty() ? "空字符串" : "已配置") : "null");
|
|
|
+ log.error("secret: {}", secret != null ? (secret.isEmpty() ? "空字符串" : "已配置") : "null");
|
|
|
result.put("errcode", 500);
|
|
|
result.put("errmsg", "未配置 wechat.appid/secret");
|
|
|
return result;
|
|
|
}
|
|
|
+
|
|
|
+ log.info("✅ 配置检查通过");
|
|
|
+ log.info("appId: {}", appId);
|
|
|
+ log.info("secret: {}...", secret.substring(0, Math.min(8, secret.length())));
|
|
|
+
|
|
|
String url = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
|
|
|
- jscode2sessionUrl, appId, secret, code);
|
|
|
+ jscode2sessionUrl, appId, secret, code.trim());
|
|
|
+ log.info("请求URL: {}", url.replace(secret, "***"));
|
|
|
+
|
|
|
try (CloseableHttpClient client = HttpClients.createDefault()) {
|
|
|
HttpGet get = new HttpGet(url);
|
|
|
+ log.info("发送HTTP请求到微信服务器...");
|
|
|
+
|
|
|
try (CloseableHttpResponse resp = client.execute(get)) {
|
|
|
+ int statusCode = resp.getStatusLine().getStatusCode();
|
|
|
+ log.info("HTTP状态码: {}", statusCode);
|
|
|
+
|
|
|
String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
|
|
|
+ log.info("微信返回原始响应: {}", body);
|
|
|
+
|
|
|
if (body == null || body.isEmpty()) {
|
|
|
+ log.error("❌ 微信返回空响应");
|
|
|
Map<String, Object> err = new HashMap<>();
|
|
|
err.put("errcode", 500);
|
|
|
err.put("errmsg", "微信返回空响应");
|
|
|
return err;
|
|
|
}
|
|
|
+
|
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
|
Map<String, Object> parsed = mapper.readValue(body, new TypeReference<Map<String, Object>>(){});
|
|
|
+
|
|
|
+ // 检查是否有错误
|
|
|
+ if (parsed.containsKey("errcode")) {
|
|
|
+ Integer errcode = (Integer) parsed.get("errcode");
|
|
|
+ if (errcode != 0) {
|
|
|
+ String errmsg = (String) parsed.get("errmsg");
|
|
|
+ log.error("❌ 微信接口返回错误");
|
|
|
+ log.error("错误码: {}", errcode);
|
|
|
+ log.error("错误信息: {}", errmsg);
|
|
|
+
|
|
|
+ // 针对常见错误给出提示
|
|
|
+ if (errcode == 40029) {
|
|
|
+ log.error("提示: code 无效,可能原因:");
|
|
|
+ log.error(" 1. code 已被使用过(每个 code 只能使用一次)");
|
|
|
+ log.error(" 2. code 已过期(5分钟有效期)");
|
|
|
+ log.error(" 3. code 与 appid 不匹配");
|
|
|
+ } else if (errcode == 40163) {
|
|
|
+ log.error("提示: code 已被使用");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("✅ 微信接口调用成功");
|
|
|
+ log.info("openid: {}", parsed.get("openid"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return parsed != null ? parsed : new HashMap<>();
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- log.error("调用 jscode2session 失败", e);
|
|
|
+ log.error("❌ 调用 jscode2session 异常", e);
|
|
|
Map<String, Object> err = new HashMap<>();
|
|
|
err.put("errcode", 500);
|
|
|
err.put("errmsg", "调用 jscode2session 异常:" + e.getMessage());
|
|
|
@@ -122,38 +175,91 @@ public class WeChatServiceImpl implements WeChatService {
|
|
|
|
|
|
@Override
|
|
|
public String getUserPhoneByCode(String code) {
|
|
|
+ log.info("=== 开始获取微信手机号 ===");
|
|
|
+ log.info("接收到的 phoneCode: {}", code);
|
|
|
+ log.info("Mock 模式: {}", mockEnabled);
|
|
|
+
|
|
|
// 开发环境 Mock:返回演示手机号
|
|
|
if (mockEnabled) {
|
|
|
+ log.info("✅ 使用 Mock 模式,返回测试手机号");
|
|
|
return "13800138000";
|
|
|
}
|
|
|
- if (code == null || code.trim().isEmpty()) return null;
|
|
|
+
|
|
|
+ if (code == null || code.trim().isEmpty()) {
|
|
|
+ log.error("❌ phoneCode 为空");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("获取 access_token...");
|
|
|
String accessToken = getAccessToken();
|
|
|
- if (accessToken == null) return null;
|
|
|
+ if (accessToken == null) {
|
|
|
+ log.error("❌ 获取 access_token 失败");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ log.info("✅ access_token 获取成功: {}...", accessToken.substring(0, Math.min(20, accessToken.length())));
|
|
|
+
|
|
|
String url = String.format("%s?access_token=%s", getPhoneUrl, accessToken);
|
|
|
+ log.info("请求URL: {}", url.replace(accessToken, "***"));
|
|
|
+
|
|
|
try (CloseableHttpClient client = HttpClients.createDefault()) {
|
|
|
// 微信该接口要求 POST JSON:{"code":"xxx"}
|
|
|
org.apache.http.client.methods.HttpPost post = new org.apache.http.client.methods.HttpPost(url);
|
|
|
post.setHeader("Content-Type", "application/json;charset=UTF-8");
|
|
|
- String payload = "{\"code\":\"" + code + "\"}";
|
|
|
+ String payload = "{\"code\":\"" + code.trim() + "\"}";
|
|
|
+ log.info("请求体: {}", payload);
|
|
|
post.setEntity(new org.apache.http.entity.StringEntity(payload, StandardCharsets.UTF_8));
|
|
|
+
|
|
|
+ log.info("发送HTTP POST请求到微信服务器...");
|
|
|
try (CloseableHttpResponse resp = client.execute(post)) {
|
|
|
+ int statusCode = resp.getStatusLine().getStatusCode();
|
|
|
+ log.info("HTTP状态码: {}", statusCode);
|
|
|
+
|
|
|
String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
|
|
|
- if (body == null || body.isEmpty()) return null;
|
|
|
+ log.info("微信返回原始响应: {}", body);
|
|
|
+
|
|
|
+ if (body == null || body.isEmpty()) {
|
|
|
+ log.error("❌ 微信返回空响应");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
|
Map<String, Object> parsed = mapper.readValue(body, new TypeReference<Map<String, Object>>(){});
|
|
|
- // 期望结构:{"code":0,"data":{"phoneNumber":"xxxx","purePhoneNumber":"xxxx"}}
|
|
|
- Object codeField = parsed.get("code");
|
|
|
- if (codeField instanceof Number && ((Number) codeField).intValue() == 0) {
|
|
|
- Object data = parsed.get("data");
|
|
|
- if (data instanceof Map) {
|
|
|
- Object phone = ((Map) data).get("phoneNumber");
|
|
|
- if (phone == null) phone = ((Map) data).get("purePhoneNumber");
|
|
|
- return phone != null ? String.valueOf(phone) : null;
|
|
|
+
|
|
|
+ // 检查错误码
|
|
|
+ Object errcode = parsed.get("errcode");
|
|
|
+ if (errcode != null) {
|
|
|
+ int errcodeInt = ((Number) errcode).intValue();
|
|
|
+ if (errcodeInt != 0) {
|
|
|
+ String errmsg = parsed.get("errmsg") != null ? String.valueOf(parsed.get("errmsg")) : "未知错误";
|
|
|
+ log.error("❌ 微信接口返回错误");
|
|
|
+ log.error("错误码: {}", errcodeInt);
|
|
|
+ log.error("错误信息: {}", errmsg);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 微信返回结构:{"errcode":0,"errmsg":"ok","phone_info":{"phoneNumber":"xxxx","purePhoneNumber":"xxxx","countryCode":"86","watermark":{...}}}
|
|
|
+ Object phoneInfo = parsed.get("phone_info");
|
|
|
+ if (phoneInfo instanceof Map) {
|
|
|
+ Map<String, Object> phoneMap = (Map<String, Object>) phoneInfo;
|
|
|
+ Object phone = phoneMap.get("phoneNumber");
|
|
|
+ if (phone == null) phone = phoneMap.get("purePhoneNumber");
|
|
|
+
|
|
|
+ if (phone != null) {
|
|
|
+ String phoneStr = String.valueOf(phone);
|
|
|
+ log.info("✅ 成功获取手机号: {}", phoneStr);
|
|
|
+ return phoneStr;
|
|
|
+ } else {
|
|
|
+ log.error("❌ phone_info 中没有 phoneNumber 或 purePhoneNumber");
|
|
|
+ log.error("phone_info 内容: {}", phoneMap);
|
|
|
}
|
|
|
+ } else {
|
|
|
+ log.error("❌ 响应中没有 phone_info 字段或格式错误");
|
|
|
+ log.error("响应内容: {}", parsed);
|
|
|
}
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- log.error("通过 code 获取手机号失败", e);
|
|
|
+ log.error("❌ 通过 code 获取手机号异常", e);
|
|
|
}
|
|
|
return null;
|
|
|
}
|