对接微信小程序接口
This commit is contained in:
+148
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user