对接微信小程序接口

This commit is contained in:
秦鸿展
2026-06-27 14:06:34 +08:00
parent 8893eda62d
commit 2d424847c3
4 changed files with 185 additions and 5 deletions
@@ -0,0 +1,148 @@
package com.mhd.user.application.service;
import com.alibaba.fastjson.JSONObject;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.user.interfaces.dto.wechat.WxPhoneNumberDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;
/**
* 微信小程序手机号快速验证
* appId/appSecret 在 bootstrap.yml / Nacos 中配置,不同环境配置不同值即可
*/
@Service
@Slf4j
public class WechatMiniAppService {
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
private static final String GET_PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";
@Value("${wechat.miniapp.appId:}")
private String appId;
@Value("${wechat.miniapp.appSecret:}")
private String appSecret;
/** access_token 缓存:{token, expireTime} */
private volatile String cachedToken;
private volatile long tokenExpireTime;
public AjaxResult wxGetPhoneNumber(WxPhoneNumberDTO dto, Long organizationId) {
if (dto == null || dto.getCode() == null || dto.getCode().isEmpty()) {
return AjaxResult.error("code 不能为空");
}
if (appId.isEmpty() || appSecret.isEmpty()) {
return AjaxResult.error("未配置 wechat.miniapp.appId / wechat.miniapp.appSecret");
}
try {
String accessToken = getAccessToken();
String body = "{\"code\":\"" + dto.getCode() + "\"}";
String phoneJson = doPost(String.format(GET_PHONE_URL, accessToken), body);
JSONObject result = JSONObject.parseObject(phoneJson);
int errcode = result.getIntValue("errcode");
if (errcode != 0) {
String errmsg = result.getString("errmsg");
log.error("微信手机号解密失败, errcode={}, errmsg={}", errcode, errmsg);
return AjaxResult.error("获取手机号失败:" + errmsg);
}
JSONObject phoneInfo = result.getJSONObject("phone_info");
if (phoneInfo == null) {
return AjaxResult.error("未获取到手机号信息");
}
JSONObject data = new JSONObject();
data.put("phoneNumber", phoneInfo.getString("phoneNumber"));
data.put("purePhoneNumber", phoneInfo.getString("purePhoneNumber"));
data.put("countryCode", phoneInfo.getString("countryCode"));
return AjaxResult.success(data);
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
log.error("微信手机号验证异常", e);
return AjaxResult.error("微信手机号验证失败:" + e.getMessage());
}
}
private String getAccessToken() {
if (cachedToken != null && System.currentTimeMillis() < tokenExpireTime) {
return cachedToken;
}
synchronized (this) {
if (cachedToken != null && System.currentTimeMillis() < tokenExpireTime) {
return cachedToken;
}
String url = String.format(ACCESS_TOKEN_URL, appId, appSecret);
String response = doGet(url);
JSONObject result = JSONObject.parseObject(response);
if (result.containsKey("errcode") && result.getIntValue("errcode") != 0) {
throw new ServiceException("获取微信 access_token 失败:" + result.getString("errmsg"));
}
cachedToken = result.getString("access_token");
int expiresIn = result.getIntValue("expires_in");
tokenExpireTime = System.currentTimeMillis() + (expiresIn - 300) * 1000L;
return cachedToken;
}
}
private String doGet(String urlStr) {
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
return readResponse(conn);
} catch (Exception e) {
throw new ServiceException("微信接口请求失败:" + e.getMessage());
}
}
private String doPost(String urlStr, String body) {
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
try (OutputStream os = conn.getOutputStream()) {
os.write(body.getBytes(StandardCharsets.UTF_8));
os.flush();
}
return readResponse(conn);
} catch (Exception e) {
throw new ServiceException("微信接口请求失败:" + e.getMessage());
}
}
private String readResponse(HttpURLConnection conn) throws Exception {
int code = conn.getResponseCode();
BufferedReader reader = new BufferedReader(new InputStreamReader(
code >= 400 ? conn.getErrorStream() : conn.getInputStream(), StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
if (code >= 400) {
throw new ServiceException("微信接口 HTTP " + code + "" + sb);
}
return sb.toString();
}
}