对接微信小程序接口
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();
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.mhd.user.interfaces.dto.wechat;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信小程序手机号快速验证——请求参数
|
||||
*/
|
||||
@Data
|
||||
public class WxPhoneNumberDTO {
|
||||
|
||||
@ApiModelProperty("wx.getPhoneNumber 返回的 code(注意:非 wx.login 的 code)")
|
||||
private String code;
|
||||
}
|
||||
@@ -5,7 +5,9 @@ import com.mhd.common.core.domain.entity.R;
|
||||
import com.mhd.common.core.utils.bean.BeanUtils;
|
||||
import com.mhd.common.log.annotation.Log;
|
||||
import com.mhd.common.log.enums.BusinessType;
|
||||
import com.mhd.common.security.utils.SecurityUtils;
|
||||
import com.mhd.system.api.domain.UserShipperFeignDTO;
|
||||
import com.mhd.system.api.model.LoginUser;
|
||||
import com.mhd.user.application.service.UserApplicationService;
|
||||
import com.mhd.user.application.service.UserShipperApplicationService;
|
||||
import com.mhd.user.domain.userAggregate.repository.todo.*;
|
||||
@@ -18,6 +20,7 @@ import com.mhd.common.core.web.page.TableDataInfo;
|
||||
import com.mhd.common.security.annotation.RepeatSubmit;
|
||||
import com.mhd.common.security.service.TokenService;
|
||||
import com.mhd.user.application.service.UserShipperMasterDataSyncService;
|
||||
import com.mhd.user.application.service.WechatMiniAppService;
|
||||
import com.mhd.user.interfaces.dto.updateDTO.SettlementInfoUpdateDTO;
|
||||
import com.mhd.user.interfaces.vo.SettlementInfoQueryVo;
|
||||
import com.mhd.user.interfaces.vo.ShipperMasterDataSyncTimeVo;
|
||||
@@ -42,6 +45,8 @@ public class UserShipperAPI extends BaseController {
|
||||
@Resource
|
||||
private UserShipperMasterDataSyncService userShipperMasterDataSyncService;
|
||||
@Resource
|
||||
private WechatMiniAppService wechatMiniAppService;
|
||||
@Resource
|
||||
private UserApplicationService userApplicationService;
|
||||
@Resource
|
||||
private UserShipperAssember userShipperAssember;
|
||||
@@ -342,4 +347,13 @@ public class UserShipperAPI extends BaseController {
|
||||
}
|
||||
return AjaxResult.success(resultMap);
|
||||
}
|
||||
|
||||
@ApiOperation("微信小程序手机号快速验证")
|
||||
@PostMapping("/wxGetPhoneNumber")
|
||||
public AjaxResult wxGetPhoneNumber(@RequestBody com.mhd.user.interfaces.dto.wechat.WxPhoneNumberDTO dto) {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Long organizationId = (loginUser != null && loginUser.getUserPo() != null)
|
||||
? loginUser.getUserPo().getOrganizationId() : null;
|
||||
return wechatMiniAppService.wxGetPhoneNumber(dto, organizationId);
|
||||
}
|
||||
}
|
||||
@@ -18,16 +18,16 @@ spring:
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# server-addr: 127.0.0.1:8848
|
||||
server-addr: 127.0.0.1:8848
|
||||
# 线上测试环境配置 容器名+端口号
|
||||
server-addr: 10.33.0.129:6010
|
||||
# server-addr: 10.33.0.129:6010
|
||||
# server-addr: 10.102.192.31:6848
|
||||
# username: nacos
|
||||
# password: manhuoda@2023
|
||||
config:
|
||||
# server-addr: 127.0.0.1:8848
|
||||
server-addr: 127.0.0.1:8848
|
||||
# 线上测试环境配置 容器名+端口号
|
||||
server-addr: 10.33.0.129:6010
|
||||
# server-addr: 10.33.0.129:6010
|
||||
# server-addr: 10.102.192.31:6848
|
||||
# username: nacos
|
||||
# password: manhuoda@2023
|
||||
@@ -42,4 +42,8 @@ spring:
|
||||
max-request-size: 50MB
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
wechat:
|
||||
miniapp:
|
||||
appId: wxc9dd2810a77e4e30
|
||||
appSecret: 9354ff1215a82785ef14f2355fbf2185
|
||||
|
||||
Reference in New Issue
Block a user